参考文章:swingworker_使用SwingWorker的Java Swing中的多线程
简介:
SwingWorker是一个专门为界面而实现的线程类,
它可以非常方便的在当前的UI线程中新建异步线程执行一定的耗时操作,且可以很安全的将它的返回值发送给UI线程。
SwingWorkerTaskMgt.java
package org.fiend.swing.test.demo.swingworker.test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.swing.*;
import java.awt.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.concurrent.ExecutionException;
/**
* @author pelang 2021-09-22 14:50:16
*/
public class SwingWorkerTaskMgt {
private static final Logger logger = LoggerFactory.getLogger(SwingWorkerTaskMgt.class);
private static JFrame frame;
private static JTextArea textArea;
private static JProgressBar progressBar;
public static void main(String[] args) throws ExecutionException, InterruptedException {
initUI();
SwingWorkerDemo task = new SwingWorkerDemo(textArea);
task.addPropertyChangeListener(
new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
if ("progress".equals(evt.getPropertyName())) {
progressBar.setValue((Integer) evt.getNewValue());
}
}
}
);
/*
* 判断立即执行任务是否启动swingWorker
* SwingWorker的状态只有三种: PENDING, STARTED, DONE
* PENDING: 刚刚初始化, 尚未运行
* STARTED: 正在运行中
* DONE: 运行结束, 包括正常运行结束, 异常运行结束, 强制终止结束
*/
String msg;
SwingWorker.StateValue state = task.getState();
logger.info("SwingWorker state: " + state);
if (state == SwingWorker.StateValue.STARTED) {
msg = "The task is running!";
logger.info(msg);
return;
}
if (state == SwingWorker.StateValue.DONE) {
task = new SwingWorkerDemo(textArea);
}
// 任务开始执行
task.execute();
System.out.println(task.get()); // prints all numbers we have got
}
private static void initUI() {
frame = new JFrame("SwingWorker Test");
frame.setSize(400, 300);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel jp = new JPanel(null);
jp.setBackground(Color.WHITE);
textArea = new JTextArea();
textArea.setEditable(false);
JScrollPane scrollPane = new JScrollPane(
textArea,
ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER
);
scrollPane.setBounds(10, 50, 360, 200);
progressBar = new JProgressBar(0, 100);
progressBar.setBounds(10, 0, 360, 20);
jp.add(scrollPane);
jp.add(progressBar);
frame.add(jp);
frame.setVisible(true);
}
}
SwingWorkerDemo.java
package org.fiend.swing.test.demo.swingworker.test;
import javax.swing.*;
import java.util.List;
/**
* 类 SwingWorker<T,V>
* 类型参数:
* * T - 此 SwingWorker 的 doInBackground 和 get 方法返回的结果类型
* * V - 用于保存此 SwingWorker 的 publish 和 process 方法的中间结果的类型
* *
* * SwingWorker是一个专门为界面而实现的线程类,
* * 它可以非常方便的在当前的UI线程中执行一定的耗时操作,且可以很安全
* * 的将它的返回值发送给UI线程
* *
* * 创建SwingWorker时,需要指定两个泛型:
* * 第一个泛型是SwingWorker线程执行之后得到的结果的类型(返回值的类型)
* * 第二个泛型是SwingWorker线程执行中间所发布(publish)的数据的类型
* *
* * 这里将整个SwingWorker的返回值定义为StringBuilder,中间发布的数据定义为String
* *
* * 覆盖三个方法:doInBackground()、process()、done()
* *
* * doInBackground()
* * 返回计算结果;如果无法生成计算结果,则抛出异常。
* * 注意,此方法只执行一次。
* * 注:此方法在后台线程中执行。
* <p>
* 执行耗时的操作,如:读取网络数据、读取本地文件、等待
* * 产生的中间数据 publish() 到 process() 中
* * 返回值在 done() 中被 get() 到
* * 即两种方法都能获取最终的结果
* * 最后调用SwingWorker的 execute() 方法执行该线程
* *
* * done()
* * doInBackground 方法完成后,在事件指派线程 上执行此方法。
* *
* * process(List<V> chunks)
* * 在事件指派线程上异步地从 publish 方法接收数据块。
* *
* * publish(V... chunks)
* * 将数据块发送给 process(java.util.List) 方法。
* *
* @author pelang 2021-09-09 16:47:59
*/
public class SwingWorkerDemo extends SwingWorker<String, Integer> {
private static final int numbersToFind = 30;
private static Boolean enough = false;
private final JTextArea textArea;
public SwingWorkerDemo(JTextArea textArea) {
this.textArea = textArea;
}
/**
* 此方法执行耗时操作。
* 此方法只执行一次。
*
* 返回计算结果;如果无法生成计算结果,则抛出异常。
* * * 注意,此方法只执行一次。
* * * 注:此方法在后台线程中执行。
* * <p>
* * 执行耗时的操作,如:读取网络数据、读取本地文件、等待
* * * 产生的中间数据 publish() 到 process() 中
* * * 返回值在 done() 中被 get() 到
* * * 即两种方法都能获取最终的结果
* * * 最后调用SwingWorker的 execute() 方法执行该线程
* @return
*/
@Override
public String doInBackground() {
int number = 0;
while (!enough && !isCancelled()) {
number++;
publish(number);
try {
Thread.sleep(600);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 设置"progress"属性
setProgress(number);
}
System.out.println("enough: -----> " + enough);
return String.valueOf(number);
}
@Override
protected void process(List<Integer> list) {
for (Integer i : list) {
textArea.append(i + "\n");
if (numbersToFind == i) {
enough = true;
}
}
}
}