当前位置: 首页 > news >正文

12.10 在主线程或子线程中更新 UI

Swing 是单线程工具包,所有对 UI 的操作都应发生在**事件调度线程(Event Dispatch Thread, EDT)**中。


 invokeLater

 正确更新控件内容的方法

1. 直接更新(适用于已在 EDT 中)

如果你确定当前代码是在 EDT 中运行的(例如在按钮点击事件或 paint() 方法中),可以直接更新控件:

label.setText("新的文本");
textField.setText("新输入内容");
button.setEnabled(false);

2. 如果不在 EDT 中(如在主线程或子线程中更新 UI)

必须使用 SwingUtilities.invokeLater()SwingUtilities.invokeAndWait() 来确保 UI 更新在 EDT 中执行:

SwingUtilities.invokeLater(() -> {label.setText("更新后的文本");textField.setText("更新输入框内容");
});
  • invokeLater():异步执行,不会阻塞当前线程。
  • invokeAndWait():同步执行,会阻塞当前线程直到 UI 操作完成(常用于初始化阶段)。

 示例

import javax.swing.*;
import java.awt.*;
import java.util.Timer;
import java.util.TimerTask;public class UpdateLabelExample {public static void main(String[] args) {JFrame frame = new JFrame("Swing 更新示例");JLabel label = new JLabel("初始文本", SwingConstants.CENTER);frame.add(label, BorderLayout.CENTER);frame.setSize(300, 200);frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);frame.setVisible(true);Timer timer = new Timer();timer.schedule(new TimerTask() {int count = 0;@Overridepublic void run() {String newText = "更新次数: " + (++count);SwingUtilities.invokeLater(() -> {label.setText(newText);});}}, 0, 1000); // 每秒更新一次}
}

 动态刷新其他组件示例

控件类型设置内容方法
JLabelsetText("新文本")
JTextFieldsetText("新内容")
JButtonsetText("按钮文字")
JComboBoxsetSelectedItem("选项")
JTextAreasetText("新段落")
JList需要更新 ListModel

注意事项

  • 不要在非 EDT 线程中直接修改 UI 组件!否则可能导致界面显示异常甚至崩溃。
  • 使用多线程时,务必配合 SwingWorker 或 invokeLater()
  • 对于复杂界面更新,考虑使用 SwingWorker 来后台处理数据并在完成后更新 UI。

 SwingWorker 

SwingWorker 是 Java Swing 中用于处理后台任务的一个类,旨在解决在执行长时间运行的任务时保持用户界面响应的问题。它使得开发者能够将耗时的操作从事件调度线程(Event Dispatch Thread, EDT)中移出,并提供了一种机制来更新UI而不会导致界面冻结。

基本概念

  • EDT(Event Dispatch Thread):所有Swing组件的绘制和事件处理都必须在EDT中进行。如果你尝试在非EDT线程中修改UI组件,可能会导致不一致的行为或异常。
  • SwingWorker:允许你在一个单独的工作线程中执行后台任务,同时提供了安全地更新GUI的方法。

主要方法

  1. doInBackground():这是你需要覆盖的方法,在这个方法里执行你的后台任务。此方法自动在工作线程中运行,不会阻塞EDT。
  2. process():当需要更新UI时可以调用publish()方法,这将触发process()方法在EDT上执行。process()接收一个参数列表,这些是通过publish()发送的数据片段。
  3. done():当doInBackground()完成时,会自动调用此方法,它在EDT上执行,因此可以安全地在此方法中更新UI以反映后台任务的结果。
  4. get():返回doInBackground()方法的执行结果,如果必要的话,它会等待直到doInBackground()执行完毕。通常在done()方法中使用,以获取后台任务的结果。

使用步骤

  1. 创建一个继承自SwingWorker的类。
  2. 覆盖doInBackground()方法,用于执行后台操作。
  3. 如果需要在后台任务执行期间更新UI,可以在适当的时候调用publish()方法,并实现process()方法来处理更新逻辑。
  4. 在后台任务完成后,可选择覆盖done()方法来进行最后的UI更新。

示例代码

以下是一个简单的例子,展示了如何使用SwingWorker来执行一个耗时任务并更新进度条:

import javax.swing.*;
import java.util.List;public class MySwingWorkerExample extends SwingWorker<Void, Integer> {private JProgressBar progressBar;public MySwingWorkerExample(JProgressBar progressBar) {this.progressBar = progressBar;}@Overrideprotected Void doInBackground() throws Exception {int progress = 0;while (progress < 100) {Thread.sleep(100); // 模拟耗时操作progress += 5;setProgress(progress);publish(progress);}return null;}@Overrideprotected void process(List<Integer> chunks) {for (int progress : chunks) {progressBar.setValue(progress);}}@Overrideprotected void done() {JOptionPane.showMessageDialog(null, "任务完成!");}public static void main(String[] args) {JFrame frame = new JFrame("SwingWorker 示例");JProgressBar progressBar = new JProgressBar(0, 100);frame.add(progressBar);frame.setSize(300, 100);frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);frame.setVisible(true);MySwingWorkerExample worker = new MySwingWorkerExample(progressBar);worker.execute();}
}

在这个例子中,我们创建了一个继承自SwingWorker的类,并重写了doInBackground()process()done()方法。doInBackground()模拟了一个耗时过程,每100毫秒更新一次进度,然后通过publish()process()方法更新进度条的值。当任务完成后,done()方法会显示一个消息框通知用户任务已完成。

http://www.lqws.cn/news/447769.html

相关文章:

  • 退出python解释器的四种方式
  • C#语言入门-task2 :C# 语言的基本语法结构
  • vue3 defineExpose的使用
  • 不同系统修改 Docker Desktop 存储路径(从C盘修改到D盘)
  • 解锁微服务潜能:深入浅出 Nacos
  • 蜻蜓Q系统的技术演进:从Laravel 6到Laravel 8的升级之路-优雅草卓伊凡
  • C# winform教程(二)----GroupBox
  • ROS学习之服务通信
  • 【AI编程】第3期,针对AI生成的改枪码列表创建对应的数据库表
  • AWS CloudFormation深度解析:构建现代云原生应用基础设施
  • SpringBoot扩展——发送邮件!
  • Spring MVC参数绑定终极手册:单多参对象集合JSON文件上传精讲
  • 网络编程及原理(五)
  • Kotlin 2.6 猜数小游戏
  • AI免费工具:promptpilot、今天学点啥、中英文翻译
  • WSL 安装使用和常用命令
  • 设计模式精讲 Day 7:桥接模式(Bridge Pattern)
  • OpenAI 公布《走向理解与预防失准泛化:由“角色特征”驱动的突现性失准》研究总结
  • 用“Gemini 2.0 Flash Preview Image Generation”模型修改图片,有哪些常用的提示词和方法
  • uni-app项目实战笔记16--实现头部导航栏效果
  • C++ inline变量
  • 记录存储的使用
  • MySQL 的 WITH ROLLUP 功能
  • LLM大模型应用监控---LangChain接入LangFuse进阶篇
  • Java Map 深度解析
  • 垃圾收集器
  • 【Wi-Fi天气时钟】前置知识合集
  • 硬件-DAY04(ds18b20、ARM内核)
  • 《二叉搜索树》
  • 【数字人开发】Unity+百度智能云平台实现短语音文本识别功能