博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
使用泛型SwingWorker与EDT事件分发线程保持通讯
阅读量:4135 次
发布时间:2019-05-25

本文共 11455 字,大约阅读时间需要 38 分钟。

为什么要使用SwingWorker

在swing开发中,如果一个应用程序,执行一些任务,需要大量的时间来完成,比如下载一个大文件或执行一个复杂的数据库查询。

我们假设这些任务是由用户使用一个按钮触发的。在单线程应用程序,用户单击按钮,进入计算的过程,然后等待任务完成之前,所有的事件都在主线程EDT线程进行。

但如果某些任务耗时很长,用户将甚至不能在中途取消任务,应用程序必须响应只有当长任务完成。不幸的是,许多应用程序显着这样的行为和用户感到沮丧,程序仿佛卡死一样。

多线程可以解决这个问题。它使应用程序能够在不同的线程上执行长任务,但多线程带来一个问题,如果需要实时和主线程EDT进行数据交换,该怎么办?我们知道所有的Swing对象都只有一个线程处理,EDT事件调度线程,这导致一个问题:我们不能在EDT事件分派线程以外的其他线程共享对象的对象。

 

SwingWorker

SwingWorker是一个抽象类,java将它包装好,供方便调用,下面的例子使用字符串对象来通知应用程序。

提供了两个泛型参数。第一个代表返回的对象类型。另一个代表了通知(更新)应用程序的信息的类型,并在下面的例子中高亮显示。

