0

オーディオ分析を行うアプリを作成しています (コード推定やその他のものを追加してギターチューナーとして使用するため) が、GUI に問題があります。最初の問題は、クリックすると表示されるテキストを変更するボタンがあることです。クリックすると、テキストは変更されませんが、変更する必要があるコード行に確実に到達します。

もう 1 つのことは、SwingWorker を繰り返し実行し (終了したら再起動する)、毎回 GUI を更新する必要があることです。私のコードは現時点では、SwingWorker を繰り返し実行する while ループがありますが、EDT で実行されているため (おそらく) GUI が応答しなくなります。SwingWorker を繰り返し実行させる最善の方法は何でしょうか? ループを実行するための新しいスレッドを作成するだけですか、それとも何か他のものですか?

内部 ActionListener クラスのコードは次のとおりです。

private class TunerListener implements ActionListener {
    private boolean firstUpdate = true;
    private volatile boolean executing = false;

    private final SwingWorker<Void, Void> tunerWorker = new SwingWorker<Void, Void>() {

        @Override
        protected Void doInBackground() {
            model.update();
            return null;
        }

        @Override
        protected void done() {
            if (!this.isCancelled()) {
                prev.setText(model.getPrev());
                currentNote.setText(model.getNote());
                next.setText(model.getNext());
                frequency.setText(model.getFrequency());
                switch (model.getOffset()) {
                    case -2:
                        light_2.setIcon(onRed);
                        light_1.setIcon(off);
                        light0.setIcon(offBig);
                        light1.setIcon(off);
                        light2.setIcon(off);
                        break;
                    case -1:
                        light_2.setIcon(off);
                        light_1.setIcon(onRed);
                        light0.setIcon(offBig);
                        light1.setIcon(off);
                        light2.setIcon(off);
                        break;
                    case 0:
                        light_2.setIcon(off);
                        light_1.setIcon(off);
                        light0.setIcon(onGreen);
                        light1.setIcon(off);
                        light2.setIcon(off);
                        break;
                    case 1:
                        light_2.setIcon(off);
                        light_1.setIcon(off);
                        light0.setIcon(offBig);
                        light1.setIcon(onRed);
                        light2.setIcon(off);
                        break;
                    case 2:
                        light_2.setIcon(off);
                        light_1.setIcon(off);
                        light0.setIcon(offBig);
                        light1.setIcon(off);
                        light2.setIcon(onRed);
                        break;
                }
            }
        }

    };

    @Override
    public void actionPerformed(ActionEvent ae) {

        if (ae.getActionCommand().equals("tune")) {
            if (!executing) {
                tune.setText("Stop Tuning");
                executing = true;

                while (executing) {
                    tunerWorker.execute();
                    firstUpdate = false;
                }
                firstUpdate = true;
            } else {
                tune.setText("Start Tuning");
                executing = false;
                tunerWorker.cancel(true);
                firstUpdate = true;
            }
        }

    }
}

編集: ボタンのテキストの問題は修正されたようですが、まだこの SwingWorker を正しく動作させることができません。while ループを完全に削除して、done() メソッドから再実行しようとしましたが、これは実際には役に立たないようです...

4

2 に答える 2

6

"SwingWorkerは 1 回だけ実行されるように設計されています。" 代わりに、このに示すように、ワーカーの実行とライフサイクルを制御します。

于 2012-05-05T11:39:36.523 に答える
5

免責事項: マルチスレッドは、私の最大の専門分野ではありません...

両方の問題は実際には同じものです。たとえば、EDT が while ループの実行でビジーであるため、GUI が応答しなくなります。これは、新しいテキスト値でボタンを再描画できず、ユーザー入力に反応できないことを意味します。

また、SwingWorker の各インスタンスは 1 回しか実行できないためexecute()、ループ内で複数回呼び出しても 1 回だけ実行されます。

TunerWorker オブジェクトを作成してその中にループを配置し、ループを開始する必要があるときはいつでも新しいオブジェクトを作成することをお勧めします。このような:

class TunerListener implements ActionListener {

private TunerWorker tw = null;

@Override
public void actionPerformed(ActionEvent ae) {

    if (ae.getActionCommand().equals("tune")) {
        if (tw == null || tw.isDone()) {
            tune.setText("Stop Tuning");
            executing = true;

            tw = new TunerWorker();
            tw.execute();

        } else {
            tune.setText("Start Tuning");
            executing = false;
            tw.cancel(true);
            }
        }
    }
}

final class TunerWorker extends SwingWorker<Void, Void> {

    @Override
    protected Void doInBackground() {
        while (!this.isCancelled()) {
            model.update();
        }        
        return null;
    }    

    @Override
    protected void done() {
        if (!this.isCancelled()) {
            //Removed this code to make the example prettier...
        }
    }
}

ああ、何をしようとしているのかわからなかったfirstUpdateので、例から外しました。うまくいけば、それを元に戻す方法を理解するのはそれほど難しくありません.

編集: おっと、そのコードは実際には機能しませんでした。今すぐ修正する必要があります。

于 2012-05-05T11:42:25.430 に答える