Java如何调度KeyEvents?

时间:2010-10-14 03:45:53

标签: java swing key-bindings keyevent

我已经在key bindings上阅读了几次明确的教程,但是我的脑缓存似乎不足以容纳复杂的过程。

我正在调试一个键绑定问题(事实证明我使用了错误的JComponent.WHEN_*条件),我偶然发现了一个简单而有趣的javadoc for package private javax.swing.KeyboardManager(不幸的是)匿名Java工程师。

我的问题是这样的:除了KeyEventDispatcher在开头检查时,描述是否遗漏和/或错误?

  

KeyboardManager类用于   帮助调度键盘操作   WHEN_IN_FOCUSED_WINDOW样式操作。   其他条件的行动是   直接在JComponent中处理。

     

这是对语义的描述   [原文如此]如何键盘调度   应该像我一样至少工作[原文如此]   明白它。

     

KeyEvents被分派到   重点部分。焦点经理   在处理此问题时获得第一次破解   事件。如果焦点管理员没有   想要它,然后JComponent调用   super.processKeyEvent()允许   听众有机会处理   事件。

     

如果没有听众“消费”   事件然后键绑定得到一个   射击。这是事情的起点   变得有趣。首先,KeyStokes   [sic]用WHEN_FOCUSED定义   条件有机会。如果没有   这些想要事件,然后是   组件虽然是[原文如此]的父母   寻找类型的行动   WHEN_ANCESTOR_OF_FOCUSED_COMPONENT。

     

如果还没有人接受它,那么它   风起云涌。然后我们寻找   注册的组件   WHEN_IN_FOCUSED_WINDOW事件和火灾   给他们。请注意,如果没有   然后我们将事件传递给   菜单栏,让他们有裂缝   在它。他们的处理方式不同。

     

最后,我们检查一下是否正在查看   内部框架。如果我们是,不   一个人想要这个活动然后我们向上移动   到InternalFrame的创建者并看到   如果有人想要这个活动(等等)   等等。)


(更新)如果你曾经想过关键绑定指南中的这个粗体警告:

  

由于搜索组件的顺序不可预测,避免重复WHEN_IN_FOCUSED_WINDOW绑定!

这是因为KeyboardManager#fireKeyboardAction中的这一部分:

     Object tmp = keyMap.get(ks);
     if (tmp == null) {
       // don't do anything
     } else if ( tmp instanceof JComponent) {
           ...
     } else if ( tmp instanceof Vector) { //more than one comp registered for this
         Vector v = (Vector)tmp;
             // There is no well defined order for WHEN_IN_FOCUSED_WINDOW
             // bindings, but we give precedence to those bindings just
             // added. This is done so that JMenus WHEN_IN_FOCUSED_WINDOW
             // bindings are accessed before those of the JRootPane (they
             // both have a WHEN_IN_FOCUSED_WINDOW binding for enter).
             for (int counter = v.size() - 1; counter >= 0; counter--) {
         JComponent c = (JComponent)v.elementAt(counter);
         //System.out.println("Trying collision: " + c + " vector = "+ v.size());
         if ( c.isShowing() && c.isEnabled() ) { // don't want to give these out
             fireBinding(c, ks, e, pressed);
         if (e.isConsumed())
             return true;
         }
     }

所以搜索的顺序实际上是可预测的,但显然依赖于这个特定的实现,因此最好完全依赖它 。让它变得不可预测。

(Javadoc和代码来自WinXP上的jdk1.6.0_b105。)

1 个答案:

答案 0 :(得分:1)

我们需要从Component.dispatchEventImpl开始调试。
只需阅读该方法的源注释,就可以了解事件如何在Swing中流动(您也可以从EventQueue.pumpEventsForHeirarchy开始向上一级)。

为清楚起见,让我从代码中摘录一下:

  1. 设置当前事件的时间戳和修饰符。预调度员。在我们通知AWTEventListeners之前,请在此处进行任何必要的重新定位/重新排序。
  2. 允许Toolkit将此事件传递给AWTEventListeners。
  3. 如果没有人使用过键事件,请允许KeyboardFocusManager处理它。
  4. 允许输入方法处理事件
  5. 在交付前预处理任何特殊事件
  6. 提供正常处理的事件
  7. 4061116的特殊处理:浏览器关闭模式对话框的钩子。:)
  8. 允许对等方处理事件。除KeyEvents外,它们将在所有KeyEventPostProcessors之后由对等方处理(请参阅DefaultKeyboardFocusManager.dispatchKeyEvent())
  9. 现在,您可以将上述流程与您的说明进行匹配,以确定其是否正确。但重点是你应该真的不依赖于私有类的javadoc,原因是开发人员通常不关心在代码更改时更新私有类的注释,因此文档可能会过时。