【问题标题】:Any better solution to ListenKey anywhere inside the frame?框架内任何地方的 ListenKey 有更好的解决方案吗?
【发布时间】:2015-01-15 14:29:46
【问题描述】:

我有一个带有文本字段、表格和两个按钮的框架!

我想添加一个 KeyListener 以在按下和释放修改键时进行监听,以更改 Ok 按钮的文本并让用户选择不同的方法。无论哪个组件处于焦点,侦听器都应该工作。

例如:

  1. 没有修饰符:“Ok” - 做某事
  2. 按下 Shift 键:“确定并关闭” - 做某事并关闭框架
  3. Alt 键按下...等

现在我找到了这个解决方案,但它看起来有点笨拙,一点也不优雅。

公共类 MyFrame 扩展 JFrame {

private boolean shiftPressed;
private MyDispatcher keyDispatcher;


public MyFrame () {
    super();
    initGUI();

    shiftPressed = false;

    KeyboardFocusManager currentManager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
    keyDispatcher = new MyDispatcher();
    currentManager.addKeyEventDispatcher(keyDispatcher);

    //...remain of code

}

@Override
public void dispose() {
    // I remove the dispatcher when the frame is closed;
    KeyboardFocusManager currentManager = KeyboardFocusManager
            .getCurrentKeyboardFocusManager();
    currentManager.removeKeyEventDispatcher(keyDispatcher);
    super.dispose();
}

private class MyDispatcher implements KeyEventDispatcher {
    @Override
    public boolean dispatchKeyEvent(KeyEvent e) {
        if (e.getModifiers() == KeyEvent.SHIFT_MASK) {
            if (e.getID() == KeyEvent.KEY_PRESSED) {
                System.out.println("Shift Pressed");
                shiftPressed = true;
                btnOk.setText("Ok and Close");
            } 
        } else if (e.getID() == KeyEvent.KEY_RELEASED) {
            if(!e.isShiftDown() && shiftPressed) {
                System.out.println("Shift Released");
                btnOk.setText("Ok");
            }
        }
        return false;
    }
}

}

对如何改进代码有什么建议吗?

【问题讨论】:

  • 对于 Swing,我们通常使用key bindings 而不是较低级别的KeyListener

标签: java swing keylistener


【解决方案1】:

我想添加一个 KeyListener 以在按下和释放修改键时进行监听,以便更改 Ok 按钮的文本和 让用户选择不同的方法。无论如何,监听器都应该工作 哪个组件是焦点。

恕我直言,使用Key bindings 是一种更灵活、更可靠的方法,具有以下好处:

话虽如此,我们可以使用以下适当的掩码创建KeyStrokes

KeyStroke shiftKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_SHIFT, KeyEvent.SHIFT_DOWN_MASK);

我们甚至可以指定按键释放事件触发按键:

KeyStroke shiftReleasedKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_SHIFT, 0, true);

注意: 0 表示没有修饰符,true 是一个标志,表示击键表示按键释放事件。详情请见the API

现在,我要做的是创建一个包装器JPanel,其中包含我的所有组件并使用WHEN_IN_FOCUSED_WINDOW 条件附加操作:

JPanel wrapperPanel = new JPanel();
...
InputMap wrapperPanelInputMap = wrapperPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
wrapperPanelInputMap.put(shiftKeyStroke, "pressedAction");
wrapperPanelInputMap.put(shiftReleasedKeyStroke, "releasedAction");
...
wrapperPanel.getActionMap().put("pressedAction", pressedAction);
wrapperPanel.getActionMap().put("releasedAction", releasedAction);

pressedActionreleasedAction 都不同,Actions 可以做任何你想做的事情(即:更改按钮的文本)。

唯一的小缺点是设置键绑定所需的 LOC。但是,您可以通过创建一个可重用面板来避免样板代码,该面板可以接受不同修饰符(SHIFT、ALT、CTRL 等)的操作并在该类内部设置键绑定。

【讨论】:

    【解决方案2】:

    您的方法还可以,但它使用了全局焦点管理器。这有点危险,例如当您忘记处理框架时可能会引发一些错误。更好的做法是将您的侦听器添加到框架中的所有可聚焦组件。

    private static void addToAll(Component aStart, KeyListener aListener) {
        if (aStart.isFocusable()) {
            aStart.addKeyListener(aListener);
        }
        if (aStart instanceof Container) {
            Container container = (Container) aStart;
            for (Component comp : container.getComponents()) {
                addToAll(comp, aListener);
            }
        }
    }
    

    使用它:

    public MyFrame () {
        super();
        initGUI();
    
        shiftPressed = false;
        keyDispatcher = new MyDispatcher();
        addToAll(this.getContentPane(), keyDispatcher);
        //...remain of code
    
    }
    

    这种方法的缺点:当您动态修改 GUI 时(在创建 GUI 后添加/删除组件并将侦听器添加到所有组件),您需要从所有组件中删除侦听器并重新添加。

    【讨论】:

    • 目前我正在使用您的方法,因为从我的角度来看它更简单,但 dic19 解决方案在我看来更有效和可靠,即使需要更多代码或子类。你不觉得吗?
    • 此外,如果只有单帧(单帧程序),KeyDispatcher 方法是否仍然危险且容易出错?
    • @Kerruba 是的,dic19 的建议比我的好。我完全忘记了输入映射的 JComponent.WHEN_IN_FOCUSED_WINDOW 修饰符。而且我认为,只有在您无法提供所需功能或需要修改焦点循环的情况下,才应使用 KeyboardFocusManager。例如,如果您显示嵌套消息(或任何其他模式)对话框,即使用户无法单击按钮,您的按钮也会使用新标题。
    猜你喜欢
    • 1970-01-01
    • 2010-09-29
    • 1970-01-01
    • 1970-01-01
    • 2011-11-27
    • 2016-03-27
    • 1970-01-01
    • 1970-01-01
    • 2015-02-04
    相关资源
    最近更新 更多