问题:
我正在尝试在Java Swing应用程序中调试一些与焦点相关的问题。有时候,某些组件似乎引起了人们的关注,而我无法弄清楚这种情况在代码中发生了什么。
我尝试过的是:
VetoableChangeListener
的KeyboardFocusManager
(用于focusOwner
)。这的确为我提供了有关哪些组件丢失和获得焦点的信息,但并不能帮助我指出在代码中请求焦点的位置。KeyboardFocusManager
。但是在那方面,我也只能在事件发生时进行干预。到那时,对requestFocus
的调用的调用堆栈已经丢失。EventQueue
。但是我也可以干预EDT再次调用的dispatchEvent
方法。再次,调用堆栈丢失了(有趣的是,没有调用postEvent(AWTEvent)
)。问题:
我正在寻找的是对
requestFocusInWindow
进行调用时的调用堆栈。是否有可能获得此信息。也许,如果我可以在EventQueue
中重新定义用于发布事件的方法,那么我可以打印堆栈转储。但是,EventQueue.postEvent(AWTEvent)
不会被调用。有人可以提出一种解决方案,当对
requestFocus
或requestFocusInWIndow
进行了调用时,该解决方案将帮助我获取堆栈的状态? 最佳答案
看来他们(Sun)确实不希望您这样做。乍一看,在该路径中似乎没有任何可以轻松覆盖的虚拟方法,在EventQueue
中没有使用(postEvent
仅用于invokeLater
和来自应用程序代码的合成事件),也没有在KeyboardFocusManager
中使用(如您所知,稍后会在分派(dispatch)循环中调用可覆盖的方法。)
幸运的是,如果您使用的是Sun JRE,则可以在其中插入代码,但是它并不漂亮:Component.requestFocus()
调用静态KeyboardFocusManager.setMostRecentFocusOwner(Component)
,后者会更新称为Map
的私有(private)静态mostRecentFocusOwners
。
因此,如果您可以使用反射访问该静态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
的调用,并为您提供堆栈跟踪。