4

我做了一个样本来说明问题:

public class Worker extends SwingWorker<Integer, Integer> {
    private GeneralUserInterface gui;

    public Worker(GeneralUserInterface gui){
        this.gui = gui;
    }

    @Override
    protected Integer doInBackground() throws Exception {
        int someResultToReturn = 10;

        for(int i=0; i<100; i++){
            Thread.sleep(50);//The Work
            publish(i+1);//calls process, which updates GUI
        }

        return someResultToReturn;
    }

    @Override
    protected void process(List<Integer> values) {
        for (Integer val : values) {
            gui.updateProgressBar(val);
        }
    }
}

private void jButtonDoWorkActionPerformed(java.awt.event.ActionEvent evt) {
    Worker worker = new Worker(this);
    worker.execute();

    try {
        int resultToGet = worker.get();//Obviously freezes the GUI
    } catch (InterruptedException | ExecutionException ex) {}

    //NEXT LINE NEEDS THE RESULT TO CONTINUE
}

public void updateProgressBar(int value){
    this.jProgressBar1.setValue(value);
}

正如您所猜测的,对 worker.get() 的调用使 UI 无响应,这是正常的,因为它等待线程完成。这类问题一般是怎么解决的?

4

2 回答 2

6

这类问题一般是怎么解决的?

通常你所做的是覆盖该Swingworker.done()方法。当后台线程完成时,在 GUI 线程中执行 Done。然后,您可以安全地调用 get 而不会阻塞并做任何您需要做的事情。

这是执行此操作的一种方法:

public class Worker extends SwingWorker<Integer, Integer> {
    private GeneralUserInterface gui;

    // omitted...

    @Override
    protected Integer doInBackground() throws Exception {
        int someResultToReturn = 10;

        for(int i=0; i<100; i++){
            Thread.sleep(50);//The Work
            publish(i+1);//calls process, which updates GUI
        }

        return someResultToReturn;
    }

    // omitted...

    @Override
    protected void done() {

        try {
           int resultToGet = worker.get();//Obviously freezes the GUI
        } catch (InterruptedException | ExecutionException ex) {}

       //NEXT LINE NEEDS THE RESULT TO CONTINUE
   }
}

private void jButtonDoWorkActionPerformed(java.awt.event.ActionEvent evt) {
    Worker worker = new Worker(this);
    worker.execute();
}

然而,这可能不是最方便的设计。我发现最好让 GUI 的东西成为公共类,然后将 swing worker 创建为非静态内部类。这样,“完成”方法可以轻松访问所有 GUI 私有变量。

于 2012-11-16T21:48:23.187 回答
0

更好的解决方案是为 SwingWorker 提供由 GUI 实现的接口实例。这样你就可以让你的 Worker 更新 GUI。

public class GUI implements GUI_INTERFACE{
....
new foo(this);

@Override
public void INTERFACE_METHOD(Object info){
//Update Gui variables here.
}

}

对于您的 SwingWorker:

class foo extends SwingWorker{
GUI_INTERFACE int
public foo(GUI_INTERFACE bar){
int=bar
}


}
于 2016-02-25T20:56:43.050 回答