2

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

我有一个 Swing 应用程序,它分析 QR 码、提取找到的登录名并进行数据库调用以获取该用户的数据。为了确保可以取消 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 代码已成功读取并且它现在可以根据具体代码。

希望这能澄清一点。

4

3 回答 3

6

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

  • 完毕()

  • 过程()

  • 发布()

  • 设置进度()

应该在EDT上完成

于 2012-04-19T14:50:38.737 回答
3

简单的摇摆工人答案是覆盖该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,并从 process 方法覆盖设置 JLabel 的 Icon。

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

于 2012-04-19T16:17:43.667 回答