Following is a program that displays a black screen with a messgage ALARM ! :
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class displayFullScreen extends Window {
private JLabel alarmMessage = new JLabel("Alarm !");
public displayFullScreen() {
super(new JFrame());
setLayout(new FlowLayout(FlowLayout.CENTER));
alarmMessage.setFont(new Font("Cambria",Font.BOLD,100));
alarmMessage.setForeground(Color.CYAN);
add(alarmMessage);
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
setBounds(0,0,screenSize.width,screenSize.height);
setBackground(Color.black);
addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent ke) {
escapeHandler(ke);
}
});
}
public void escapeHandler(KeyEvent ke) {
if(ke.getKeyCode() == ke.VK_ESCAPE) {
System.out.println("escaped !");
} else {
System.out.println("Not escaped !");
}
}
public static void main(String args[]) {
new displayFullScreen().setVisible(true);
}
}
I have set a key handler in this program . The handler catches the keys pressed when the focus is on window.
When the escape key will be pressed escaped ! should be displayed otherwise !escaped.
But nothing gets displayed,when i press a key. What is the problem ?
Maybe you want a window but you have two problems:
You should extend JWindow, not Window when using a Swing application
Even extending JWindow won't work because a JWindow won't receive KeyEvent unless it is parent JFrame is visible.
So you should be using a JFrame. If you don't want the title bar and borders, then you can use an undecorated JFrame.
Also, you should NOT be using a KeyListener because even on a JFrame key events are only dispatched to the focused component. Instead you should be using Key Bindings. In this case it seems you should be adding the binding to the root pane of the frame.
Extend JFrame instead and get rid of the super call.
Related
I'm working on an old game project called Lemmings, and the Principle Game Panel is working well and receiving the MouseEvents but not the KeyEvents, which is not very logic for me, so I copied down the Code of this file for you guys to see whats going on.
The GamePanel class extends JComponent SWING class
public class GameFrame {
private class GamePanel extends JComponent {
GamePanel(Dimension dim) {
setPreferredSize(dim);
//first version of the question was with the keyListner
/*addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
super.keyPressed(e);
System.out.println(e.getKeyCode());
//nothing show up
}
});*/
//I tried using this, but it didn't work
//getInputMap().put(KeyStroke.getKeyStroke("A"), "action");
// this works cause we use the right inputMap not the one by default
getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke("A"), "action");
getActionMap().put("action",new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("A is pressed");
//now it works
}
});
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
super.mouseClicked(e);
System.out.println(e.getPoint());
}
});
setVisible(true);
}
}
private JFrame window;
private GamePanel panel;
public GameFrame() {
window = new JFrame("Test");
window.setLocationRelativeTo(null);
panel = new GamePanel(new Dimension(400, 400));
window.setContentPane(panel);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setVisible(true);
}
public static void main(String[] args) {
new GameFrame();
}
}
UPDATE WITH SOLUTION
I learned that JComponants are not focusable and so it doesn't receive KeyEvents so we have to use the Key Bindings method
I found out that every JComponent has three inputMaps referred to by WHEN_IN_FOCUSED_WINDOW, WHEN_FOCUSED, WHEN_ANCESTOR_OF_FOCUSED_COMPONENT and we have to make sure that we are using the right one for our work
for more informations look on How to use key Bindings and check the methods getInputMap() and getInputMap(int)
Key events are only dispatch to a focusable component.
By default a JPanel is not focusable so it does not receive key events.
If you are attempting to invoke some kind of Action based on a KeyEvent then you should be using Key Bindings, not a KeyListener. A key binding will allow you to listen for a KeyStroke even if the component doesn't have focus.
Read the section from the Swing tutorial on How to Use Key Bindings for more information and working examples.
the problem can be solved simply by adding a KeyListener to the JFrame in case we don't need to create Actions and stuff
this solution can only be possible if there are no other components focusable.
in the file GameFrame.java
in the function void init();
add
window.addKeyListener(new KeyAdapter() {
#Override
public void keyPressed (KeyEvent e) {
super.keyPressed(e);
System.out.println("test "+e.getKeyChar());
}
});
i was studying event handling and performed the following:
Created a JFrame without any component in it
i overridden the keyPressed() method in such a way that whenever a key is pressed from the keyboard,A button should appear in the frame(by using add() and then calling repaint()).
Now the thing i want to ask is that at the time of key press from the keyboard,nothing was being added to the frame,however after pressing the key when i resized the frame WINDOW,the button came out from nowhere in the frame....
what's happening?
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class MyFrame extends JFrame implements KeyListener
{
private JButton bt=new JButton();
MyFrame()
{
addKeyListener(this);
}
public void keyPressed(KeyEvent ke)
{
this.add(bt);
repaint();
}
public void keyTyped(KeyEvent ke)
{
}
public void keyReleased(KeyEvent ke)
{
}
}
public class MyClass /*class containing the main method*/
{
public static void main(String args[])
{
MyFrame frm=new MyFrame();
frm.setVisible(true);
frm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
,nothing was being added to the frame,
The component was added to the frame. The problem is it has a size of (0, 0) so there is nothing to paint
however after pressing the key when i resized the frame WINDOW,the button came out from nowwhere in the frame
The layout manager gets invoked and the component is given a size and location based on the rules of the layout manager. So now you see the component.
When you add a component to a visible GUI the code is:
panel.add(...);
panel.revalidate();
panel.repaint();
You need to call revalidate after adding a component to the JFrame
this.add(bt);
revalidate();
repaint();
revalidate revalidates the component hierarchy to account for any new components that may have been added.
KeyListeners don't work well for Swing applications as KeyEvents require focus to work.
This is why in Swing it is better to use Key Bindings which allow you to map an Action to a KeyStroke even when a component doesn't have focus.
I want to display a TextField only when user has entered a value in Input field
Here is my code:
import java.awt.BorderLayout;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JTextField;
public class PlayingAround {
JFrame frame;
JTextField display;
JTextField input;
public static void main(String[] args) {
PlayingAround obj = new PlayingAround();
obj.create();
}
private void create() {
frame = new JFrame();
display = new JTextField();
input = new JTextField();
display.setEditable(false);
display.setVisible(false);
input.addKeyListener(new Listener());
frame.add(BorderLayout.NORTH, display);
frame.add(BorderLayout.SOUTH, input);
frame.setSize(300, 300);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
class Listener implements KeyListener {
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
display.setVisible(true);
display.setText(input.getText());
}
}
}
But my problem is that the Display JTextField doesn't becomes visible until there are some events like Resizing the Window, Minimizing and maximizing the Window.
I tried calling frame.repaint() in the keyReleased Method but even it has not helped.
You should call revalidate() and repaint() on the container that holds the JTextField after placing the text field component in the container. The revalidate() call sends a request to the container's layout managers to re-layout its components. The repaint() then requests that the JVM request of the paint manager to redraw the newly laid out container and its child components. The repaint() is not always needed but is usually a good idea.
Also, don't use a KeyListener for this, but rather a DocumentListener on the first text component's Document. This way, if the user empties the first text component, you can make the second text component disappear if desired. Also, text can be entered without key presses, and you want to allow for that.
I need to make the GUI in java respond to mouse and keyboard input simultaneously.. I know I should add something to the loop in the action listener .. but did not find the right idea .. any suggestions please??
I need to make my GUI respond to the mouse motion and clicks and at the same time respond to the keyboard button pressed if mouse is over a button and pressed enter .. the GUI will respond to the keyboard and the mouse motion actions will continue normally !! .. Hope the problem is cleared!
You do not have to "add something in loop". You just have to add MouseListener and KeyListener to your GUI element (e.g. Frame) and implement the callback methods as you want.
Take a look, at Toolkit.addAWTEventLstener
This will allow you monitor all the events flowing the event queue.
The problem your going to have is identifying the components that are in the area of effect and overcoming the default behaviour of the components (pressing enter while a text field has focus will trigger a action event on it, but now you want to do something else)
To get the behavior of responding to a mouse over the button and enter being pressed I would:
Use Key Bindings attached to the JButton to allow it to respond to the enter key.
Make sure that when doing the above use the InputMap that is associated with the JComponent.WHEN_IN_FOCUSED_WINDOW constant so that the button doesn't actually have to have focus to respond but needs to be in the focused window.
Of course bind to the KeyStroke associated with KeyEvent.VK_ENTER.
In the key bindings action, check if the button's model is in the rollOver state by calling isRollOver() on the model.
and if so, respond.
Note that none of this above requires a MouseListener because I'm using the ButtonModel's isRollOver in place of that.
As an example, my SSCCE:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.*;
public class MouseKeyResponse extends JPanel {
private JButton button = new JButton("Button");
public MouseKeyResponse() {
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("button clicked");
}
});
add(button);
setUpKeyBindings(button);
}
private void setUpKeyBindings(JComponent component) {
int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
InputMap inputMap = component.getInputMap(condition);
ActionMap actionMap = component.getActionMap();
String enter = "enter";
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), enter);
actionMap.put(enter, new EnterAction());
}
private class EnterAction extends AbstractAction {
#Override
public void actionPerformed(ActionEvent evt) {
if (button.isEnabled() && button.getModel().isRollover()) {
System.out.println("Enter pressed while button rolled over");
button.doClick();
}
}
}
private static void createAndShowGui() {
MouseKeyResponse mainPanel = new MouseKeyResponse();
JFrame frame = new JFrame("MouseKeyResponse");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
I prepared a small test case below. My problem is when i right click on the window. JPopupMenu show up but if i click anywhere outside the JWindow menu does not disappear. I have to click somewhere on the window to get rid of it which is not the expected behavior.
EDIT:
after reading akf's answer i switched to JFrame, when frame is in focus and pop up menu is showing it disappears when you click on another window. but if the window does not have focus and you click somewhere menu does not disappear.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class test {
static class window extends JWindow
implements MouseListener, MouseMotionListener{
JPopupMenu popMenu;
JPanel panel = new JPanel();
Point location;
MouseEvent pressed;
public window(){
addMouseListener( this );
addMouseMotionListener( this );
JLabel label = new JLabel("JWindow", JLabel.CENTER);
initPopMenu();
add(label);
setVisible(true);
setAlwaysOnTop(true);
setLocationRelativeTo(null);
pack();
}
public void initPopMenu(){
popMenu = new JPopupMenu();
JMenuItem item;
item = new JMenuItem( "Title" );
item.setEnabled(false);
popMenu.add(item);
popMenu.addSeparator();
item = new JMenuItem( "Item One" );
popMenu.add(item);
item = new JMenuItem( "Item 2" );
popMenu.add(item);
item = new JMenuItem( "Item 3" );
popMenu.add(item);
}
public void mousePressed(MouseEvent e)
{
pressed = e;
int nModifier = e.getModifiers();
if (((nModifier & InputEvent.BUTTON2_MASK) != 0)||
((nModifier & InputEvent.BUTTON3_MASK) != 0))
popMenu.show( this, e.getX(), e.getY() );
}
public void mouseClicked(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {}
public void mouseDragged(MouseEvent me){
}
public void mouseMoved(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
}
public static void main(String[] args) {
window dw = new window();
}
}
Take a look at the Java Doc for JWindow.isFocusableWindow
A JWindow cannot be the focused window unless it has an owner and the owner is visible.
You're using the default constructor, so your JWindow has the shared owner asn is not focusable. When it is not focusable, it cannot detect the loss of focus when you click somewhere else.
I changed JWindow to JFrame and added a call to setUndecorated(true); before the call to setVisible and it's working for me. If these changes do not make it work for you, please post the version of Java you are using: java -fullversion
In Java 6 on Windows, I cannot get the popup to even display with the code you have provided. On the other hand, if I change your superclass to JFrame, it works as desired, with the popup going away when I click outside of the window. Is there a reason why you are using JWindow as your superclass and not JFrame? If you wish to have a border-less/title-less window, you can call setUndecorated(true) on your JFrame (before you set visible and pack, of course.)
What about hiding the menu if it's visible from within the MouseExited method?