空指针异常:java.awt.EventQueue.getCurrentEventImpl

11

我已经将一个Swing应用程序迁移到了Java 8,最近我们看到了以下的NPE异常。

java.lang.NullPointerException
at java.awt.EventQueue.getCurrentEventImpl(EventQueue.java:848)
at java.awt.EventQueue.getCurrentEvent(EventQueue.java:842)
at java.awt.Component.requestFocusHelper(Component.java:7628)
at java.awt.Component.requestFocusHelper(Component.java:7620)
at java.awt.Component.requestFocus(Component.java:7495)
at javax.swing.JComponent.requestFocus(JComponent.java:1504)
at javax.swing.plaf.basic.BasicPopupMenuUI$MenuKeyboardHelper.stateChanged(BasicPopupMenuUI.java:1173)
at javax.swing.MenuSelectionManager.fireStateChanged(MenuSelectionManager.java:202)
at javax.swing.MenuSelectionManager.setSelectedPath(MenuSelectionManager.java:129)
at javax.swing.JPopupMenu.setVisible(JPopupMenu.java:784)
at javax.swing.JPopupMenu.show(JPopupMenu.java:965)
at org.tbee.swing.StandardComponentPopupMenu.showJTableMenu(StandardComponentPopupMenu.java:555)
at org.tbee.swing.StandardComponentPopupMenu$2.run(StandardComponentPopupMenu.java:175)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:756)
at java.awt.EventQueue.access$500(EventQueue.java:97)
at java.awt.EventQueue$3.run(EventQueue.java:709)
at java.awt.EventQueue$3.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:75)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:726)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)

由于使用了lambda表达式,因此迁回J7是个问题,所以我无法轻易确认这是否真的是一个J8问题。但是相关代码已经运行了几年时间,经历了Java 5、6和7的考验,因此很可能是J8特有的。

异常的原因是EventQueue中的currentEvent未设置。它应该通过setCurrentEventAndMostRecentTimeImpl(AWTEvent e)方法进行设置。然而,如果我在堆栈中向后跟踪,我发现在EventQueue:756(Java 1.8.0u45)之后,恰好调用了该方法并执行了派发操作。

    if (event instanceof ActiveEvent) {
        // This could become the sole method of dispatching in time.
        setCurrentEventAndMostRecentTimeImpl(event);
        ((ActiveEvent)event).dispatch();

我不知道为什么那个变量是空的。由于所有事件都被代码片段处理,调试几乎是不可能的。

有人知道Swing在J8中的事件处理是否有变化吗?


2
我已确认它是J8,因为我有一个测试类针对堆栈中看到的StandardComponentPopupMenu。它在J6和J7上运行正常,但在J8上出现NPE错误。 - tbeernot
2
有人正在推送一个新的EventQueue实例吗? - Holger
我在JDK 11.0.4中仍然偶尔看到这个问题:我们的应用程序代码调用EventQueue.getCurrentEvent()并获得空返回,尽管在调用堆栈中我可以看到Component.dispatchEventImpl(JEditorPane)最近已经超过了应该将非空值设置为EventQueue.currentEvent(由WeakReference持有)的点。当调用堆栈中的代码仍然持有局部变量引用事件时,WeakReference被释放是有效的吗? - Luke Usherwood
在下面的补丁之后,它再也没有出现过。我现在正在 J15 上运行它。 - tbeernot
谢谢更新。在那种情况下,我经常发现invokeLater是一个好主意。(避免在处理其他事件时启动新的操作 - 您可能会遭受不一致/部分修改的内部状态。)不幸的是,我遇到的崩溃是不同的用例 - 代码需要立即回答“是否仍在处理同一事件?” - Luke Usherwood
3个回答

4

最终,弹出式菜单的打开必须在EDT上重新安排时间,即使打开它的代码正在EDT上运行。

    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            jpopupMenu.show(c, x, y);
        }
    });

只有在运行于J8时。

1
由于您正在使用Java 8,可以使用SwingUtilities.invokeLater(() → jpopupMenu.show(c,x,y)); - Holger
是的,好的,这段代码所在的Swing库(用于J8应用程序)仍然基于J6。 - tbeernot

2

另外,请确保如果您正在安装备用事件队列,则需要在其自己的事件上执行此操作,例如:

Swingutilities.invokeLater(){
    ... run() {
       ..do event queue push();
    }
}

问题在于事件队列的推送并没有迁移当前事件,而只是挂起的事件。

你有这个声明的来源吗? - Ozymandias

-2

以下代码运行良好:

   SwingUtilities.invokeLater(new Runnable() {
                  @Override
                  public void run() {
                      Toolkit.getDefaultToolkit().getSystemEventQueue().push(Customized Event);
                  }
              });

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接