监听组件层次结构的关键事件

Posted

技术标签:

【中文标题】监听组件层次结构的关键事件【英文标题】:Listening to key events for a component hierarchy 【发布时间】:2011-06-20 07:46:38 【问题描述】:

我有一个 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 中注册任何内容,因此不会为相同的击键注册其他内容。

【问题讨论】:

【参考方案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

【讨论】:

以上是关于监听组件层次结构的关键事件的主要内容,如果未能解决你的问题,请参考以下文章

监听器事件事件源事件注册深度剖析

关于 Java Swing 中组件类的继承层次结构的说明?

反应事件层次结构问题

Vue 组件层次结构和传递数据

软件工程中软件结构图和层次图的异同

在 Android Navigation 组件中使用 backstack 打开不同层次结构中的片段