2

私のプログラムには 3 つのプライマリ クラスがあります。1 つ目はアプレットを拡張 (およびメインとして機能)、2 つ目はバックエンドのロジスティクス/サーバーとの通信を処理するスレッド (Runnable を実装)、3 つ目は GUI を作成する JPanel クラス (これは作成されます)SwingUtilities.invokeAndWait()メイン(アプレット)クラスでの呼び出しによる新しいスレッドで。

GUI クラスはバックエンド スレッドと数回通信して、画面に表示するデータを取得します。私の問題は、バックエンド クラスがコンポーネントにデータを提供する前に、GUI がそのコンポーネントを表示していることです。そこで、他のスレッドでメソッドを呼び出し、そのメソッドからの応答を待ってから、そのコンポーネントを表示するように GUI に指示したいと思います。私はいくつかのバリエーションを試しました:

Object[] data = backend.Method1(); 
wait();
showComponents(data);

GUIクラスでnotifyAll();、バックエンドスレッドのMethod1の下部に配置しますが、netbeansで警告が表示され(同期コンテキスト外でObject.waitを呼び出しています)、java.lang.illegalmonitorstateexception実行時にプログラムがクラッシュします。synchronized2 つのメソッドにキーワードを追加しようとしましたが、これによりプログラムがフリーズします。

私は(明らかに、確かに)マルチスレッドについて学んでいます:ここで何を誤解していますか?

JPanel クラスが runnable を実装していないことに関連していると感じています。

編集: @MadProgrammer の提案に従って、私は SwingWorker を利用しています。指摘してくれてありがとう、私は前に聞いたことがありませんでした。

 final JLabel loading = new JLabel("loading");
    loading.setVisible(true);
    add(loading);

    SwingWorker sw = new SwingWorker<Map<String, ArrayList<Time[]>>, Void>() {
        @Override
        public Map<String, ArrayList<Time[]>> doInBackground(){
            System.out.println("doing");
            Map<String, ArrayList<Time[]>> toReturn = dbh.getTimes(specToPass);
            return toReturn;
        }

        public void done(){
            try {
                loading.setVisible(false);
                Map<String, ArrayList<Time[]>> weekMap = new HashMap(this.get());
                showTimes(weekMap);
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            } catch (ExecutionException ex) {
                  ex.printStackTrace();
            }
       }
    };
    sw.execute();

これを適切に実装していない場合はお知らせください。再度、感謝します。

4

1 に答える 1

5

しないでください。何らかの方法で UI をブロックすることは、常に悪い考えです。これにより、アプリケーションが「ハング」し、UI が更新されなくなります (または、ユーザーからの入力に応答しなくなります)。

これにより、ユーザーエクスペリエンスが非常に悪くなります。

代わりに、必要に応じてデータ スレッドが更新を UI に送り返すことを可能にする何らかの種類のコールバックを使用します。これにより、UI がデータ スレッドからのデータを待機している間、「待機」メッセージのようなものを表示できるようになります。

を使用してデータ コレクションを処理することもできSwingWorkerますが、すべてのニーズに対して単純すぎるかもしれませんが、更新を UI に同期させるための単純な方法を提供します。

すべての作成/変更/UI とのやり取りが、イベント ディスパッチ スレッドのコンテキスト内で行われるようにしてください。

詳細については、Swing での同時実行をご覧ください。

更新しました

基本的なワークフロー(IMHO)は次のようになります...

  • UI - バックグラウンド スレッドからデータを要求し、リスナー インターフェイスをバックグラウンド スレッドに渡します (たとえばloadingDone、 や など のメソッドを使用)。loadingFailed
  • UI - 「読み込み中」メッセージを表示します。素敵なアニメーション GIF を表示する場合があります
  • loadingDoneスレッド - データがロードされたら (すべてがうまくいったと仮定して)、データをパッケージ化し、メソッドを介して戻します。
  • UI -loadingDoneが呼び出されると、( を使用して) EDT と再同期しSwingUtilities.invokeLater、UI を更新します。

これは実際には a を使用すると簡単になり、SwingWorker組み込みの進行状況の更新が提供されます。

于 2013-03-19T05:50:38.407 に答える