Java 如何委派SwingWorker';s发布到其他方法

Java 如何委派SwingWorker';s发布到其他方法,java,swingworker,Java,Swingworker,我的“问题”可以用以下描述。假设我们有一个需要在后台运行的密集进程,并让它更新Swing JProgress条。解决方案很简单: import java.util.List; import javax.swing.JOptionPane; import javax.swing.JProgressBar; import javax.swing.SwingWorker; /** * @author Savvas Dalkitsis */ public class Test { p

我的“问题”可以用以下描述。假设我们有一个需要在后台运行的密集进程,并让它更新Swing JProgress条。解决方案很简单:

import java.util.List;

import javax.swing.JOptionPane;
import javax.swing.JProgressBar;
import javax.swing.SwingWorker;


/**
 * @author Savvas Dalkitsis
 */
public class Test {

    public static void main(String[] args) {
        final JProgressBar progressBar = new JProgressBar(0,99);
        SwingWorker<Void, Integer> w = new SwingWorker<Void, Integer>(){

            @Override
            protected void process(List<Integer> chunks) {
                progressBar.setValue(chunks.get(chunks.size()-1));
            }

            @Override
            protected Void doInBackground() throws Exception {

                for (int i=0;i<100;i++) {
                    publish(i);
                    Thread.sleep(300);
                }

                return null;
            }

        };
        w.execute();
        JOptionPane.showOptionDialog(null,
                new Object[] { "Process", progressBar }, "Process",
                JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE,
                null, null, null);
    }

}
import java.util.List;
导入javax.swing.JOptionPane;
导入javax.swing.JProgressBar;
导入javax.swing.SwingWorker;
/**
*@作者Savvas Dalkitsis
*/
公开课考试{
公共静态void main(字符串[]args){
最终JProgressBar progressBar=新JProgressBar(0,99);
SwingWorker w=新SwingWorker(){
@凌驾
受保护的无效进程(列表块){
setValue(chunks.get(chunks.size()-1));
}
@凌驾
受保护的Void doInBackground()引发异常{

对于(inti=0;i,可能对每个长方法都做一个SwingWorker。每个SwingWorker都有自己的进度级别


每个SwingWorker都会在doInBackground方法中更新自己的进度级别,然后调用publish。在process方法中,因此在EDT中,每个SwingWorker都会读取它的进度级别,并更新模型和vision通用进度条。

我遇到了类似的问题。下面是我发现的,也许真正正确的答案并不存在,但让我们给出它试一试:

  • 如果我们有很多迭代,我们可以在
    doInBackGround()
    方法中更新进度条。JProgressBar是SwingWorker的构造函数参数,它扩展了SwingWorker(因此,是的,我们使用自定义)
  • 如果我们没有迭代,也不能中断需要花费大量时间才能完成的方法,我们可以把整个过程搞糟,然后像大多数人一样去做(因此我们的进度条没有线性过程,但它只是在部分工作完成后刷新它的值)。坏消息是,如果我们的方法是唯一一个工作人员这样做的方法(f.e.在后台发送电子邮件)进度条将突然变得满了。不过不是很好,让我们看看第三个选项
  • 这可能会很疯狂,性能也会下降,这都是因为我们的应用程序必须是花式的。因此,让我们来看看这个方法的源代码,它需要很长时间才能完成。我们重写它并粘贴完全相同的代码,但我们又添加了一个参数-猜猜看,是的JProgressBar。在这个方法中,我们创建了一个线程,它将运行到一些布尔参数(标志指示方法最终完成)设置为true。线程将在一些合理的间隔内不断更新JProgressBar。最大的问题是假设合理的间隔是多少。我们应该进行一些测试并估计间隔的值
在第三点中,我描述了如何从方法执行线程,该方法完成一些非迭代(至少在我们的Java代码中不是)且不能中断的任务。线程更新作为方法参数给出的JProgressBar。然而,这显然比纯方法调用要慢(我正在更新我的答案,使之更加清晰和概括)

虽然您已经成功地将逻辑和表示解耦,但这并不是以一种有利于代码重用的方式完成的。Java通过实现使逻辑与表示解耦变得很容易,并获得一些实质性的重用。其思想是使用事件处理程序而不是操作对象

首先,将抽象概念化。后台工作需要间歇地向GUI“呼喊”(发布),GUI需要倾听。两个通用类将编写此想法:

/**
 * Wrapper for the background logic.
 *
 * <T> return type
 * <S> intermediary type (the "shout out")
 */
public static abstract class LoudCall<T, S> implements Callable<T> {

    private PropertyChangeSupport pcs;
    private S shout;

    public LoudCall() {
        pcs = new PropertyChangeSupport(this);
    }

    public void shoutOut(S s) {
        pcs.firePropertyChange("shoutOut", this.shout, 
                this.shout = s);
    }

    public void addListener(PropertyChangeListener listener) {
        pcs.addPropertyChangeListener(listener);
    }

    public void removeListener(PropertyChangeListener listener) {
        pcs.removePropertyChangeListener(listener);
    }

    @Override
    public abstract T call() throws Exception;
}

/**
 * Wrapper for the GUI listener.
 *
 * <T> return type
 * <S> intermediary type (the "shout out" to listen for)
 */
public static abstract class ListenerTask<T, S> extends SwingWorker<T, S> 
        implements PropertyChangeListener {

    private LoudCall<T, S> aMethod;

    public ListenerTask(LoudCall<T, S> aMethod) {
        this.aMethod = aMethod;
    }

    @Override
    protected T doInBackground() throws Exception {
        aMethod.addListener(this);
        return aMethod.call();
    }

    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        if ("shoutOut".equals(evt.getPropertyName())) {
            publish((S)evt.getNewValue());
        }
    }

    @Override
    protected abstract void process(List<S> chunks);
}
/**
*后台逻辑的包装器。
*
*返回类型
*中介类型(“喊出”)
*/
公共静态抽象类LoudCall实现了可调用{
私有财产变更支持PC;
二等兵呼喊;
公共大声呼叫(){
pcs=新财产变更支持(本);
}
公众虚空呼喊(S){
pcs.firePropertyChange(“shoutoot”,this.shout,
这是(s);
}
公共void addListener(PropertyChangeListener侦听器){
pcs.addPropertyChangeListener(listener);
}
公共void RemovelListener(PropertyChangeListener侦听器){
pcs.removePropertyChangeListener(监听器);
}
@凌驾
公共抽象T call()抛出异常;
}
/**
*GUI侦听器的包装器。
*
*返回类型
*中间类型(要收听的“呼喊声”)
*/
公共静态抽象类ListenerTask扩展了SwingWorker
实现PropertyChangeListener{
私人大声呼叫法;
公共侦听器任务(大声呼叫法){
this.aMethod=aMethod;
}
@凌驾
受保护的T doInBackground()引发异常{
aMethod.addListener(这个);
返回aMethod.call();
}
@凌驾
公共作废属性更改(属性更改事件evt){
if(“shoutOut”.equals(evt.getPropertyName())){
发布((S)evt.getNewValue());
}
}
@凌驾
受保护的抽象无效进程(列表块);
}
这些类可用于所有Swing小部件。对于ProgressBar,“shout out”将是一个整数,返回类型为Void:

public class ProgressExample {  
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
    @Override
    public void run() {

        // 1. setup the progress bar
        final JProgressBar progressBar = new JProgressBar(0, 99);

        // 2. Wrap the logic in a "Loud Call"
        LoudCall<Void, Integer> aMethod = new LoudCall<Void, Integer>() {
            @Override
            public Void call() throws Exception {
                for (int i = 0; i < 100; i++) {
                    // "i have an update for the GUI!"
                    shoutOut(i);
                    Thread.sleep(100);
                }
                return null;
            }
        };

        // 3. Run it with a "Listener Task"
        (new ListenerTask<Void, Integer>(aMethod) {
            @Override
            protected void process(List<Integer> chunks) {
                progressBar.setValue(chunks.get(chunks.size() - 1));
            }
        }).execute();

        // 4. show it off!
        JOptionPane.showOptionDialog(null,
            new Object[] { "Process", progressBar }, "Process",
            JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE,
            null, null, null
        );
    }
        });
    }
}
公共类进程示例{
公共静态void main(字符串[]args){
SwingUtilities.invokeLater(新的Runnable(){
@凌驾
公开募捐{
//1.设置进度条
最终JProgressBar progressBar=新的JProgressBar(0,99);
//2.用“大声呼叫”来概括逻辑
LoudCall aMethod=新的LoudCall(){
@凌驾
public Void call()引发异常{
对于(int i=0;i<100;i++){
//“我有GUI的更新!”
呼喊(一);
睡眠(100);
}
返回null;
}
};
//3.使用“侦听器任务”运行它
(新ListenerTask(Method){
@凌驾
保护
public class ProgressExample {  
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
    @Override
    public void run() {

        // 1. setup the progress bar
        final JProgressBar progressBar = new JProgressBar(0, 99);

        // 2. Wrap the logic in a "Loud Call"
        LoudCall<Void, Integer> aMethod = new LoudCall<Void, Integer>() {
            @Override
            public Void call() throws Exception {
                for (int i = 0; i < 100; i++) {
                    // "i have an update for the GUI!"
                    shoutOut(i);
                    Thread.sleep(100);
                }
                return null;
            }
        };

        // 3. Run it with a "Listener Task"
        (new ListenerTask<Void, Integer>(aMethod) {
            @Override
            protected void process(List<Integer> chunks) {
                progressBar.setValue(chunks.get(chunks.size() - 1));
            }
        }).execute();

        // 4. show it off!
        JOptionPane.showOptionDialog(null,
            new Object[] { "Process", progressBar }, "Process",
            JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE,
            null, null, null
        );
    }
        });
    }
}