2012-02-15 20:38:54.0|分类: swing|浏览量: 1635
如同所有其他在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。 |