Java如何分派KeyEvents?

Java如何分派KeyEvents?,java,swing,key-bindings,keyevent,Java,Swing,Key Bindings,Keyevent,我已经阅读了几次明确的教程,但我的大脑缓存似乎不够大,无法容纳复杂的过程 我在调试一个密钥绑定问题(结果是我使用了错误的JComponent.WHEN*条件),我偶然发现了一个简洁而有趣的javadoc,它是一个匿名Java工程师(不幸的是)为私有包编写的 我的问题是:除了在最开始检查的KeyEventDispatcher,描述是否遗漏和/或错误? KeyboardManager类用于 帮助为应用程序分派键盘操作 当以窗口样式操作为焦点时。 具有其他条件的操作是 直接在JComponent中处理

我已经阅读了几次明确的教程,但我的大脑缓存似乎不够大,无法容纳复杂的过程

我在调试一个密钥绑定问题(结果是我使用了错误的
JComponent.WHEN*
条件),我偶然发现了一个简洁而有趣的javadoc,它是一个匿名Java工程师(不幸的是)为私有包编写的

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

KeyboardManager类用于 帮助为应用程序分派键盘操作 当以窗口样式操作为焦点时。 具有其他条件的操作是 直接在JComponent中处理

下面是对symantics的描述 [原文如此]键盘如何调度 至少应该像我一样工作 理解它

KeyEvents被发送到 重点部分。焦点管理器 在处理此文件时获取第一个裂纹 事件如果焦点管理器没有 想要它,JComponent就会调用它 super.processKeyEvent()这允许 听众有机会处理问题 事件

如果没有侦听器“消费” 然后,keybindings获得一个 射击。事情就是从这里开始的 变得有趣。首先,密钥 [sic]定义为当_聚焦时 我有机会。如果没有 他们想要的是事件,然后是 组件虽然是[sic]父母,但仍能行走 寻找类型的动作 当\u聚焦\u组件的\u祖先\u时

如果还没有人拿走它,那么它 在这里结束。然后我们寻找 为注册的组件 当窗口事件和火灾发生时 对他们来说。请注意,如果没有这些 找到后,我们将事件传递给 菜单栏,让他们有一个裂缝 看看吧。他们的处理方式不同

最后,我们检查一下我们是否在看 内部框架。如果我们是和否 一个人想要这个活动,然后我们继续前进 致内部框架的创建者,请参见 如果有人想参加这个活动(等等) 等等)


(更新)如果您曾经对《密钥绑定指南》中的此粗体警告感到疑惑,请执行以下操作:

因为搜索组件的顺序是不可预测的,在聚焦窗口绑定中避免重复

这是因为
键盘管理器#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。)

我们需要从开始调试
只需阅读该方法的源注释,您就可以完全了解事件在Swing中如何流动(您也可以从EventQueue.pumpeventsforheirarch启动一个级别)

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

  • 设置当前事件的时间戳和修饰符。;预调度员。在我们通知AWTEventListeners之前,请在此执行任何必要的重定目标/重新排序
  • 允许工具箱将此事件传递给AWTEventListeners
  • 如果没有人使用密钥事件,请允许KeyboardFocusManager处理它
  • 允许输入方法处理事件
  • 交付前对任何特殊事件进行预处理
  • 传递事件以进行正常处理
  • 4061116的特殊处理:用于浏览器关闭模式对话框的挂钩。:)
  • 允许对等方处理事件。除KeyEvents外,它们将在所有KeyEventPostProcessor之后由对等方进行处理(请参阅DefaultKeyboardFocusManager.dispatchKeyEvent()

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

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