监听组件层次结构的关键事件
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
【讨论】:
以上是关于监听组件层次结构的关键事件的主要内容,如果未能解决你的问题,请参考以下文章