SwingUtilities.invokeLater 详解

SwingUtilities.invokeLater 是一个在Java Swing 中用于将代码安全地提交到事件分发线程(Event Dispatch Thread,简称EDT)执行的方法 。EDT 是Swing 应用程序中负责处理GUI 事件和更新界面的线程。为了保证Swing 组件的线程安全,所有对Swing 组件的更新都必须在EDT 中进行。invokeLater 允许你在其他线程中(例如后台线程)执行代码,然后将更新UI 的操作安全地放入EDT 队列,让EDT 在适当的时候执行这些操作。

下面是使用 SwingUtilities.invokeLater 的基本步骤和示例:

  1. 创建一个 Runnable 对象:将你想要在EDT 中执行的代码封装在一个 Runnable 接口的实现类中。这个 Runnable 对象会在 invokeLater 调用后被执行。
Java 复制代码
    Runnable updateUI = new Runnable() {
        public void run() {
            // 在这里更新你的 Swing 组件
            myComponent.setText("更新后的文本");
            myComponent.repaint(); // 如果需要,重绘组件
        }
    };
  1. 调用 SwingUtilities.invokeLater()Runnable 对象作为参数传递给 SwingUtilities.invokeLater() 方法。
Java 复制代码
    SwingUtilities.invokeLater(updateUI);
  1. 方法立即返回: 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.invokeLatermyTextField.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 线程执行。

参考:

相关推荐
程序员码歌5 小时前
明年35岁了,如何破局?说说心里话
android·前端·后端
橙*^O^*安6 小时前
Go 语言基础:变量与常量
运维·开发语言·后端·golang·kubernetes
工程师小星星6 小时前
Golang语言的文件组织方式
开发语言·后端·golang
哈喽姥爷6 小时前
Spring Boot---自动配置原理和自定义Starter
java·spring boot·后端·自定义starter·自动配置原理
舒一笑8 小时前
为什么where=Version就是乐观锁了?
后端·mysql·程序员
GoGeekBaird8 小时前
关于垂类AI应用落地行业的方法论思考
后端·github·agent
小宁爱Python8 小时前
Django 基础入门:命令、结构与核心配置全解析
后端·python·django
你的人类朋友9 小时前
认识一下Bcrypt哈希算法
后端·安全·程序员
tangweiguo030519879 小时前
基于 Django 与 Bootstrap 构建的现代化设备管理平台
后端·django·bootstrap
IT果果日记9 小时前
详解DataX开发达梦数据库插件
大数据·数据库·后端