public class MyBlankWorker extends SwingWorker
{ @Override protected Integer doInBackground() throws Exception { // Start publish("Start"); setProgress(1); // More work was done publish("More work was done"); setProgress(10); // Complete publish("Complete"); setProgress(100); return 1; } @Override protected void process(List< String> chunks) { // Messages received from the doInBackground() (when invoking the publish() method) }}

通过setprogress() 设置0和100之间的整数。doinbackground() 用于漫长任务执行。此方法不是由事件调度线程调用的,而是由另一个线程(称为工作线程)。我们可以用publish()方法和/或setprogress()更新进度。调用两个方法都会对事件调度线程的创建新任务,它是工作线程和事件调度线程的线程之间的单向桥。

doinbackground()中调用publish()方法和/或setprogress()必须防止大量的任务发送给事件调度线程,引发洪水事件

注意:publish()从工作线程调用,而process()由事件调度线程EDT调用

举例:

输入:

publish("a"); publish("b", "c"); publish("d", "e", "f");

结果就是:

process("a", "b", "c", "d", "e", "f") 最后是一个文件全文检索的异步查询例子,查询某目录下所有的txt文件
import java.io.File;import java.util.ArrayList;import java.util.List;import javax.swing.JTextArea;import javax.swing.SwingWorker;import org.apache.commons.io.FileUtils;import org.apache.commons.io.filefilter.SuffixFileFilter;import org.apache.commons.io.filefilter.TrueFileFilter;import org.apache.commons.lang.StringUtils;/** * Searches the text files under the given directory and counts the number of instances a given word is found in these * file. *  * @author Albert Attard */public class SearchForWordWorker extends SwingWorker
{ private static void failIfInterrupted() throws InterruptedException { if (Thread.currentThread().isInterrupted()) { throw new InterruptedException("Interrupted while searching files"); } } /** The word that is searched */ private final String word; /** The directory under which the search occurs. All text files found under the given directory are searched. */ private final File directory; /** The text area where messages are written. */ private final JTextArea messagesTextArea; /** * Creates an instance of the worker * * @param word * The word to search * @param directory * the directory under which the search will occur. All text files found under the given directory are * searched * @param messagesTextArea * The text area where messages are written */ public SearchForWordWorker(final String word, final File directory, final JTextArea messagesTextArea) { this.word = word; this.directory = directory; this.messagesTextArea = messagesTextArea; } @Override protected Integer doInBackground() throws Exception { // The number of instances the word is found int matches = 0; /* * List all text files under the given directory using the Apache IO library. This process cannot be interrupted * (stopped through cancellation). That is why we are checking right after the process whether it was interrupted or * not. */ publish("Listing all text files under the directory: " + directory); final List
textFiles = new ArrayList<>(FileUtils.listFiles(directory, new SuffixFileFilter(".txt"), TrueFileFilter.TRUE)); SearchForWordWorker.failIfInterrupted(); publish("Found " + textFiles.size() + " text files under the directory: " + directory); for (int i = 0, size = textFiles.size(); i < size; i++) { /* * In order to respond to the cancellations, we need to check whether this thread (the worker thread) was * interrupted or not. If the thread was interrupted, then we simply throw an InterruptedException to indicate * that the worker thread was cancelled. */ SearchForWordWorker.failIfInterrupted(); // Update the status and indicate which file is being searched. final File file = textFiles.get(i); publish("Searching file: " + file); /* * Read the file content into a string, and count the matches using the Apache common IO and Lang libraries * respectively. */ final String text = FileUtils.readFileToString(file); matches += StringUtils.countMatches(text, word); Thread.sleep(20); // Update the progress setProgress((i + 1) * 100 / size); } // Return the number of matches found return matches; } @Override protected void process(final List
chunks) { // Updates the messages text area for (final String string : chunks) { messagesTextArea.append(string); messagesTextArea.append("\n"); } }}

JFrame UI类如下

package com.javacreed.examples.swing.worker.part3;import java.awt.GridBagConstraints;import java.awt.GridBagLayout;import java.awt.Insets;import java.awt.event.ActionEvent;import java.beans.PropertyChangeEvent;import java.beans.PropertyChangeListener;import java.io.File;import javax.swing.AbstractAction;import javax.swing.Action;import javax.swing.JButton;import javax.swing.JFileChooser;import javax.swing.JFrame;import javax.swing.JLabel;import javax.swing.JProgressBar;import javax.swing.JScrollPane;import javax.swing.JTextArea;import javax.swing.JTextField;import javax.swing.SwingWorker.StateValue;public class Application extends JFrame {  /**  */  private static final long serialVersionUID = -8668818312732181049L;  private Action searchCancelAction;  private Action browseAction;  private JTextField wordTextField;  private JTextField directoryPathTextField;  private JTextArea messagesTextArea;  private JProgressBar searchProgressBar;  private SearchForWordWorker searchWorker;  public Application() {    initActions();    initComponents();  }  private void cancel() {    searchWorker.cancel(true);  }  private void initActions() {    browseAction = new AbstractAction("Browse") {      private static final long serialVersionUID = 4669650683189592364L;      @Override      public void actionPerformed(final ActionEvent e) {        final File dir = new File(directoryPathTextField.getText()).getAbsoluteFile();        final JFileChooser fileChooser = new JFileChooser(dir.getParentFile());        fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);        final int option = fileChooser.showOpenDialog(Application.this);        if (option == JFileChooser.APPROVE_OPTION) {          final File selected = fileChooser.getSelectedFile();          directoryPathTextField.setText(selected.getAbsolutePath());        }      }    };    searchCancelAction = new AbstractAction("Search") {      private static final long serialVersionUID = 4669650683189592364L;      @Override      public void actionPerformed(final ActionEvent e) {        if (searchWorker == null) {          search();        } else {          cancel();        }      }    };  }  private void initComponents() {    setLayout(new GridBagLayout());    GridBagConstraints constraints = new GridBagConstraints();    constraints.gridx = 0;    constraints.gridy = 0;    constraints.insets = new Insets(2, 2, 2, 2);    add(new JLabel("Word: "), constraints);    wordTextField = new JTextField();    wordTextField.setText("Hello");    constraints = new GridBagConstraints();    constraints.gridx = 1;    constraints.gridy = 0;    constraints.gridwidth = 2;    constraints.insets = new Insets(2, 2, 2, 2);    constraints.weightx = 1;    constraints.fill = GridBagConstraints.BOTH;    add(wordTextField, constraints);    constraints = new GridBagConstraints();    constraints.gridx = 0;    constraints.gridy = 1;    constraints.insets = new Insets(2, 2, 2, 2);    add(new JLabel("Path: "), constraints);    directoryPathTextField = new JTextField();    directoryPathTextField.setText("C:\\Users\\Albert\\Work\\JavaCreed\\examples");    constraints = new GridBagConstraints();    constraints.gridx = 1;    constraints.gridy = 1;    constraints.gridwidth = 1;    constraints.insets = new Insets(2, 2, 2, 2);    constraints.weightx = 1;    constraints.fill = GridBagConstraints.BOTH;    add(directoryPathTextField, constraints);    constraints = new GridBagConstraints();    constraints.gridx = 2;    constraints.gridy = 1;    constraints.insets = new Insets(2, 2, 2, 2);    add(new JButton(browseAction), constraints);    messagesTextArea = new JTextArea();    messagesTextArea.setEditable(false);    constraints = new GridBagConstraints();    constraints.gridx = 0;    constraints.gridy = 2;    constraints.gridwidth = 3;    constraints.insets = new Insets(2, 2, 2, 2);    constraints.weightx = 1;    constraints.weighty = 1;    constraints.fill = GridBagConstraints.BOTH;    add(new JScrollPane(messagesTextArea), constraints);    searchProgressBar = new JProgressBar();    searchProgressBar.setStringPainted(true);    searchProgressBar.setVisible(false);    constraints = new GridBagConstraints();    constraints.gridx = 0;    constraints.gridy = 3;    constraints.gridwidth = 2;    constraints.insets = new Insets(2, 2, 2, 2);    constraints.weightx = 1;    constraints.fill = GridBagConstraints.BOTH;    add(searchProgressBar, constraints);    constraints = new GridBagConstraints();    constraints.gridx = 2;    constraints.gridy = 3;    constraints.insets = new Insets(2, 2, 2, 2);    constraints.weightx = 0;    add(new JButton(searchCancelAction), constraints);  }  private void search() {    final String word = wordTextField.getText();    final File directory = new File(directoryPathTextField.getText());    messagesTextArea.setText("Searching for word '" + word + "' in text files under: " + directory.getAbsolutePath()        + "\n");    searchWorker = new SearchForWordWorker(word, directory, messagesTextArea);    searchWorker.addPropertyChangeListener(new PropertyChangeListener() {      @Override      public void propertyChange(final PropertyChangeEvent event) {        switch (event.getPropertyName()) {        case "progress":          searchProgressBar.setIndeterminate(false);          searchProgressBar.setValue((Integer) event.getNewValue());          break;        case "state":          switch ((StateValue) event.getNewValue()) {          case DONE:            searchProgressBar.setVisible(false);            searchCancelAction.putValue(Action.NAME, "Search");            searchWorker = null;            break;          case STARTED:          case PENDING:            searchCancelAction.putValue(Action.NAME, "Cancel");            searchProgressBar.setVisible(true);            searchProgressBar.setIndeterminate(true);            break;          }          break;        }      }    });    searchWorker.execute();  }}
View Code

入口:

 

import javax.swing.JFrame;import javax.swing.SwingUtilities;public class Main {  public static void main(final String[] args) {    SwingUtilities.invokeLater(new Runnable() {      @Override      public void run() {        final Application frame = new Application();        frame.setTitle("Swing Worker Demo");        frame.setSize(600, 400);        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);        frame.setVisible(true);      }    });  }}

 

引用:http://www.javacreed.com/swing-worker-example/

 

转载地址:http://wxpvi.baihongyu.com/

你可能感兴趣的文章
浅谈HTML
查看>>
css基础
查看>>
Servlet进阶和JSP基础
查看>>
servlet中的cookie和session
查看>>
过滤器及JSP九大隐式对象
查看>>
软件(项目)的分层
查看>>
菜单树
查看>>
Servlet的生命周期
查看>>
JAVA八大经典书籍,你看过几本?
查看>>
《读书笔记》—–书单推荐
查看>>
JAVA数据类型
查看>>
【Python】学习笔记——-6.2、使用第三方模块
查看>>
【Python】学习笔记——-7.0、面向对象编程
查看>>
【Python】学习笔记——-7.2、访问限制
查看>>
【Python】学习笔记——-7.3、继承和多态
查看>>
【Python】学习笔记——-7.5、实例属性和类属性
查看>>
git中文安装教程
查看>>
虚拟机 CentOS7/RedHat7/OracleLinux7 配置静态IP地址 Ping 物理机和互联网
查看>>
Jackson Tree Model Example
查看>>
常用js收集
查看>>