java学习之浅谈多线程4--SwingWorker

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

#doInBackground():T                     //执行任务并返回T类型的结果
#done():void                            //结束doInBackground之后执行事件分发线程

+execute():void                         //安排这个SwingWorker来执行工作线程
+get():T                                //如果有必要则等待计算完成,然后获取它的结果(即doInBackground返回的结果)

+isDone():boolean                       //如果任务完成则返回true
+cancle():beelean                       //取消任务
#publish(data v...):void                //发送process方法要处理的数据。这个方法用于从doInBackground中传送之间结果,
                                        //以处理process方法中的事件分发线程。注意,v...表示变种参数

#process(data:java.util.List<V>):void   //异步地接受事件分发线程上来自publish方法的数据

#setProgress(progress:int):void         //设置进展约束属性。这个值应该从0到100
#getProgress():void                     //返回进展约束属性

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

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

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.List;

import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingWorker;

public class ProgressBarDemo extends JApplet {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    private JProgressBar jpb = new JProgressBar();                      //定义一个进度条显示进度
    private JTextArea jtaResult = new JTextArea();                      //定义一个文本域显示素数
    private JTextField jtfPrimeCount = new JTextField(8);               //定义一个文本框用于用户填写素数个数
    private JButton jbtnDisplayPrime = new JButton("Display Prime");    //定义一个按钮执行任务

    public ProgressBarDemo() {
        jpb.setStringPainted(true);     //设置显示进度的百分比
        jpb.setValue(0);
        jpb.setMaximum(100);

        //设置文本域自动换行,并且断行不断字
        jtaResult.setWrapStyleWord(true);
        jtaResult.setLineWrap(true);

        JPanel panel = new JPanel();
        panel.add(new JLabel("Enter the prime number count"));
        panel.add(jtfPrimeCount);
        panel.add(jbtnDisplayPrime);

        add(jpb, BorderLayout.NORTH);
        add(new JScrollPane(jtaResult), BorderLayout.CENTER);
        add(panel, BorderLayout.SOUTH);

        jbtnDisplayPrime.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                ComputePrime task = 
                        new ComputePrime(Integer.parseInt(jtfPrimeCount.getText()), jtaResult);

                task.addPropertyChangeListener(new PropertyChangeListener() {

                    @Override
                    public void propertyChange(PropertyChangeEvent evt) {
                        //判断改变的属性是否是进度,如果是则获取进度的值并显示在进度条上
                        if("progress".equals(evt.getPropertyName())) {
                            jpb.setValue((Integer)evt.getNewValue());
                        }
                    }
                });

                task.execute();     //执行
            }
        });
    }

    static class ComputePrime extends SwingWorker<Integer, Integer> {

        private int count;
        private JTextArea result;

        public ComputePrime(int count, JTextArea result) {
            this.count = count;
            this.result = result;
        }

        @Override
        protected Integer doInBackground() throws Exception {
            publishPrimeNumbers(count);
            return 0;
        }

        //把找到的素数全部显示出来
        @Override
        protected void process(List<Integer> list) {
            for(int i=0; i<list.size(); i++) {
                result.append(list.get(i) + " ");
            }
            super.process(list);
        }

        private void publishPrimeNumbers(int n) {
            int count = 0;
            int number = 2;

            while(count <= n) {
                if(isPrime(number)) {
                    count ++;
                    setProgress(100 * count / n);   //设置进度
                    publish(number);                //通过publish方法将找到的素数number发送给process方法
                }

                number ++;
            }
        }

        public static boolean isPrime(int number) {
            for(int divisor = 2; divisor <= number / 2; divisor++) {
                if(number % divisor == 0) {
                    return false;
                }
            }

            return true;
        }

    }

}

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

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

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值