3

多段階プロセスを実行するコードをリファクタリングしています。各ステップは、ネストされたjava.awt.EventQueue.invokeLAter.... 呼び出し内にあります。次のようになります。

   import java.awt.EventQueue;


public class NestedInvokeLater {

    /**
     * @param args
     */
    public static void main(String[] args) {
        java.awt.EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                changeTabPanel();
                copySomeFiles();
                enableNextButton1();
                upDateProgressBar(10);
                java.awt.EventQueue.invokeLater(new Runnable() {

                    @Override
                    public void run() {
                        readInFiles();
                        doSomethingToFiles();
                        upDateProgressBar(15);
                        java.awt.EventQueue.invokeLater(new Runnable() {

                            @Override
                            public void run() {
                                doSomethingElse();
                                upDateProgressBar(100);

                            }
                        });
                    }
                });

            }

        });

    };
}

私は Java に慣れていないので、これらの呼び出しを入れ子にして EDT に「ジョブ」を追加する点がわかりません。また、これらの呼び出しをいじることに 100% 自信があるわけでもありません。私は、invokeLater呼び出しが何をするのか、そして各ステップが何をするのかを理解していると思います。この理解が間違っている場合は修正してください。

invokeLaterは、イベント ディスパッチ スレッドで実行されるジョブのリストに呼び出しを追加するために使用されます。次に Java は、各呼び出しがいつ/どのように行われるかを処理し、EDT と GUI が「バックグラウンドで」ジョブを実行する際にロックしないようにします。

これらの呼び出しをネストすると、一連のジョブをキューに入れる必要があることがわかります。そのうちの 1 つは何かをキューに入れることであり、それはいくつかのジョブをキューに入れます....そのうちの 1 つは何かをキューに入れることです。ただし、最初の内部呼び出しは、前のジョブが完了した後にのみキューに入れられます。すべてが順番に発生します (これはプロセス全体の私の理解に沿っています) が、ネストされたリクエストを使用してジョブをキューに入れる理由がわかりません。これを最初から書いていたら、呼び出しごとに単純に関数を作成し、それらを順番に呼び出していたでしょう。

私はJavaの初心者にすぎないことを認識しています。おそらく、このネストを重要にする大きな何かが欠けているでしょう。しかし、これに関するドキュメントはなく、ネストに関するコードのコメントもありません。

私は何が欠けていますか?このコードの要点が何かあるとすれば、それは何ですか?

4

4 に答える 4

4

これほど多くのネストされた呼び出しを実行しても意味がありません。善意に基づいていますが、実装が不十分です。

これを適切に行いたい場合は、SwingWorker.

ドキュメントにSwingWorkerは、アプリケーションのバックグラウンドでいくつかのタスクを実行する実装方法の優れた例があります (PrimeNumbersTaskクラスはそこに示されています)。

編集: これは、あなたの場合に SwingWorker で何をすべきかの例です。

class SequentialInvoker extends SwingWorker<Void, Integer> {
    @Override
    public void doInBackground() {

        changeTabPanel();
        copySomeFiles();
        enableNextButton1();
        setProgress(10);

        readInFiles();
        doSomethingToFiles();
        setProgress(15);

        doSomethingElse();
        setProgress(100);
    }
}

プログレス バーに進行状況を実際に表示するには、SwingWorkerドキュメントからコピーした次のコードを見てください。

JTextArea textArea = new JTextArea();
JProgressBar progressBar = new JProgressBar(0, 100);
SequentialInvoker task = new SequentialInvoker();
task.addPropertyChangeListener(
    new PropertyChangeListener() {
        public  void propertyChange(PropertyChangeEvent evt) {
            if ("progress".equals(evt.getPropertyName())) {
                progressBar.setValue((Integer)evt.getNewValue());
            }
        }
    }); 

このコードを使用すると、進行状況バーに進行状況が表示されますSwingWorker

于 2013-03-19T16:27:00.993 に答える
2

このようにする利点の 1 つは、他のキューに入れられたものがその間に実行されることです。そのため、changeTabPanel() を実行するセクションと readInFiles() を実行する部分の間で、GUI はユーザーがボタンをクリックするなどに応答するようになります...

実際の実装は少し紛らわしい混乱であり、匿名関数がなぜそれほど良い考えではなかったのか (私見) を示しています。3 つの部分を「実際の」関数にして、それらを順番に呼び出すというあなたの傾向は良いものです。ただし、同じロジックを維持するには、実際に行う必要があるのは、それらを 3 つのrunnableにして、それぞれの invokeLater を後続の runnable にすることです。

そして、@Cyrille は、EDT でこれらの主要なタスクを実行することは適切ではありません。

于 2013-03-19T16:32:04.690 に答える
1

ここで使用されるジョブは 3 つありinvokeLaterます。それぞれがコストのかかることを行い、呼び出しupdateProgressBarてから、次のジョブを EDT に追加します。

つまり、invokeLater を呼び出して実行するのではなく、コードが次のコストのかかる処理に進むだけの場合、EDT はプログレス バーを再描画して新しい値を表示する機会がありません。これがおそらく、作業が 3 回のinvokelater呼び出しで中断された理由です。

さて、これは私が良いコードと呼ぶものではありません。これは非常に悪い習慣です。EDT で長いプロセスを実行しないでください。すべてがブロックされ、GUI が応答しなくなるからです。これは、プロセスが別のスレッドで実行されるように変更してinvokeLaterから、プログレス バーを更新するためだけに呼び出す必要があります。

編集:タイトルの質問にもっと一般的に答えるために:への呼び出しをネストする賢明な理由はほとんどありませんinvokeLater。これを行っているときは、「このジョブをキューに入れて、同じスレッドで実行されますが、後で良いと思われるときに実行されるようにします」と言います。したがって、ここのように、GUI の残りの部分に自分自身を再描画する機会を与えます。ただし、EDT で実行時間の長いプロセスがある場合にのみ意味があり、これは常に避ける必要があります。

于 2013-03-19T16:27:55.400 に答える
0

あなたが投稿したコードは私にはまったく意味がありません.EDTにイベントを投稿する可能性のある並列スレッドが実行されていないため、すべてを順番に書くことができます. invokeLater()ただし、Swing コンポーネントを使用するため、最初のコンポーネントが必要です。

しかし、あなたのコードが示すように、ファイルの読み取り、ファイルで何かを行うなど、比較的時間のかかる操作を行っていることを示唆しています...これらのメソッドは、EDT ではなく、新しいワーカー スレッドで実行する必要があります。また、これらのワーカー スレッドの run() メソッドでは、GUI を更新するために EventQueue.invokeLater() を呼び出す必要があります。

于 2013-03-19T16:31:11.703 に答える