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()。Done は、バックグラウンド スレッドが完了すると、GUI スレッドで実行されます。その後、ブロックせずに get を安全に呼び出すことができ、必要なことは何でも実行できます。

これを行う 1 つの方法を次に示します。

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 を public クラスにしてから、swing ワーカーを非静的内部クラスとして作成するのが最もうまくいくと思います。そうすれば、「完了」メソッドはすべての GUI プライベート変数に簡単にアクセスできます。

于 2012-11-16T21:48:23.187 に答える
0

より良い解決策は、GUI によって実装されたインターフェースのインスタンスを SwingWorker に提供することです。そうすれば、ワーカーに 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 に答える