使用 invokeLater 后 Swing UI 不更新

Posted

技术标签:

【中文标题】使用 invokeLater 后 Swing UI 不更新【英文标题】:Swing UI not updating after using invokeLater 【发布时间】:2010-11-13 18:57:36 【问题描述】:

我的 Java Swing UI 没有像我认为的那样更新/重新绘制。应用程序发送 XMPP 消息并在不同线程上接收响应。处理该响应并更新 UI 以反映消息中包含的信息。

收到响应后,我使用更新 JPanel 组件

javax.swing.SwingUtilities.invokeLater(new Runnable() 
    public void run()  /* execute logic to update panel */ 
);

自从我使用 Java 开发以来已经有一段时间了,但是根据我的在线研究,invokeLater 将可运行对象排队等待在 GUI 线程上执行。但是,直到我在应用程序中执行导致重绘的其他操作(例如调整窗口大小)时,我的 GUI 才会更新。我错过了什么?在更新面板的逻辑之后,我尝试了 invalidate() 和 repaint() 的各种组合,但结果仍然相同 - 直到我调整窗口大小时 GUI 才会更新。

编辑:当我说更新面板时,具体来说,我是在执行 removeAll() 然后添加一些 JLabels。

【问题讨论】:

【参考方案1】:

如果您的意思是“更新面板”是指添加或删除组件,那么您最好使用 invalidate() 或 revalidate() 以便布局管理器捕获更改。

请参阅here 了解类似问题。

【讨论】:

【参考方案2】:

如果您在 GUI 事件处理(例如动作侦听器)期间从面板中添加或删除组件,调用 doLayout() 应该有望解决您的问题。我发现当 GUI 不更新时,调用 validate()、doLayout() 和 repaint() 往往会解决问题。

【讨论】:

其实你不应该直接调用doLayout(),而应该调用revalidate()。 @Stroboskop 尽管您不应该这样做,但文档中说“通常在验证组件时调用它。”我的经验表明,在事件处理期间从容器中添加和删除组件时,revalidate() 不会调用此方法。 对。由于所有这些都发生在 EventQueue 中,因此很有可能在您完成之前不会查看重新验证标志。但我猜想调用 repaint() 会在稍后触发绘画和布局...... 谢谢谢谢谢谢!如果不是因为这个答案,我现在将逐行阅读我的自定义布局管理器的代码! @Stroboskop 我只是从我的 ActionListener 调用 revalidate() 和 repaint() 但是容器只有在我调整窗口大小时才更新,即使我向该容器的每个可能的容器发送了垃圾邮件 revalidate() 和 repaint() 调用......从现在开始,当我遇到这样的问题时,我将按顺序调用 invalidate()、doLayout()、validate()、revalidate()、repaint()。【参考方案3】:

在面板中添加/删除组件后,您应该使用:

panel.revalidate(); // this works 99% of the time
panel.repaint(); // sometimes needed.

我相信 validate()、invalidate() 等其他东西是 AWT 时代遗留下来的,而 revalidate() 做得更好,是专门为 Swing 添加的。

【讨论】:

以上是关于使用 invokeLater 后 Swing UI 不更新的主要内容,如果未能解决你的问题,请参考以下文章

Java开发中的线程安全选择与SwingUtilities类的invokeLater()或invokeAndWait()

Swing 窗口的初始化方式有啥区别?

Java中 EvenQueue.invokeLater用法

SwingUtilities.invokeLater

Swing GUI 不更新

转Swing 与EDT线程