zoukankan      html  css  js  c++  java
  • java学习之浅谈多线程4SwingWorker

    GUI事件处理和绘图代码在一个被称为事件分发线程的特殊线程中执行。如果一个事件需要很长的时间处理,线程就不能顾及到队列中的其他任务。为了解决这个问题,可以运行费时的任务来处理单独线程中的事件。SwingWorker是一个实现Runnable的抽象类,可以定义一个任务来扩展SwingWorker,使用任务产生的结果来运行费时的任务并更新GUI。

     1 #doInBackground():T                     //执行任务并返回T类型的结果
     2 #done():void                            //结束doInBackground之后执行事件分发线程
     3 
     4 +execute():void                         //安排这个SwingWorker来执行工作线程
     5 +get():T                                //如果有必要则等待计算完成,然后获取它的结果(即doInBackground返回的结果)
     6 
     7 +isDone():boolean                       //如果任务完成则返回true
     8 +cancle():beelean                       //取消任务
     9 #publish(data v...):void                //发送process方法要处理的数据。这个方法用于从doInBackground中传送之间结果,
    10                                         //以处理process方法中的事件分发线程。注意,v...表示变种参数
    11 
    12 #process(data:java.util.List<V>):void   //异步地接受事件分发线程上来自publish方法的数据
    13 
    14 #setProgress(progress:int):void         //设置进展约束属性。这个值应该从0到100
    15 #getProgress():void                     //返回进展约束属性

    SwingWorker有两个参数即SwingWorker< T,V>,T是doInBackground和get方法的返回类型;V是publish和process方法要处理的数据类型

    完成后台线程的计算可能需要很长的时间,最好能通知用户计算的进度,可以使用JProgressBar来显示进度。考虑例子:让用户指定素数的个数n,并显示从2开始的前n个素数。代码如下:

      1 import java.awt.BorderLayout;
      2 import java.awt.event.ActionEvent;
      3 import java.awt.event.ActionListener;
      4 import java.beans.PropertyChangeEvent;
      5 import java.beans.PropertyChangeListener;
      6 import java.util.List;
      7 
      8 import javax.swing.JApplet;
      9 import javax.swing.JButton;
     10 import javax.swing.JLabel;
     11 import javax.swing.JPanel;
     12 import javax.swing.JProgressBar;
     13 import javax.swing.JScrollPane;
     14 import javax.swing.JTextArea;
     15 import javax.swing.JTextField;
     16 import javax.swing.SwingWorker;
     17 
     18 public class ProgressBarDemo extends JApplet {
     19 
     20     /**
     21      * 
     22      */
     23     private static final long serialVersionUID = 1L;
     24 
     25     private JProgressBar jpb = new JProgressBar();                      //定义一个进度条显示进度
     26     private JTextArea jtaResult = new JTextArea();                      //定义一个文本域显示素数
     27     private JTextField jtfPrimeCount = new JTextField(8);               //定义一个文本框用于用户填写素数个数
     28     private JButton jbtnDisplayPrime = new JButton("Display Prime");    //定义一个按钮执行任务
     29 
     30     public ProgressBarDemo() {
     31         jpb.setStringPainted(true);     //设置显示进度的百分比
     32         jpb.setValue(0);
     33         jpb.setMaximum(100);
     34 
     35         //设置文本域自动换行,并且断行不断字
     36         jtaResult.setWrapStyleWord(true);
     37         jtaResult.setLineWrap(true);
     38 
     39         JPanel panel = new JPanel();
     40         panel.add(new JLabel("Enter the prime number count"));
     41         panel.add(jtfPrimeCount);
     42         panel.add(jbtnDisplayPrime);
     43 
     44         add(jpb, BorderLayout.NORTH);
     45         add(new JScrollPane(jtaResult), BorderLayout.CENTER);
     46         add(panel, BorderLayout.SOUTH);
     47 
     48         jbtnDisplayPrime.addActionListener(new ActionListener() {
     49 
     50             @Override
     51             public void actionPerformed(ActionEvent e) {
     52                 ComputePrime task = 
     53                         new ComputePrime(Integer.parseInt(jtfPrimeCount.getText()), jtaResult);
     54 
     55                 task.addPropertyChangeListener(new PropertyChangeListener() {
     56 
     57                     @Override
     58                     public void propertyChange(PropertyChangeEvent evt) {
     59                         //判断改变的属性是否是进度,如果是则获取进度的值并显示在进度条上
     60                         if("progress".equals(evt.getPropertyName())) {
     61                             jpb.setValue((Integer)evt.getNewValue());
     62                         }
     63                     }
     64                 });
     65 
     66                 task.execute();     //执行
     67             }
     68         });
     69     }
     70 
     71     static class ComputePrime extends SwingWorker<Integer, Integer> {
     72 
     73         private int count;
     74         private JTextArea result;
     75 
     76         public ComputePrime(int count, JTextArea result) {
     77             this.count = count;
     78             this.result = result;
     79         }
     80 
     81         @Override
     82         protected Integer doInBackground() throws Exception {
     83             publishPrimeNumbers(count);
     84             return 0;
     85         }
     86 
     87         //把找到的素数全部显示出来
     88         @Override
     89         protected void process(List<Integer> list) {
     90             for(int i=0; i<list.size(); i++) {
     91                 result.append(list.get(i) + " ");
     92             }
     93             super.process(list);
     94         }
     95 
     96         private void publishPrimeNumbers(int n) {
     97             int count = 0;
     98             int number = 2;
     99 
    100             while(count <= n) {
    101                 if(isPrime(number)) {
    102                     count ++;
    103                     setProgress(100 * count / n);   //设置进度
    104                     publish(number);                //通过publish方法将找到的素数number发送给process方法
    105                 }
    106 
    107                 number ++;
    108             }
    109         }
    110 
    111         public static boolean isPrime(int number) {
    112             for(int divisor = 2; divisor <= number / 2; divisor++) {
    113                 if(number % divisor == 0) {
    114                     return false;
    115                 }
    116             }
    117 
    118             return true;
    119         }
    120 
    121     }
    122 
    123 }

    :doInBackground方法作为任务线程的一部分执行,它负责完成线程的基本任务,并以返回值来作为线程的执行结果。继承类须覆盖该方法并确保包含或代理任务线程的基本任务。不要直接调用该方法,应使用任务对象的execute方法来调度执行。

    当从任务线程调用publish方法时,SwingWorker类调度process方法,如果SwingWorker通过publish发布了一些数据,那么也应该实现process方法来处理这些中间结果,任务对象的父类会在事件分发线程上激活process方法,因此在此方法中程序可以安全的更新UI组件。

    无论何时调用setProgress方法,SwingWorker类都会产生一个propertyChangeEvent。setProgress方法设置一个0到100之间的新的进度值,这个值包装在PropertyChangeEvent中,这个事件的监听器使用getNewValue()方法获取进度值。

    程序执行结果如下:
    糟糕,图片不见了>.<

    Do not be evil
  • 相关阅读:
    启动程序相关的命令
    分享的几行代码
    各种大数据软件安装
    tomcat报没法分配内存大小解决方案
    数据库事务
    pytorch之CNN实现
    搜索与匹配
    调试 pytorch 及 python 的 特殊语法
    图神经网络 GCN 等综述(转载)
    关于【finder不能完成该操作 因为未能读取或写入"文件名"中的某些数据(错误代码-36)】(实测,好用)
  • 原文地址:https://www.cnblogs.com/nangch/p/5353568.html
Copyright © 2011-2022 走看看