问题
I have been trying to use the arrow keys as part of my application. Following the best practice I have stuck with using key bindings. I gound that the arow keys do not produce a key typed event so I employed this answer.
However, my application has a number of components and I found that if I have a JToolbar in my JFrame the method in the previous link no longer works. Why is this and how do I have a JToolbar and use key bindings?
Here is a SSCCE
public class ArrowTest extends JFrame {
public static void main(final String[] args){
final ArrowTest at = new ArrowTest();
at.setSize(100,200);
final JPanel jp = new JPanel();
jp.setBackground(Color.BLUE);
at.getContentPane().add(jp);
final JToolBar toolbar = new JToolBar();
toolbar.add(new JButton());
//at.add(toolbar);
at.setVisible(true);
}
public ArrowTest() {
super();
this.getContentPane().setLayout(new GridBagLayout());
this.getContentPane().setBackground(Color.BLACK);
this.setKeyBindings();
}
public void setKeyBindings() {
final int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
final ActionMap actionMap = this.getRootPane().getActionMap();
final InputMap inputMap = this.getRootPane().getInputMap(condition);
for (final Direction direction : Direction.values()) {
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_V,0), direction.getText());
inputMap.put(direction.getKeyStroke(), direction.getText());
actionMap.put(direction.getText(), new MyArrowBinding(direction.getText()));
}
}
enum Direction {
UP("Up", KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0)),
DOWN("Down", KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0)),
LEFT("Left", KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0)),
RIGHT("Right", KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0));
Direction(final String text, final KeyStroke keyStroke) {
this.text = text;
this.keyStroke = keyStroke;
}
private String text;
private KeyStroke keyStroke;
public String getText() {
return text;
}
public KeyStroke getKeyStroke() {
return keyStroke;
}
@Override
public String toString() {
return text;
}
}
private class MyArrowBinding extends AbstractAction {
private static final long serialVersionUID = -6904517741228319299L;
public MyArrowBinding(final String text) {
super(text);
putValue(ACTION_COMMAND_KEY, text);
}
@Override
public void actionPerformed(final ActionEvent e) {
final String actionCommand = e.getActionCommand();
System.out.println("Key Binding: " + actionCommand);
}
}
}
回答1:
By default, JToolBar
registers an action for the KeyStroke's UP/DOWN/LEFT/RIGHT, and the JToolBar
you add to the JFrame
automatically grabs the focus, hence you don't see anything when binding to the rootpane (the toolbar catches the events before you).
One solution is to make the JToolBar
and the JButton
not focusable and allow your JPanel
to be focusable (actually you could leave the JToolBar
and the JButton
and request the focus on your panel but this also means that you have to handle the focus management of your panel):
import java.awt.Color;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JToolBar;
import javax.swing.KeyStroke;
public class ArrowTest extends JFrame {
public static void main(final String[] args) {
final ArrowTest at = new ArrowTest();
at.setSize(100, 200);
final JPanel jp = new JPanel();
jp.setBackground(Color.BLUE);
jp.setFocusable(true);
at.getContentPane().add(jp);
final JToolBar toolbar = new JToolBar();
JButton comp = new JButton();
toolbar.add(comp);
at.add(toolbar);
at.setVisible(true);
}
public ArrowTest() {
super();
this.getContentPane().setLayout(new GridBagLayout());
this.getContentPane().setBackground(Color.BLACK);
this.setKeyBindings();
}
public void setKeyBindings() {
for (final Direction direction : Direction.values()) {
MyArrowBinding binding = new MyArrowBinding(direction.getText());
getRootPane().registerKeyboardAction(binding, direction.getText(), direction.getKeyStroke(),
JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
}
}
enum Direction {
UP("Up", KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0)), DOWN("Down", KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0)), LEFT("Left",
KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0)), RIGHT("Right", KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0));
Direction(final String text, final KeyStroke keyStroke) {
this.text = text;
this.keyStroke = keyStroke;
}
private String text;
private KeyStroke keyStroke;
public String getText() {
return text;
}
public KeyStroke getKeyStroke() {
return keyStroke;
}
@Override
public String toString() {
return text;
}
}
private class MyArrowBinding extends AbstractAction {
private static final long serialVersionUID = -6904517741228319299L;
public MyArrowBinding(final String text) {
super(text);
putValue(ACTION_COMMAND_KEY, text);
}
@Override
public void actionPerformed(final ActionEvent e) {
final String actionCommand = e.getActionCommand();
System.out.println("Key Binding: " + actionCommand);
}
}
}
I also replaced your calls to getActionMap/getInputMap
by a single call to javax.swing.JComponent.registerKeyboardAction(ActionListener, String, KeyStroke, int)
回答2:
Following the advice in this answer I have solved the issue using
public void setKeyBindings() {
final int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
final ActionMap actionMap = this.getRootPane().getActionMap();
final InputMap inputMap = this.getRootPane().getInputMap(condition);
for (final Direction direction : Direction.values()) {
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_V,0), direction.getText());
inputMap.put(direction.getKeyStroke(), direction.getText());
actionMap.put(direction.getText(), new MyArrowBinding(direction.getText()));
}
condition = JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT;
actionMap = toolbar.getActionMap();
inputMap = toolbar.getInputMap(condition);
for (final Direction direction : Direction.values()) {
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_V,0), direction.getText());
inputMap.put(direction.getKeyStroke(), direction.getText());
actionMap.put(direction.getText(), new MyArrowBinding(direction.getText()));
}
}
来源:https://stackoverflow.com/questions/17047625/why-does-jtoolbar-break-my-keybindings