Как Java отправляет KeyEvents? - PullRequest
8 голосов
/ 14 октября 2010

Я несколько раз читал конкретное руководство по привязкам клавиш , но мой мозговой кэш кажется недостаточно большим, чтобы содержать сложные процессы.

Я отлаживал проблему с привязкой ключа (оказалось, что я использовал неправильное условие JComponent.WHEN_*), и наткнулся на краткий и веселый javadoc для пакета private javax.swing.KeyboardManager от (к сожалению, ) анонимный инженер Java.

У меня такой вопрос: кроме KeyEventDispatcher, который проверяется в самом начале, что-то упускает описание и / или ошибается?

Класс KeyboardManager используется для помочь диспетчеризировать действия клавиатуры для WHEN_IN_FOCUSED_WINDOW стиль действий. Действия с другими условиями обрабатывается непосредственно в JComponent.

Вот описание символики [так] о том, как клавиатура диспетчеризации должен работать по крайней мере [SIC], как я понимать это.

Ключевые события отправляются на сфокусированный компонент. Фокус менеджер получает первую трещину при обработке этого событие. Если менеджер фокуса не хотите, тогда 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 и код из jdk1.6.0_b105 на WinXP.)

1 Ответ

1 голос
/ 18 июня 2011

Нам нужно начать отладку с Component.dispatchEventImpl .
Простое чтение исходных комментариев метода должно дать вам идеальное представление о том, как события протекают в Swing (вы также можете начать на один уровень выше с EventQueue.pumpEventsForHeirarchy).

Для ясности просто позвольте мне датьвыписка из кода:

  1. Установка метки времени и модификаторов текущего события .;Pre-диспетчеры.Выполните все необходимые ретаргетинг / переупорядочение здесь, прежде чем мы уведомим AWTEventListeners.
  2. Разрешить Toolkit передавать это событие AWTEventListeners.
  3. Если никто не использовал ключевое событие, разрешите KeyboardFocusManager его обработать.
  4. Разрешить методам ввода обрабатывать событие
  5. Предварительная обработка любых специальных событий перед доставкой
  6. Доставить событие для нормальной обработки
  7. Специальная обработка для 4061116: Крюкдля браузера, чтобы закрыть модальные диалоги. :)
  8. Разрешить одноранговому узлу обрабатывать событие.За исключением KeyEvents, они будут обрабатываться одноранговым узлом после всех KeyEventPostProcessors (см. DefaultKeyboardFocusManager.dispatchKeyEvent ())

Теперь вы можете сопоставить приведенный выше поток с вашим описанием, чтобы определить, является ли оно правильным или нет.Но дело в том, что вы действительно не должны зависеть от javadocs приватных классов, причина в том, что разработчики обычно не заботятся об обновлении комментариев приватных классов при изменении кода, поэтому документы могут устареть.

...