简体   繁体   English

如何在不冻结GUI的情况下调用SwingWorker .get()?

[英]How to call SwingWorker .get() without freezing GUI?

I made a sample to make the question clear : 我提供了一个样本来阐明问题:

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);
}

As you would guess, the call to worker.get() makes the UI unresponsive, which is normal since it waits the thread to finish. 如您所料,对worker.get()的调用使UI无响应,这是正常的,因为它等待线程完成。 How is this kind of problem usually solved ? 通常如何解决这种问题?

How is this kind of problem usually solved ? 通常如何解决这种问题?

Normally what you do is override the Swingworker.done() method. 通常,您要做的是重写Swingworker.done()方法。 Done is executed in the GUI thread when your background thread is completed. 后台线程完成后,在GUI线程中执行完成。 Then you can safely call get without blocking and do whatever you need to do. 然后,您可以安全地调用get而不会阻塞,并做您需要做的任何事情。

Here is one way to do this: 这是执行此操作的一种方法:

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();
}

However this may not be the most convenient design. 但是,这可能不是最方便的设计。 I find it works best to have the GUI stuff be the public class, then create the swing worker as a non-static inner class. 我发现最好让GUI成为公共类,然后将swing worker创建为非静态内部类。 That way the "done" method has easy access to all the GUI private variables. 这样,“完成”方法可以轻松访问所有GUI私有变量。

a better solution is to provide your SwingWorker with an instance of an interface implemented by your GUI. 更好的解决方案是为SwingWorker提供由GUI实现的接口的实例。 That way you can have your Worker update the GUI. 这样,您就可以让工作人员更新GUI。

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

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

}

For your SwingWorker: 对于您的SwingWorker:

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


}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM