【问题标题】:Key binding not responding when arrow pressed按下箭头时键绑定没有响应
【发布时间】:2015-09-04 11:39:39
【问题描述】:

您好,我正在用 Java 开发一个应用程序(在 mac 中)。当用户按下箭头时,我希望它做一些事情。

我的代码如下:

public class Main {

static JScrollPane scrollPane;

public static void main(String[] args) {


    JFrame f = new JFrame();
    Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
    f.setBounds(0, 0, dim.width, dim.height);

    StandartPanel p = new StandartPanel();

    f.add(p);

    JToolBar tb = new JToolBar();

    tb.add(new JButton("button"));

    f.add(tb);
    f.setVisible(true);
}

}

它只是一个创建 JFrame 并将 StandartPanel 和带有按钮的 JToolBar 放入其中的程序。

StandartPanel的代码如下:

public class StandartPanel extends JPanel {


public StandartPanel () {

    for( int i = 0; i < 10; i++)
        this.add(new JLabel("Jlabel number: " + i));

    this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "forward");
    this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0), "forward");
    this.getActionMap().put("forward", new AbstractAction() {

        @Override
        public void actionPerformed(ActionEvent e) {
            System.out.println("pressed");
        }
    });
}

}

for 循环并不重要,重要的是当按下 D 或 Down 时它会打印“pressed”。

当我实际按下 D 时,它会打印“按下”,但当我单击时它什么也不做。

在尝试了一些事情之后,我发现如果不是向 JToolBar 添加一个 JButton,而是添加一个 JLabel,它就可以工作(如果我不添加任何东西,它也可以工作)。

因此,将 JButton 添加到 JToolBar 会以某种方式阻止键绑定与向下按钮一起使用。

关于它为什么会发生以及如何解决它的任何想法?

谢谢!

【问题讨论】:

标签: java swing key-bindings


【解决方案1】:

在我的 Mac 上测试:

this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "forward");

没有用,但是由于某种原因我无法解释,使用...

this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, true), "forward");

哦,而且,而不是使用...

Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
f.setBounds(0, 0, dim.width, dim.height);

考虑使用...

f.setExtendedState(JFrame.MAXIMIZED_BOTH);

它不仅会给出一个类似的结果,它还会考虑隐藏/显示的停靠点之类的东西,并以更正确的方式表示窗口状态(即最大化而不仅仅是“填充”该区域)

【讨论】:

  • (+1) 我的 猜想 为什么您的解决方案有效,因为它仅在按键释放时触发事件,JToolBar 可能在按键上。 (并阻止其他行动)-但我确信我的“理论”很容易被推翻:P
  • @LuxxMiner 我认为是这样,但JToolBar 也有KeyEvent.VK_KP_DOWN 的绑定,我可以很好地使用它,无需修改,似乎还有更多事情要做VK_DOWN 我没有看到的键。如果我向 OP 的 StandartPanel 添加一个可聚焦的组件并赋予它焦点,那么一切正常......我在这个阶段被难住了,因为 WHEN_IN_FOCUSED_WINDOW 不应该关心还有谁可能会响应关键事件(根据我到目前为止的经验)
  • @MadProgrammer 真的吗? this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put( KeyStroke.getKeyStroke(KeyEvent.VK_KP_DOWN, 0), "forward"); 对我不起作用......它变得越来越奇怪:D
【解决方案2】:

最简单的方法是将您的(JToolBar 和)JButton 设置为不可聚焦。 (参见this,JToolBar 通常注册 UP/DOWN/LEFT/RIGHT 以切换工具栏中按钮的焦点。)但要小心!这将阻止 JToolbar 从一项“跳跃”到另一项。 (如果您想保留该功能,请查看 MadProgrammer 的答案)- 在您的代码中实现它看起来像这样:

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Toolkit;
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.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JToolBar;
import javax.swing.KeyStroke;

public class Main {

    static JScrollPane scrollPane;

    public static void main(String[] args) {

        JFrame f = new JFrame();
        Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
        f.setBounds(0, 0, dim.width, dim.height);

        StandartPanel p = new StandartPanel();

        f.add(p);

        JToolBar tb = new JToolBar();

        JButton button = new JButton("Button");
        button.setFocusable(false);

        tb.add(button);
        //tb.setFocusable(false);

        f.add(tb, BorderLayout.NORTH);
        f.setVisible(true);
    }

    static class StandartPanel extends JPanel {

        public StandartPanel() {

            for (int i = 0; i < 10; i++) {
                this.add(new JLabel("Jlabel number: " + i));
            }

            this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
                    KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "forward");
            this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
                    KeyStroke.getKeyStroke(KeyEvent.VK_D, 0), "forward");
            this.getActionMap().put("forward", new AbstractAction() {

                @Override
                public void actionPerformed(ActionEvent e) {
                    System.out.println("pressed");
                }
            });
        }

    }

}

【讨论】:

  • 使用WHEN_IN_FOCUSED_WINDOW意味着只要组件在当前焦点窗口内,键绑定就应该触发。鉴于 OP 可以让它为 [D] 键工作,但在 [Down Arrow] 下,这表明它们在起作用
  • @MadProgrammer JToolBar 自动注册向上/向下/向左/向右的动作(从一个项目跳到另一个项目) - 将所有按钮设置为不可聚焦将防止这种情况发生。 (这就是它与 JLabels 一起使用的原因)
  • 它不应该(但确实)有所作为,但正在改变用户对工具栏的期望,值得让键绑定工作。值得思考的有趣事情;)
  • 哦,对于像我这样愚蠢的老白痴,您能否也将这个解释添加到您的回答中;)
  • 更奇怪的是,如果我使用KeyEvent.VK_KP_DOWN,它也被JToolBar使用,它工作得很好,“非键盘”似乎有问题箭头键...怪异:P