SwingWorker结束,PropertyChangeListener监听,但我如何回到EDT?

时间:2012-04-19 14:46:59

标签: java multithreading swing swingworker

我已经在这个主题上浏览了很多线索,但似乎没有什么能适合我的具体情况。

我有一个swing应用程序,它分析QR-Codes,提取找到的loginNames并进行DB调用以获取该用户的数据。为了确保可以取消QR码的捕获并且在捕获时仍然可以访问我的应用程序,我使用SwingWorker来实现此目的。到目前为止一切正常,我已经包含了一个PropertyChangeListener,因此应用程序知道我的SwingWorker何时成功读取代码。但是因为我不想将PropertyChangeListener作为我的mainClass中的嵌套类(为了保持结构良好),我在外面为它创建了一个新类。现在我想从这个PropertyChangeListener类返回到我的主类,切换到显示获取数据的相应面板。我有不同的代码可以读取,所以根据代码我有不同的面板切换到(所以我不能一遍又一遍地静态切换到同一个面板)。那么如何委托PropertyChangeListener将控件返回给我的EDT呢? 我已经尝试使用wait()和notify()让我的EDT知道SwingWorker完成了。但显然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没有引用任何面板,即使在EDT中完成了done() - 方法,我还需要以某种方式通知我的mainClass代码已经成功读取并且它现在可以改变panl根据具体代码。

希望这可以解决一些问题。

3 个答案:

答案 0 :(得分:6)

我认为你误解了,因为SwingWorker有什么原因,请阅读SwingWorker tutorial,其中的实现非常保证方法的输出:

  • ()完成

  • 处理()

  • 发布()

  • setProgress()

应在EDT

上完成

答案 1 :(得分:3)

这是错误的:

protected byte[] doInBackground() throws Exception {

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

这表明你在doInBackground方法中进行了关键的Swing调用,这是永远不应该做的事情。而是考虑发布Image或ImageIcon,并从流程方法覆盖设置JLabel的Icon。

正如我在评论中指出的那样,如果减少代码耦合,有时最好将一个PropertyChangeListener与SwingWorker一起使用。这是SwingWorker拥有自己的PropertyChangeSupport及其自己的状态枚举的一个原因。

答案 2 :(得分:2)

简单的swing工作者回答是覆盖done()方法。这是在EDT上执行的 - SwingWorker会为您处理。

您可以使用SwingUtilities.invokeLater自行完成。

对于你提出问题的方式,我怀疑你没有完全掌握线程问题以及如何在线程之间切换。所以对tutorial(如果你还没有)的好评可能是有序的。