2010-10-14 72 views
8

我已经几次阅读key bindings上的明确教程,但我的大脑缓存似乎不足以容纳复杂的过程。 (不幸的是)匿名的Java工程师偶然发现了一个简洁而热闹的javadoc,供私人包javax.swing.KeyboardManager使用。Java如何派发KeyEvent?

我的问题是这样的:除了最初检查的KeyEventDispatcher描述是否遗漏和/或错误?

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

这里的symantics 如何键盘调度 应该ATLEAST [原文]工作,我 理解[原文]的描述。

KeyEvents被分派到 的焦点组件。焦点经理 在处理此事件时首先得到解决。如果焦点管理者不想要 ,那么JComponent调用 super.processKeyEvent()这允许 听众有机会处理 事件。

如果没有一个听众“消耗” 事件,则键绑定获得 镜头。这是开始 变得有趣的地方。首先,用WHEN_FOCUSED 条件定义的KeyStokes [sic]得到一个机会。如果没有 这些想要的事件,然后 组件行走,虽然它的[sic]父母 寻找类型 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。)

+0

这是对KeyEvent处理的一个很好的分析......但我不知道它是否真的是一个可以回答的问题。 – BoffinbraiN 2011-05-08 10:09:55

+0

@BoffinbraiN:我希望有几十个摆动徽章的人会说“就我所知,这是正确的”,这是最好的:) :) – 2011-05-09 13:47:23

+1

是的,那肯定会更好!但是我认为对于这个深度的东西,它确实是针对特定实现的,而且你比大多数勤奋的程序员都仔细地仔细审查了这个实现。 ;)当然,最好不要让你的代码依赖于这个特定的细节。 – BoffinbraiN 2011-05-09 16:41:42

回答

1

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

为清楚起见只是让我给从代码的摘录:

  1. 设置时间戳和当前事件的改性剂;预调度员。在通知AWTEventListeners之前,在这里做任何必要的重定向/重新排序。
  2. 允许工具包将此事件传递给AWTEventListeners。
  3. 如果没有人使用关键事件,则允许KeyboardFocusManager处理它。
  4. 允许输入的方法来处理事件
  5. 程序前交付
  6. 之前的任何特殊事件的正常处理交付事件
  7. 为4061116特殊处理:挂钩浏览器关闭模式对话框:)
  8. 允许对等方处理事件。除此之外的KeyEvents,他们将所有的KeyEventPostProcessors后对被处理(见DefaultKeyboardFocusManager.dispatchKeyEvent())

现在你可以配合你的描述上述流程,以确定其是否正确与否。但关键是你不应该依赖私有类的javadoc,原因是开发人员通常不会在代码改变时更新私有类的注释,所以文档可能会过时。