|
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()方法获取进度值。
程序猿的技术大观园:www.javathinker.net
|
网站系统异常
系统异常信息 |
Request URL:
http://www.javathinker.net/WEB-INF/lybbs/jsp/topic.jsp?postID=932&replyID=0&skin=1&saveSkin=true&pages=1&replyNum=
java.lang.NullPointerException
如果你不知道错误发生的原因,请把上面完整的信息提交给本站管理人员。
|
|