Я пытаюсь отладить некоторые связанные с фокусом проблемы в своем Java приложение Swing. Существуют времена, когда некоторые компоненты, кажется, захватывают фокус, и я не могу выяснить, где в коде это происходит.
A VetoableChangeListener
с KeyboardFocusManager
(для focusOwner
). Это действительно дает мне информацию, о которой компоненты теряют и получают фокус, но это не помогает мне прикрепить точку, где в коде фокус требуют.
Пользовательское KeyboardFocusManager
. Но в этом также я могу вмешаться только, когда это получает события. К тому времени стек вызовов вызова к requestFocus
уже потерян.
Пользовательское EventQueue
. Но там также я в состоянии вмешаться в dispatchEvent
метод, который снова называют от EDT. Снова стек вызовов потерян (интересно postEvent(AWTEvent)
не назван).
То, что я ищу, является стеком вызовов когда вызов к requestFocusInWindow
сделан. Действительно ли возможно получить эту информацию. Возможно, если я мог бы переопределить метод, используемый для регистрации события в EventQueue
, тогда я могу распечатать дамп стека. Однако EventQueue.postEvent(AWTEvent)
не становится вызванным.
Может любой предлагать решение, которое поможет мне получить состояние стека когда вызов к requestFocus
или requestFocusInWIndow
возможно, был сделан?
Похоже, они (Солнце) действительно не хотят, чтобы вы этого делали. На первый взгляд кажется, что в этом пути нет никаких виртуальных методов, которые можно было бы легко переопределить, не в EventQueue
( postEvent
используется только для invokeLater
и синтезирование событий из кода приложения), ни в KeyboardFocusManager
(как вы обнаружили, переопределяемые методы вызываются позже из цикла диспетчеризации).
К счастью, если вы используете Sun JRE, там - это место, куда можно вставить код, но это не очень красиво:
Component.requestFocus ()
вызывает статический KeyboardFocusManager.setMostRecentFocusOwner (Component)
, который обновляет частный статический Карта
называется mostRecentFocusOwners
.
Итак, если вы можете получить доступ к этой статической карте
с помощью отражения, вы можете заменить ее перенаправляющей картой
, которая отслеживает вызовы его метода 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
и предоставит вам трассировку стека.