zoukankan      html  css  js  c++  java
  • 使用泛型SwingWorker与EDT事件分发线程保持通讯

    为什么要使用SwingWorker

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

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

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

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

    SwingWorker

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

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

    public class MyBlankWorker extends SwingWorker<Integer, String> {
    
      @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<Integer, String> {
    
      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<File> 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<String> chunks) {
        // Updates the messages text area
        for (final String string : chunks) {
          messagesTextArea.append(string);
          messagesTextArea.append("
    ");
        }
      }
    }

    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()
            + "
    ");
        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/

  • 相关阅读:
    UV动画
    使用RampTexture实现BRDF效果
    使用RampTexture来控制diffuse shading
    Half Lambert
    Lamber算法 & SurfaceShader自定义光照
    What is _MainTex_ST ?
    C# Enum,Int,String的互相转换
    Plugins in Unity
    Mono在Full AOT模式下的限制
    雾化
  • 原文地址:https://www.cnblogs.com/starcrm/p/4968853.html
Copyright © 2011-2022 走看看