我已经在这个主题上浏览了很多线索,但似乎没有什么能适合我的具体情况。
我有一个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根据具体代码。
希望这可以解决一些问题。
答案 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(如果你还没有)的好评可能是有序的。