Java如何调度KeyEvents?

Geo*_*eng 9 java swing keyevent key-bindings

我已经阅读了几次关于键绑定的明确教程,但是我的脑缓存似乎不足以容纳复杂的进程.

我正在调试一个键绑定问题(事实证明我使用的是错误的JComponent.WHEN_*条件),我偶然发现javax.swing.KeyboardManager了一个(不幸的)匿名Java工程师私有包的简洁和欢闹的javadoc .

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

KeyboardManager类用于帮助调度WHEN_IN_FOCUSED_WINDOW样式操作的键盘操作.具有其他条件的操作直接在JComponent中处理.

下面是我理解的键盘调度应该如何工作的语法[原文如此]的描述.[原文如此].

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;
         }
     }
Run Code Online (Sandbox Code Playgroud)

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

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

Sur*_*ran 2

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

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

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

现在您可以将上面的流程与您的描述进行匹配来判断是否正确。但重点是你真的不应该依赖私有类的javadoc,原因是开发人员通常不关心在代码更改时更新私有类的注释,因此文档可能会过时。