当前位置: 首页 > 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.lryc.cn/news/572546.html

相关文章:

  • Tensorflow推理时遇见PTX错误,安装CUDA及CuDNN, 解决问题!
  • 编辑器及脚本案例
  • 【Redis】主从复制
  • Transformer结构介绍
  • 【K8S】详解Labels​​ 和 ​​Annotations
  • 记录存储的使用
  • 计量经济学(复习/自用/未完)
  • AIGC - Prompt Optimizer 提示词优化器
  • uni-app项目实战笔记16--实现头部导航栏效果
  • 【数字人开发】Unity+百度智能云平台实现短语音文本识别功能
  • OpenAI 公布《走向理解与预防失准泛化:由“角色特征”驱动的突现性失准》研究总结
  • 用“Gemini 2.0 Flash Preview Image Generation”模型修改图片,有哪些常用的提示词和方法
  • Spring MVC参数绑定终极手册:单多参对象集合JSON文件上传精讲
  • MCAL学习(6)——诊断、DCM
  • 股票心理学习篇:交易的人性弱点 - 频繁交易
  • 基于Python的机动车辆推荐及预测分析系统
  • 计算机网络零基础完全指南
  • ROS2 笔记汇总(3) 动作
  • Linux树莓派项目实战:外网访问、PWM呼吸灯、超声波测距与驱动开发
  • 《思维力:高效的系统思维》
  • 【开源模型】高考数学139分!小米MiMo开源模型:7B参数突出重围
  • MySQL 的 WITH ROLLUP 功能
  • MySQL: Invalid use of group function
  • swing综合案例.
  • Github 热点项目 [特殊字符]PHP性能革命!FrankenPHP让Laravel/Symfony飞起来!
  • (哈希)128. 最长连续序列
  • 5G核心网周期性注册更新机制:信令流程与字段解析
  • Python 数据分析与可视化 Day 1 - Pandas 数据分析基础入门
  • 算法导论第十九章 并行算法:解锁计算新维度
  • 防火墙的禁用及开启