【问题标题】:Listening to key events for a component hierarchy监听组件层次结构的关键事件
【发布时间】:2023-04-07 03:40:01
【问题描述】:

我有一个 Swing 应用程序,它需要根据是否按下 control 或 alt 键来显示不同的控件集。我向主组件添加了一个 KeyListener,但仅在选择该组件时才通知它,而不是在选择子组件时通知。有没有办法监听组件和所有后代的事件?

编辑:

我尝试使用主组件的 InputMap,但按下修饰键时没有触发任何事件。具体来说,我有以下代码:

InputMap inputMap = panel.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
inputMap.put(KeyStroke.getKeyStroke("pressed CONTROL"), "test1");
inputMap.put(KeyStroke.getKeyStroke("released CONTROL"), "test2");
ActionMap actionMap = panel.getActionMap();
actionMap.put("test1", new AbstractAction() {
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("pressed");
    }
});
actionMap.put("test2", new AbstractAction() {
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("released");
    }
});

当按下和释放控制键时,这将打印“released”而不是“pressed”。没有其他任何东西在任何 InputMap 中注册任何内容,因此不会为相同的击键注册其他内容。

【问题讨论】:

    标签: java events swing keylistener


    【解决方案1】:

    只需像这样更改您的 getKeyStroke(...) 调用:

    InputMap inputMap = panel.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
    inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_CONTROL, KeyEvent.CTRL_DOWN_MASK, false), "test1");
    inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_CONTROL, 0, true), "test2");
    ActionMap actionMap = panel.getActionMap();
    actionMap.put("test1", new AbstractAction() {
        @Override
        public void actionPerformed(ActionEvent e) {
            System.out.println("pressed");
        }
    });
    actionMap.put("test2", new AbstractAction() {
        @Override
        public void actionPerformed(ActionEvent e) {
            System.out.println("released");
        }
    });
    

    我花了很多时间试错才想出正确的咒语。

    使用 getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) 很重要,以便能够监听子小部件和更深层次的小部件。

    在查找控制键 PRESS 事件时,除了 KeyEvent.VK_CONTROL 之外,指定 KeyEvent.CTRL_DOWN_MASK 尤为重要。您修改后的代码示例中缺少此特定细节。

    【讨论】:

    • 我遇到了WHEN_ANCESTOR_OF_FOCUSED_COMPONENT 的问题,发现使用WHEN_IN_FOCUSED_WINDOW 更有用。
    【解决方案2】:

    您也许可以使用Global Event Listener

    【讨论】:

      【解决方案3】:

      您可以考虑使用the InputMap and ActionMap 的一些swing 组件。您可以使用JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT 指定,以表明您希望在组件或其子组件处于焦点时响应给定的击键。

      如果您不想使用 InputMap 或 ActionMap,您可以将 KeyListener 添加到所有子组件中:

      for (Component child : parent.getComponents())
      {
       child.addKeyListener(keyListener);
      }
      

      【讨论】:

      • 这适用于“释放的 CONTROL”按键,但不适用于“按下的 CONTROL”。 alt 和 shift 也是如此。
      • @Adam Crume 好吧,一些控件可能正在监听 ctrl、alt 或 shift。但是,至少使用其他按键进行测试,它会在按键时启动给定的动作。但不可否认,它会在按下按键时反复启动。
      • Zack 在 InputMap 和 ActionMap 中提到的是使用键绑定。再次查看教程,它将解决您的问题。
      • 不,教程没有解决我的问题。 InputMap 不适用于这种情况。我发现将 press KeyStroke 更改为“ctrl press CONTROL”会响应控制键的按下,但还有另一个问题:我想知道何时按下控制键,无论是否按下 alt/altGr/shift/meta 或不是。如果不为我关心的每个修改键添加 16 个击键,这是不可能的。我改用这个:javaworld.com/javaworld/javatips/jw-javatip69.html
      • @Adam Crume 好的。但是,我和我提供的充满鳗鱼的气垫船教程中的信息仍然很适合将来了解。祝你的应用好运!
      【解决方案4】:

      您可能想尝试使用键绑定而不是 KeyListener。键绑定是一个更高级别的构造,即使“监听”的组件没有焦点,也可以监听按键 - 与 KeyListeners 相反。您可以在 Swing 教程中找到更多相关信息:How to use key bindings

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-12-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-09-19
        • 1970-01-01
        相关资源
        最近更新 更多