Отладка фокуса в Java

проблема:

я пытаюсь отладить некоторые проблемы, связанные с фокусом, в моем приложении Java Swing. Бывают моменты, когда некоторые компоненты, похоже, захватывают фокус, и я не могу понять, где в коде это происходит.

что я пробовал:

  • A VetoableChangeListener с KeyboardFocusManager (для focusOwner). Это дает мне информацию о том, какие компоненты теряют и получают фокус, но это не помогает мне определить, где в коде фокус просят.

  • таможни KeyboardFocusManager. Но и в этом я могу вмешаться только тогда, когда он получает события. К этому времени стек вызовов вызова requestFocus уже потеряли.

  • таможни EventQueue. Но и там я могу вмешаться в dispatchEvent метод, который снова вызывается из EDT. Снова стек вызовов теряется (интересно, что postEvent(AWTEvent) это не назвать).

вопрос:

что Я ищу стек вызовов, когда вызов requestFocusInWindow сделано. Можно ли получить эту информацию. Возможно, если бы я мог переопределить метод, используемый для публикации события в EventQueue, затем я могу распечатать дамп стека. Однако EventQueue.postEvent(AWTEvent) не вызывается.

кто может предложить решение, которое поможет мне получить состояние стека при вызове requestFocus или requestFocusInWIndow может быть сделано?

2 ответов


кажется, они (Солнце) действительно не хотят, чтобы вы это делали. На первый взгляд, в этом пути нет виртуальных методов, которые можно легко переопределить, а не в EventQueue (postEvent используется только для invokeLater и синтезирования событий из кода приложения), ни в KeyboardFocusManager (как вы обнаружили, переопределяемые методы вызываются позже из цикла отправки.)

к счастью, если вы используете Sun JRE, там is место, куда вы можете вставить код, но это не красиво:

Component.requestFocus() вызывает static KeyboardFocusManager.setMostRecentFocusOwner(Component), который обновляет частный static Map под названием mostRecentFocusOwners.

Итак, если вы можете получить доступ к этому static Map используя отражение, вы можете заменить его на пересылку Map что следы призывает его put способ:

import com.google.common.collect.ForwardingMap;

// ...

Field mrfoField = KeyboardFocusManager.class.getDeclaredField("mostRecentFocusOwners");
mrfoField.setAccessible(true);
final Map delegate = (Map) mrfoField.get(null);
Map mrfo = new ForwardingMap() {
    public Object put(Object key, Object value) {
        new Throwable().printStackTrace();
        return super.put(key, value);
    }
    protected Map delegate() {
        return delegate;
    }
};
mrfoField.set(null, mrfo);

и это будет ловить звонки на requestFocus и дать вам трассировки стека.


я наткнулся на этот элегантный решение на