我开发了一个用于创建和提取存档的Java应用程序 - 如WinRAR。您可以使用多线程同时创建多个归档。最近,我希望在每个创建时在新的JFrame中以JProgressBar的形式在存档创建期间添加信息状态。
但我的问题是在新的状态框架和创建存档的线程中生成信息。这就是我在存档线程中创建JFrame以更新当前进度条的原因。
但就像我可以在各种信息来源和你的答案/评论中阅读它一样,它反对Java Swing和性能;我无法在EDT。
的其他地方创建swing对象但是,我应该如何解决我的问题呢?如何在存档的写入和状态JFrame(使用JProgressBar)之间建立通信?
修改 的
我实现了SwingWorker来管理我的应用程序中的GUI。现在已经完成,我还有一个问题:
使用SwingWorker,如何使用状态框架按钮上的事件对后台任务执行操作? (例如:暂停压缩或停止压缩。)
答案 0 :(得分:5)
在JProgressBar中放置并显示JDialog,不要创建新的Top-Level Container。创建一次并重新使用
长时间繁重的代码可以更好地重定向到BackGround任务
您可以通过后台任务
中的JProgressBar
进度移动
只有在EDT上完成GUI相关代码Concurrency in Swing
并且有两种正确的方法
来自Runnable#Thread
,但GUI相关代码必须包含在invokeLater()
答案 1 :(得分:5)
正如其他人所建议的那样,最好的方法是使用SwingWorker
。
SwingWorker
属性是可听的,并且总是在EDT中调用侦听器,因此,您可以执行以下操作:
public class ArchivingWorker extends SwingWorker<Void, Void> {
JProgressBar progressBar = null;
// Other members here...
...
public ArchivingWorker(...) {
// Any specific initialization here (in EDT)
addPropertyChangeListener(new PropertyChangeListener() {
@Override void propertyChange(PropertyChangeEvent e) {
if ( "state".equals(e.getPropertyName())
&& e.getNewValue() == StateValue.STARTED) {
// Background thread has just started, show a progress dialog here
progressBar = new JProgressBar();
...
}
else if ("progress".equals(e.getPropertyName())) {
// Update progress bar here with e.getNewValue()
...
}
}
});
}
@Override protected Void doInBackground() {
// Archiving process here and update progress from time to time
setProgress(progress);
return null;
}
@Override protected void done() {
// Ensure that archiving process worked correctly (no exception)
try {
get();
} catch (Exception e) {
// Handle exception (user feedback or whatever)
} finally {
// Close progress dialog
...
}
}
}
然后您可以根据需要使用ArchivingWorker
:
ArchivngWorker worker = new ArchivingWorker(...);
worker.execute();
答案 2 :(得分:1)
@mKorbel提供的答案很好,但实际上不需要使用其他顶级容器(例如JDialog
)来显示进度条。相反,您可以使用JFrame
实例的Glass Pane。