SwingUtilities.invokeLater
是一个在Java Swing 中用于将代码安全地提交到事件分发线程(Event Dispatch Thread,简称EDT)执行的方法 。EDT 是Swing 应用程序中负责处理GUI 事件和更新界面的线程。为了保证Swing 组件的线程安全,所有对Swing 组件的更新都必须在EDT 中进行。invokeLater
允许你在其他线程中(例如后台线程)执行代码,然后将更新UI 的操作安全地放入EDT 队列,让EDT 在适当的时候执行这些操作。
下面是使用 SwingUtilities.invokeLater
的基本步骤和示例:
- 创建一个
Runnable
对象:将你想要在EDT 中执行的代码封装在一个Runnable
接口的实现类中。这个Runnable
对象会在invokeLater
调用后被执行。
Java
Runnable updateUI = new Runnable() {
public void run() {
// 在这里更新你的 Swing 组件
myComponent.setText("更新后的文本");
myComponent.repaint(); // 如果需要,重绘组件
}
};
- 调用
SwingUtilities.invokeLater()
将Runnable
对象作为参数传递给SwingUtilities.invokeLater()
方法。
Java
SwingUtilities.invokeLater(updateUI);
- 方法立即返回:
invokeLater
方法会立即返回,而不会等待Runnable
对象在EDT 中执行完毕。它会将Runnable
对象放入EDT 的事件队列,稍后由EDT 处理。
示例:
假设你有一个 JTextField
控件 myTextField
,你需要在后台线程中获取一些数据,然后更新这个文本框的内容。
Java
import javax.swing.*;
import java.awt.*;
import java.util.concurrent.ExecutionException;
public class SwingInvokeLaterExample {
private JFrame frame;
private JTextField myTextField;
public SwingInvokeLaterExample() {
frame = new JFrame("SwingUtilities.invokeLater 示例");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300, 200);
frame.setLayout(new FlowLayout());
myTextField = new JTextField(20);
frame.add(myTextField);
JButton button = new JButton("启动后台任务");
button.addActionListener(e -> {
// 启动一个后台线程
new SwingWorker<String, Void>() {
@Override
protected String doInBackground() throws Exception {
// 模拟耗时操作
Thread.sleep(2000);
return "后台数据";
}
@Override
protected void done() {
try {
String data = get();
// 使用 invokeLater 将更新 UI 的操作放入 EDT
SwingUtilities.invokeLater(() -> {
myTextField.setText(data);
});
} catch (InterruptedException | ExecutionException ex) {
ex.printStackTrace();
}
}
}.execute();
});
frame.add(button);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(SwingInvokeLaterExample::new);
}
}
在这个例子中,doInBackground
方法模拟了一个耗时的后台操作,在 done
方法中,我们使用 SwingUtilities.invokeLater
将 myTextField.setText(data)
的操作放入EDT,以安全地更新UI。
总结:
SwingUtilities.invokeLater
确保了Swing 组件的线程安全,允许在非EDT 线程中执行耗时操作,并将UI 更新操作安全地提交到EDT。这是一个非常重要的Swing 编程技巧,能帮助你避免常见的UI 错误。
详细解释 EDT:
-
EDT 的作用:
EDT 是Swing 用于处理用户界面事件(如鼠标点击、键盘输入等)和更新GUI 的专用线程。它确保了Swing 组件的线程安全,避免了多个线程同时访问和修改GUI 导致的各种问题。
-
单线程特性:
虽然Java 是多线程的,但Swing 的EDT 是一个单线程。所有Swing 组件的更新和事件处理都必须通过EDT 来完成,这意味着任何对Swing 组件的直接操作都必须在EDT 线程中进行。所以不要在EDT中执行耗时长的任务 ,会导致Swing程序卡顿。耗时操作放在独立的任务线程通过SwingWorker启动。
-
线程安全问题:
如果在非EDT 线程中直接操作Swing 组件,可能会导致各种问题,例如界面卡顿、数据不同步、甚至是程序崩溃。
-
如何处理:
要确保Swing 组件的线程安全,需要使用
SwingUtilities.invokeLater()
或SwingUtilities.invokeAndWait()
方法将需要更新Swing 组件的代码提交到EDT 线程执行。
参考:
- 长时间任务要放到 :SwingWorker详解
- EDT(Event Dispatching Thread,"事件分配线程")blog.csdn.net/hjm0823/art...