1

我一直在尝试将箭头键用作我的应用程序的一部分。遵循最佳实践,我坚持使用键绑定。我认为箭头键不会产生键类型事件,所以我采用了这个答案

但是,我的应用程序有许多组件,我发现如果我的 JFrame 中有一个 JToolbar,则上一个链接中的方法不再有效。为什么会这样,我如何拥有 JToolbar 并使用键绑定?

这是一个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);
        }
    }    
}
4

2 回答 2

4

默认情况下,JToolBar为 KeyStroke 的 UP/DOWN/LEFT/RIGHT 注册一个操作,并且JToolBar您添加到的JFrame自动获取焦点,因此在绑定到根窗格时您看不到任何内容(工具栏捕获您之前的事件)。

一种解决方案是使JToolBarandJButton不可聚焦并允许您JPanel聚焦(实际上您可以离开 JToolBarandJButton并请求将焦点放在面板上,但这也意味着您必须处理面板的焦点管理):

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);
        }
    }
}

我还用getActionMap/getInputMap一个电话代替了你的电话javax.swing.JComponent.registerKeyboardAction(ActionListener, String, KeyStroke, int)

于 2013-06-11T16:45:35.050 回答
1

按照这个答案中的建议,我已经解决了这个问题

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()));
    } 


}
于 2013-06-11T16:07:19.540 回答