import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class Menu{
JFrame frame = new JFrame();
Image icon = Toolkit.getDefaultToolkit().getImage("image1.png");
Action escapePressed;
public Menu() {
frame.setVisible(true);
frame.setIconImage(icon);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setMinimumSize(new Dimension(500, 500));
frame.setTitle("Nine Games");
frame.setFocusable(true);
frame.setResizable(true);
frame.add(new StartScreen());
escapePressed = new EscapePressed();
frame.getInputMap().put(KeyStroke.getKeyStroke('w'), "escapePressed");
frame.getActionMap().put("escapePressed", escapePressed);
}
public class EscapePressed extends AbstractAction {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("Escape Pressed");
System.exit(0);
}
}
}
I don't know why, but this program says that getInputMap
and getActionMap
don't exist. Which is weird. I could have sworn I put it all in correctly . I followed a tutorial even but nothing seems to work.
CodePudding user response:
A couple of problems:
- a JFrame doesn't have an InputMap and ActionMap. Only components that extend from JComponent can use Key Bindings. So to handle an exit KeyStroke you probably want to use the
JRootPane
to add your bindings - you don't want to use the default
WHEN_FOCUSED
InputMap because the root pane won't have focus as some other component you add to the frame will have focus. Instead you want to use theWHEN_IN_FOCUSED_WINDOW
InputMap.
So your code might be like:
//frame.getInputMap().put(KeyStroke.getKeyStroke('w'), "escapePressed");
//frame.getActionMap().put("escapePressed", escapePressed);
frame.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke('w'), "escapePressed");
frame.getRootPane().getActionMap().put("escapePressed", escapePressed);
Read the section from the Swing tutorial on How to Use Key Bindings for more information.
Also check out Using Top Level Containers for more information about the root pane.
CodePudding user response:
I prefer not to use KeyStroke.getKeyStroke
as there is a level of ambiguity in how the key stroke might be triggered, this is a personal thing, but I've wasted too much time trying to debug issues related to it.
Instead, I prefer to use KeyStroke.getKeyStroke(KeyEvent.VK_W, 0)
instead. This is much easier to (for me) to understand and I can configure "pressed" or "released" functionality through it as well.
The default behaviour of getInputMap()
is to generate events WHEN_FOCUSED
, this is the same as you would expect from KeyListener
, but you're adding your key binding to the JFrame
, which is unlikely to ever gain focus (it's a composite component, so it doesn't make sense for it to do so).
Instead, you should try something like...
frame.getInputMap(WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0), "escapePressed");
frame.getActionMap().put("escapePressed", escapePressed);
Now, personally, I think this kind of thing is probably better maintained via a component, which gets added to the frame, but this is me.