Reputation:
I wanted to make a KeyListener to stop the programm when I press the ESC key. But it only works when I did nothing else (pressed the button). I`m sorry if it is something super obvious but I cant find the mistake.
package basics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
public class Graphic extends JFrame implements ActionListener, KeyListener {
private JButton button;
public Graphic() {
button = new JButton();
button.addActionListener(this);
button.setIcon(new ImageIcon("Image.jpg"));
this.getContentPane().add(button);
}
public void actionPerformed(ActionEvent e) {
if(e.getSource() == button){
//some code
}
}
public static void main(String[] args) {
JFrame bec = new Graphic();
bec.setDefaultCloseOperation(Graphic.EXIT_ON_CLOSE);
bec.setSize(1731, 563);
bec.setVisible(true);
bec.setTitle("title");
bec.requestFocus();
bec.addKeyListener(new Graphic());
}
@Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_ESCAPE){
System.exit(0);
}
}
@Override
public void keyReleased(KeyEvent e) {
}
@Override
public void keyTyped(KeyEvent e) {
}
}
Upvotes: 0
Views: 256
Reputation: 1997
KeyListener
suffers from issues related to focusability and with other controls in the GUI. A simple solution would be to use the Actions API. Under this approach, the program simply specifies, for a given component, the “binding” or “mapping” between any key of interest and the Action (command) object to be invoked when that key is pressed (or released). Key bindings are associated with a specific GUI component.
In this case, a proper solution could be:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.KeyStroke;
public class Graphic extends JFrame implements ActionListener {
private JButton button;
public Graphic() {
getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "Cancel"); //$NON-NLS-1$
getRootPane().getActionMap().put("Cancel", new AbstractAction(){ //$NON-NLS-1$
public void actionPerformed(ActionEvent e)
{
dispose();
}
});
button = new JButton();
button.addActionListener(this);
button.setIcon(new ImageIcon("Image.jpg"));
this.getContentPane().add(button);
}
public void actionPerformed(ActionEvent e) {
if(e.getSource() == button){
//some code
}
}
public static void main(String[] args) {
JFrame bec = new Graphic();
bec.setDefaultCloseOperation(Graphic.EXIT_ON_CLOSE);
bec.setSize(1731, 563);
bec.setVisible(true);
bec.setTitle("title");
bec.requestFocus();
}
}
Upvotes: 1
Reputation: 168845
But it only works when I did nothing else (pressed the button).
No it doesn't work (at all). Have a look at this code:
public static void main(String[] args) {
JFrame bec = new Graphic();
// ..
bec.addKeyListener(new Graphic());
}
The key listener is added to a 2nd instance of Graphic
that is never displayed.
Another reason it would not work: Because a KeyListener
(even when added to the correct instance) requires that the component to which it's added is both focusable (a JFrame
by default is not) and has the input focus (which that frame will never have, given it is not focusable).
Solution: For Swing, we typically use key bindings rather than the lower level KeyListener
. A key binging offers ways to specify on what conditions it will be invoked, some of which do not require the component to have focus.
Upvotes: 0
Reputation: 18253
You problem is to catch KeyListener
across all components. You can do it like this:
public Graphic() {
// ...
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(e -> {
if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
dispose();
return true;
}
return false;
});
}
When you add this, your application will be closed exactly after you press ESC
button. If you want to block it e.g. if some of you components have focus (e.g. JTextField
and you want to do specific action), then you have to focus component in this listener and avoid invoking dispose()
.
Upvotes: 0
Reputation: 7
Are you sure there's no TextArea's or other focusable things? They can get focus, and key events will pass to them instead of listener.
UPD: Sorry, didn't see that you have nothing but button there.
Upvotes: 0