【问题标题】:Key binding does not work键绑定不起作用
【发布时间】:2012-12-15 00:32:29
【问题描述】:

我让 JButton 通过 ActionListener 执行一些操作。在我尝试使用 Action 绑定键盘快捷键(在this 之后)后,鼠标点击按钮有效,但对键盘没有反应。

之前的代码

在面板中创建的按钮,添加了 actionListener。

private FooActionListener actionListener = new FooActionListener();

buttonLeft = new JButton("Left");
up.addActionListener(actionListener);

那么,主类外的FooActionListener类内的actionPerformed方法:

public void actionPerformed(ActionEvent e) {
    Object source = e.getSource();
    if (source == buttonLeft) { thing.move(Direction.LEFT); }
}

之后的代码

final String leftText = "Left";
final Action left = new AbstractAction() {

    @Override
    public void actionPerformed(ActionEvent e) {
        thing.move(Direction.LEFT);
    }
};

buttonLeft = new JButton(left);
buttonLeft.setText(leftText);
KeyStroke keyLeft = KeyStroke.getKeyStroke(KeyEvent.VK_A, 0);
buttonLeft.getInputMap(buttonLeft.WHEN_IN_FOCUSED_WINDOW).put(keyLeft,
    "Left");
buttonLeft.getActionMap().put("Left", left );

更新:我不太确定新代码是否真的可以使用鼠标执行。假设对象应该一键移动 25 个像素,在原始代码中也是如此。但是对于新动作,它似乎每次点击都会移动两次甚至三次,这表明某个动作有一些奇怪的行为。

【问题讨论】:

    标签: java swing key-bindings


    【解决方案1】:

    按钮可能会吸收您的映射,但我会稍作不同。

    因为您使用了Action(正确),所以您的移动逻辑大部分已经集中化了。

    我只是将映射应用到主容器。

    public class TestKeybindings01 {
    
        public static void main(String[] args) {
            new TestKeybindings01();
        }
    
        public TestKeybindings01() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    }
    
                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.setLayout(new BorderLayout());
                    frame.add(new TestPane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        public class TestPane extends JPanel {
    
            private JLabel label;
            private JButton left;
            private JButton right;
    
            public TestPane() {
    
                label = new JLabel("Make a choice");
                label.setHorizontalAlignment(JLabel.CENTER);
    
                LeftAction leftAction = new LeftAction(label);
                RightAction rightAction = new RightAction(label);
    
                InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
                im.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0), "left");
                im.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0), "right");
    
                ActionMap am = getActionMap();
                am.put("left", leftAction);
                am.put("right", rightAction);
    
                left = new JButton(leftAction);
                right = new JButton(rightAction);
    
                setLayout(new GridBagLayout());
                GridBagConstraints gbc = new GridBagConstraints();
                gbc.gridx = 0;
                gbc.gridy = 0;
                gbc.gridwidth = 2;
                gbc.anchor = GridBagConstraints.CENTER;
                gbc.fill = GridBagConstraints.HORIZONTAL;
                add(label, gbc);
    
                gbc.gridy++;
                gbc.gridwidth = 1;
                add(left, gbc);
                gbc.gridx++;
                add(right, gbc);
    
    
            }
    
        }
    
        public abstract class AbstractDirectionAction extends AbstractAction {
    
            private JLabel label;
    
            public AbstractDirectionAction(JLabel label) {
                this.label = label;
            }
    
            public JLabel getLabel() {
                return label;
            }
    
            public void setDirection(String text) {
                getLabel().setText(text);
            }
    
        }
    
        public class LeftAction extends AbstractDirectionAction {
    
            public LeftAction(JLabel label) {
                super(label);
                putValue(NAME, "<<");
            }
    
            @Override
            public void actionPerformed(ActionEvent e) {
                setDirection("Left");
            }
    
        }
    
        public class RightAction extends AbstractDirectionAction {
    
            public RightAction(JLabel label) {
                super(label);
                putValue(NAME, ">>");
            }
    
            @Override
            public void actionPerformed(ActionEvent e) {
                setDirection("Right");
            }
    
        }
    
    }
    

    【讨论】:

    • 您能否详细说明吸收映射的含义?另外,检查问题的更新,看看是否有任何提示。而这个 EventQueue.invokeLater 业务是关于什么的?
    • 按钮实现可能“吸收”键事件,这可能是它支持助记符支持的一部分,防止它引发键绑定事件。我能想到这样重复事件的唯一原因是你按住键。 EventQueue.invokeLater 是因为 Swing 是单线程 API,对 UI 的所有更新都必须在事件调度线程内进行。当你main被执行时,保证你没有使用EDT
    • 至于重复,这里我说的是鼠标点击。我使用与原始代码完全相同的鼠标单击,但似乎它在同一次单击时调用了 thing.move 方法两次。有没有办法调试它?
    • 向您添加一些诊断信息,并确定该操作是否执行了多次。
    • @theUg example
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-18
    • 1970-01-01
    相关资源
    最近更新 更多