2

このトピックに関する多くのスレッドを既に閲覧しましたが、私の特定の状況に合うものはないようです。

QRコードを分析し、見つかったloginNamesを抽出し、DB呼び出しを行ってそのユーザーのデータをフェッチするswingアプリケーションがあります。QR コードのキャプチャをキャンセルできるようにし、キャプチャ中にアプリケーションに引き続きアクセスできるようにするために、この目的のために SwingWorker を使用しました。これまでのところ、すべて正常に動作しています。PropertyChangeListener を含めたので、アプリケーションは SwingWorker がコードを正常に読み取ったことを認識できます。しかし、PropertyChangeListener を mainClass 内のネストされたクラスとして保持したくないので (適切な構造を維持するため)、外部に新しいクラスを作成しました。次に、この PropertyChangeListener クラスからメイン クラスに戻り、取得したデータを表示する適切なパネルに切り替えます。読み取ることができるさまざまなコードがありますが、そのため、コードに応じて、切り替えるパネルが異なります(同じパネルに何度も静的に切り替えることはできません)。では、PropertyChangeListener をデリゲートして、コントロールを EDT に戻すにはどうすればよいでしょうか。SwingWorker が終了したことを EDT に知らせるために、wait() と notify() を使用してみました。しかし明らかに wait() は私の EDT をブロックし、SwingWorker の使用は無意味です。

私の問題を十分に詳しく説明できれば幸いです。これに対処するための良いアイデアを持っている人もいます。コード スニペットについてはお問い合わせください。必要なものを追加します。しかし、私のプロジェクトはもう少し複雑なので、求められているものだけを投稿します。

助けてくれてありがとう:)

編集: これは私の SwingWorker が何をしているかを説明するためのコードの抜粋です。

SwingWorker クラス:

public class CodeDetector extends SwingWorker<byte[], String> {

String s;                     // read String
byte[] completeCode;          // byte[] which is returned by doInBackground()
BufferedImage resizedImg;
IplImage img;
JLabel labelForStream;
JLabel result;
FrameGrabber grabber = new VideoInputFrameGrabber();     // using JavaCV.


public CodeDetector(JLabel labelForStream, JLabel result) {
    this.labelForStream = labelForStream;
    this.resultLabel = result;
}

@Override
protected byte[] doInBackground() throws Exception {
    try {
        grabber.start();         // 
        while (true) {
            // End if current thread was canceled.
            if (Thread.currentThread().isInterrupted()) {
                return null;
            }

            // Grab each image, save it, scan for code and display it.  
            img = grabber.grab();
            resizedImg = //  resizing image to fit labelForStream.
                            // save resizedImg to file
            // read barcode from saved file
                    if (isBadgeCode(tmp) || isDeviceCode(tmp)) {
                        s = tmp;
                    } else {
                        continue;
                    }
                    break;
                } catch (NotFoundException e) {
                    // Code could not be encoded yet.
                }
                ...

                    // end worker after timeout

        // show image on window
                if (img != null) {
                    labelForStream.setIcon(new ImageIcon(resizedImg));
                }
            }
        }
    } catch (Exception e) { 
        System.err.println("Error: " + e.getMessage() + " - " + e.getStackTrace() + " - " +  e.getClass());
    }
    return s != null ? s.getBytes() : null;
}

@Override
protected void done() {
    try {
        completeCode = get();
        if (completeCode != null) {
            String code = new String(completeCode);
            if (isOtherCode(code)) {
                resultLabel.setText(code);
            } else if (isUsernameCode(code)) {
                // Cut userName from read code (if previously verified) and set label text.
                resultLabel.setText(verify(code, true) ? code.split(":")[0] : null);
            }
        } else {
            resultLabel.setText(null);
        }
        resultLabel.setVisible(true);
        resultLabel.updateUI();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (ExecutionException e) {
        e.printStackTrace();
    } catch (CancellationException e) {
        return;
    } catch (Exception e) {
        e.printStackTrace();
    }
}

この SwingWorker にはパネルへの参照がないため、done() メソッドが EDT で実行されたとしても、コードが正常に読み取られたこと、および現在はパネルを変更できることを何らかの方法で mainClass に通知する必要があります。特定のコード。

これで問題が少し解決することを願っています。

4

3 に答える 3

6

あなたが誤解していると思いますが、どのような理由があるのか​​ 、実装がメソッドからの出力を完全に保証するSwingWorkerチュートリアルSwingWorkerを読んでください:

  • 終わり()

  • 処理する()

  • 公開()

  • setProgress()

EDTで行う必要があります

于 2012-04-19T14:50:38.737 に答える
3

Swing Worker の簡単な答えは、done()メソッドをオーバーライドすることです。これは EDT で実行されます - SwingWorker がそれを処理します。

SwingUtilities.invokeLater を使用して、自分で行うことができます。

質問の仕方については、スレッドの問題とスレッド間の切り替え方法を完全に把握していないと思われます。したがって、チュートリアルの適切なレビュー(まだ行っていない場合) が適切である可能性があります。

于 2012-04-19T14:51:59.343 に答える
3

これは間違っています:

protected byte[] doInBackground() throws Exception {

  // ....
  if (img != null) {
     labelForStream.setIcon(new ImageIcon(resizedImg));
  }
  // ....
}

これは、doInBackground メソッド内から重要な Swing 呼び出しを行っていることを示しているため、決して実行してはならないことです。代わりに、Image または ImageIcon を公開し、プロセス メソッドのオーバーライドから JLabel の Icon を設定することを検討してください。

私のコメントで指摘したように、コード結合を減らす場合は、SwingWorker で PropertyChangeListener を使用することをお勧めします。これが、SwingWorker が独自の PropertyChangeSupport と独自の状態列挙型を持つ理由の 1 つです。

于 2012-04-19T16:17:43.667 に答える