SwingUtilities.invokeLater

Posted

技术标签:

【中文标题】SwingUtilities.invokeLater【英文标题】: 【发布时间】:2011-11-04 01:02:22 【问题描述】:

我的问题与 有关。我应该什么时候使用它?每次需要更新 GUI 组件时都必须使用吗?它究竟是做什么的?是否有替代方案,因为它听起来不直观并且添加了看似不必要的代码?

【问题讨论】:

相当于Control.BeginInvoke @SLaks 这是否意味着如果我有一个线程我就不必使用它? @FadelMS,由于 Swing 框架产生了它自己的线程(EDT),因此您将始终拥有该线程。 (没有处理用户点击等的“消息检查”循环,对吧?那么各种 actionPerformed 方法是如何被调用的?由 EDT!)所以当你假设您有 一个 线程,我不得不解释一下,因为您 only 拥有 EDT(即,您抛出了一个 GUI 并从 main 方法的边缘掉了下来) .在这种情况下,不,您不会需要使用invokeLater。但是,您将无法进行任何“后台”处理。如果这样做,您将完全锁定 GUI... What does do? 的可能重复项 【参考方案1】:

每次需要更新 GUI 组件时都必须使用吗?

不,如果您已经在事件调度线程 (EDT) 上,则不会,这在响应用户发起的事件(例如点击和选择)时总是如此。 (actionPerformed 方法等总是由 EDT 调用。)

但是,如果您不是在 EDT 上并且想要进行 GUI 更新(如果您想从某个计时器线程或某个网络线程等更新 GUI),您将拥有安排由 EDT 执行的更新。这就是这个方法的用途。

Swing 基本上是线程不安全的。即,与该 API 的所有交互都需要在单个线程(EDT)上执行。如果您需要从另一个线程(计时器线程、网络线程...)进行 GUI 更新,您需要使用您提到的方法(SwingUtilities.invokeLater、SwingUtilities.invokeAndWait...)。

【讨论】:

@Jens:这意味着如果我在同一个线程(Swing)上或在运行时做事,我可以不用它。 嗯,“或在运行时做事”不是很精确。如果你在运行时做事,比如在计时器线程中,那么不,你不能没有这些类型的方法。【参考方案2】:
Swing is single threaded and all changes to the GUI must be done on EDT 

invokeLater()的基本用法

    主要方法应始终包裹在invokeLater()

    延迟(但异步)动作/事件到 EventQueue 结束,

    如果 EDT 不存在,那么您必须使用 invokeLater() 创建一个新的 EDT。您可以使用if (SwingUtilities.isEventDispatchThread()) ... 进行测试

    存在invokeAndWait(),但直到今天我(只是我的观点)找不到使用invokeAndWait() 而不是invokeLater() 的理由,除了对GUI(JTree 和JTable)的硬更改,但是只需Substance L&F(非常适合测试 EDT 上事件的一致性)

    基本资料:Concurrency in Swing

    后台任务的所有输出必须包装在invokeLater()

【讨论】:

【参考方案3】:

每个 Swing 应用程序至少有 2 个线程:

    执行应用程序的主线程 EDT(事件调度线程)是一个更新 UI 的线程(因此 UI 不会冻结)。

如果您想更新 UI,您应该在 EDT 中执行代码。 SwingUtilities.invokeLater、SwingUtilities.invokeAndWait、EventQueue.invokeLater、EventQueue.invokeAndWait 等方法允许您通过 EDT 执行代码。

【讨论】:

【参考方案4】:

我这次的问题与SwingUtilities.invokeLater有关:我应该什么时候使用它?

理解的关键是 Java 有一个单独的线程 (EDT) 处理 Swing 相关事件。

您应该使用invokeLater() 来显示桌面应用程序的主要JFrame(例如),而不是尝试在当前线程中执行此操作。它还将为以后正常关闭应用程序创建上下文。

对于大多数应用程序来说就是这样。

每次需要更新 GUI 组件时都必须使用吗?它的具体作用是什么?

没有。如果您修改一个 GUI 组件,它将触发一个事件,该事件被注册以供 Swing 稍后调度。如果有此事件的侦听器,EDT 线程将在某个地方调用它。您不需要使用invokeLater(),只需在组件上正确设置侦听器即可。

请记住,此线程与屏幕上的线程绘图框架等相同。因此,侦听器不应执行复杂/长时间/CPU 密集型任务,否则您的屏幕将冻结。

是否有替代方案,因为它听起来不直观并且添加了看似不必要的代码?

除了在组件上显示您的应用程序和您感兴趣的invokeLater() + 侦听器之外,您不需要编写更多代码。其余的由 Swing 处理。

【讨论】:

【参考方案5】:

大多数用户启动的事件(点击、键盘)已经在 EDT 上,因此您不必为此使用 SwingUtilities。这涵盖了很多情况,除了你的 main() 线程和更新 EDT 的工作线程。

【讨论】:

好吧,用户可以更新一个正在被更新 GUI 的线程监控的文件。 hmm ... 这不算作(直接,规则所在的位置)用户发起的事件:用户更新文件(在 EDT 上的 Swing 内部)并保存它(通过单击 EDT 上的按钮),触发 OS 文件更新事件(外部摇摆,关闭 EDT)通知,该通知到达负责更新 EDT 上的 GUI 的监视器(关闭 EDT)

以上是关于SwingUtilities.invokeLater的主要内容,如果未能解决你的问题,请参考以下文章