【问题标题】:How does Java dispatch KeyEvents?Java 如何调度 KeyEvents?
【发布时间】:2010-10-14 03:45:53
【问题描述】:

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

我正在调试一个键绑定问题(结果发现我使用了错误的JComponent.WHEN_* 条件),我偶然发现了一个简明有趣的 javadoc 包私有 javax.swing.KeyboardManager 由一位(不幸的)匿名 Java 工程师编写。

我的问题是:除了一开始检查的KeyEventDispatcher描述是否遗漏和/或错误?

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

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

KeyEvents 被分派到 重点组件。焦点管理器 第一次处理这个 事件。如果焦点管理器没有 想要它,然后 JComponent 调用 super.processKeyEvent() 这允许 听众有机会处理 事件。

如果没有听众“消费” 事件然后键绑定得到一个 射击。这是事情开始的地方 变得有趣。一、KeyStokes [原文如此] 用 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。)

【问题讨论】:

  • 这是对 KeyEvent 处理的一个很好的分析......但我不知道它是否真的是一个可以回答的问题。
  • @BoffinbraiN:我希望有几十个挥杆徽章的人说“据我所知这是正确的”:)
  • 是的,那肯定会更好!但我认为,对于这么深的东西,它确实是特定于实现的,而且你已经比大多数勤奋的程序员更仔细地审查了这个实现。 ;) 当然,最好不要让你的代码依赖于这个特定的细节。
  • 如果你把它分解成一个问题和一个自我回答,这可能会更好。然后,您可以接受您的答案或让人们对其进行投票。
  • +1 表示“大脑缓存”。 ;-)

标签: java swing key-bindings keyevent


【解决方案1】:

我们需要从Component.dispatchEventImpl开始调试。
只需阅读该方法的源 cmets 即可让您对事件在 Swing 中的流动方式有一个完美的了解(您也可以从 EventQueue.pumpEventsForHeirarchy 开始上一级)。

为了清楚起见,让我摘录一段代码:

  1. 设置当前事件的时间戳和修饰符。预调度员。在我们通知 AWTEventListener 之前,请在此处执行任何必要的重定向/重新排序。
  2. 允许 Toolkit 将此事件传递给 AWTEventListeners。
  3. 如果没有人使用过按键事件,则允许 KeyboardFocusManager 处理它。
  4. 允许输入法处理事件
  5. 在交付前预处理任何特殊事件
  6. 交付事件以进行正常处理
  7. 4061116 的特殊处理:浏览器挂钩以关闭模式对话框。:)
  8. 允许对等方处理事件。除了 KeyEvents,它们将在所有 KeyEventPostProcessor 之后由 peer 处理(参见 DefaultKeyboardFocusManager.dispatchKeyEvent())

现在您可以将上述流程与您的描述相匹配,以确定它是否正确。但关键是你真的不应该依赖私有类的javadocs,原因是开发人员通常不关心在代码更改时更新私有类的cmets,所以文档可能会过时。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多