2012-02-15 20:38:54.0|分类: swing|浏览量: 1827
如同所有其他在Java平台上运行的程序,一个Swing程序可以创建额外的线程和线程池,这需要使用本文即将介绍的方法。本文将介绍以上这三种线程。工作线程的讨论将涉及到使用javax.swing.SwingWorker类。这个类有许多有用的特性,包括在工作线程任务与其他线程任务之间的通信与协作。 SwingWorker worker = new SwingWorker< ImageIcon[], Void>() {
@Override
public ImageIcon[] doInBackground() {
final ImageIcon[] innerImgs = new ImageIcon[nimgs];
for (int i = 0; i < nimgs; i++) {
innerImgs[i] = loadImage(i+1);
}
return innerImgs;
}
@Override
public void done() {
//Remove the "Loading images" label.
animator.removeAll();
loopslot = -1;
try {
imgs = get();
} catch (InterruptedException ignore) {}
catch (java.util.concurrent.ExecutionException e) {
String why = null;
Throwable cause = e.getCause();
if (cause != null) {
why = cause.getMessage();
} else {
why = e.getMessage();
}
System.err.println("Error retrieving file: " + why);
}
}
};
所有的继承自SwingWorker的子类都必须实现doInBackground;实现done方法是可选的。
注意,SwingWorker是一个范型类,有两个参数。第一个类型参数指定doInBackground的返回类型。同时也是get方法的类型,它可以被其他线程调用以获得来自于doInBackground的返回值。第二个类型参数指定中间结果的类型,这个例子没有返回中间结果,所以设为void。 使用get方法,可以使对象imgs的引用(在工作线程中创建)在事件派发线程中得到使用。这样就可以在线程之间共享对象。 实际上有两个方法来得到doInBackground类返回的对象。 [1]调用SwingWorker.get没有参数。如果后台任务没有完成,get方法将阻塞直到它完成。 [2]调用SwingWorker.get带参数指定timeout。如果后台任务没有完成,阻塞直到它完成-除非timeout期满,在这种情况下,get将抛出java.util.concurrent.TimeoutException。 5.具有中间结果的任务 让一个正在工作的后台任务提供中间结果是很有用处的。后台任务可以调用SwingWorker.publish方法来做到这个。这个方法接受许多参数。每个参数必须是由SwingWorker的第二个类型参数指定的一种。 可以覆盖(override)SwingWorker.process来保存由publish方法提供的结果。这个方法是由事件派发线程调用的。来自publish方法的结果集通常是由一个process方法收集的。 我们看一下Filpper.java提供的实例。这个程序通过一个后台任务产生一系列的随机布尔值测试java.util.Random。就好比是一个投硬币试验。为了报告它的结果,后台任务使用了一个对象FlipPair。 private static class FlipPair {
private final long heads, total;
FlipPair(long heads, long total) {
this.heads = heads;
this.total = total;
}
}
heads表示true的结果;total表示总的投掷次数。
后台程序是一个FilpTask的实例:
private class FlipTask extends SwingWorker< Void, FlipPair> {
因为任务没有返回一个最终结果,这里不需要指定第一个类型参数是什么,使用Void。在每次“投掷”后任务调用publish:
@Override
protected Void doInBackground() {
long heads = 0;
long total = 0;
Random random = new Random();
while (!isCancelled()) {
total++;
if (random.nextBoolean()) {
heads++;
}
publish(new FlipPair(heads, total));
}
return null;
}
由于publish时常被调用,许多的FlipPair值将在process方法被事件派发线程调用之前被收集;
process仅仅关注每次返回的最后一组值,使用它来更新GUI:
protected void process(List pairs) {
FlipPair pair = pairs.get(pairs.size() - 1);
headsText.setText(String.format("%d", pair.heads));
totalText.setText(String.format("%d", pair.total));
devText.setText(String.format("%.10g",
((double) pair.heads)/((double) pair.total) - 0.5));
}
6.取消后台任务
调用SwingWorker.cancel来取消一个正在执行的后台任务。任务必须与它自己的撤销机制一致。有两个方法来做到这一点: [1]当收到一个interrupt时,将被终止。 [2]调用SwingWorker.isCanceled,如果SwingWorker调用cancel,该方法将返回true。 7.绑定属性和状态方法 SwingWorker支持bound properties,这个在与其他线程通信时很有作用。提供两个绑定属性:progress和state。progress和state可以用于触发在事件派发线程中的事件处理任务。 通过实现一个property change listener,程序可以捕捉到progress,state或其他绑定属性的变化。 7.1 The progress Bound Variable Progress绑定变量是一个整型变量,变化范围由0到100。它预定义了setter (the protected SwingWorker.setProgress)和getter (the public SwingWorker.getProgress)方法。 7.2 The state Bound Variable State绑定变量的变化反映了SwingWorker对象在它的生命周期中的变化过程。该变量中包含一个SwingWorker.StateValue的枚举类型。可能的值有: [1]PENDING 这个状态持续的时间为从对象的建立直到doInBackground方法被调用。 [2]STARTED 这个状态持续的时间为doInBackground方法被调用前一刻直到done方法被调用前一刻。 [3]DONE 对象存在的剩余时间将保持这个状态。 需要返回当前state的值可调用SwingWorker.getState。 7.3 Status Methods 两个由Future接口提供的方法,同样可以报告后台任务的状态。如果任务被取消,isCancelled返回true。此外,如果任务完成,即要么正常的完成,要么被取消,isDone返回true。 |
