56

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

4

5 回答 5

52

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

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

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

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

于 2011-08-25T20:41:54.073 回答
14
Swing is single threaded and all changes to the GUI must be done on EDT 

基本用法invokeLater()

  1. 主要方法应始终包含在invokeLater()

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

  3. 如果 EDT 不存在,那么您必须使用invokeLater(). 你可以用 if (SwingUtilities.isEventDispatchThread()) {...

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

  5. 基础知识:Swing 中的并发

  6. 后台任务的所有输出都必须包含在invokeLater()

于 2011-08-25T21:00:10.737 回答
7

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

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

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

于 2011-08-25T20:57:10.357 回答
7

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

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

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

大多数应用程序就是这样。

每次需要更新 GUI 组件时都必须使用吗?它究竟是做什么的?

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

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

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

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

于 2011-08-25T20:57:56.247 回答
3

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

于 2011-08-25T20:57:17.197 回答