In my question How do I draw on a JPanel from multiple outside classes? Frakcool gave me the advice to use key bindings, and one thing didn't work: When the JButton put another JPanel infront of the frame, the Keybinding didn't respond. This is the code:
private JFrame frame;
private JPanel[] statePanels;
private CardLayout layout;
private JPanel mainPanel;
private JButton button;
private String status;
void initAndShow()
{
//Init stuff
mainPanel = new JPanel(layout);
statePanels = new JPanel[2];
button = new JButton("Exit");
status = "Menu";
button.addActionListener(e -> {
status = status.equals("Menu") ? "World" : "Menu";
layout.show(mainPanel, status);
});
statePanels[0] = new OutWorldHandler();
statePanels[1] = new InWorldHandler();
mainPanel.add(statePanels[0], "Menu");
mainPanel.add(statePanels[1], "World");
mainPanel.getInputMap().put(KeyStroke.getKeyStroke('f'), "close");
mainPanel.getActionMap().put("close", this);
frame.add(mainPanel);
frame.add(button, BorderLayout.SOUTH);
}
@Override
public void actionPerformed(ActionEvent e)
{
System.out.println("hi");
}
The expected output was that when I allways pressed f
the console would print out "hi", but it only did as long as I didn't press the button
Key bindings aren't particularly complex, but they can take a little bit of getting use to. To this end, it's useful to have How to Use Key Bindings and the JavaDocs for JComponent
on hand, for reference.
One of the goals of the key bindings API is configurability, allowing us more control over determining when a key stroke should trigger an event.
The JComponent#getInputMap
method returns a mapping which is bound to the "when has focused" context. This means that the component will need to have focus (and be focusable obviously) before a binding will be triggered.
If you want the binding to be triggered at a different level, then you need to use JComponent#getInputMap(int)
and pass it one of the three available contexts:
JComponent.WHEN_IN_FOCUSED_WINDOW
JComponent.WHEN_FOCUSED
JComponent. WHEN_ANCESTOR_OF_FOCUSED_COMPONENT
Which you use will depend on your needs, but I'm generally lazy and go for JComponent.WHEN_IN_FOCUSED_WINDOW
when I want a "global" state