我有一个 JAVA6 GUI处理数据导入我们的数据库。我已经实现了一个有效的JProgressBar。我知道对GUI的更改必须通过事件派发线程来完成 - 我认为我没做(正确/完全)。
后台工作线程UploadWorker是通过传入在主程序中创建的JProgressBar构建的,并在完成后直接设置更改进度条的值:
// when constructed, this gets set to the main program's JProgressBar.
JProgressBar progress;
protected Void doInBackground() throws Exception {
write("<!-- Import starting at " + getCurrentTime() + " -->\n");
boolean chunked = false;
switch (importMethod) {
//do some importing
}
write("<!-- Import attempt completed at " + getCurrentTime() + "-->\n");
//here changes to the GUI are made
progress.setMaximum(0);
progress.setIndeterminate(false);
progress.setString("Finished Working");
return null;
}
这样可以正常工作,但有时(并非总是)会让我在std中输入几个NPE,并且用户在抱怨:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at javax.swing.plaf.basic.BasicProgressBarUI.updateSizes(Unknown Source)
...etc...
无论如何,我相信我需要做些什么才能在正确的线程上执行这些更新,对吗?怎么样?
答案 0 :(得分:3)
您可以通过多种方式执行此操作,您可以使用process
的{{1}}方法更新进度条,但对我而言,这会将您的工作人员与UI相关联,这并不总是令人满意的。
更好的解决方案是利用SwingWorker
的进度和SwingWorker
支持,例如....
PropertyChange
这意味着您可以为任何worker.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if ("state".equalsIgnoreCase(evt.getPropertyName())) {
SwingWorker worker = (SwingWorker) evt.getSource();
switch (worker.getState()) {
case DONE:
// Clean up here...
break;
}
} else if ("progress".equalsIgnoreCase(evt.getPropertyName())) {
// You could get the SwingWorker and use getProgress, but I'm lazy...
pb.setIndeterminate(false);
pb.setValue((Integer)evt.getNewValue());
}
}
});
worker.execute();
执行此操作,只要工作人员在内部调用SwingWorker
...
setProgress
这样做的好处是从事件调度线程的上下文中调用public static class ProgressWorker extends SwingWorker {
public static final int MAX = 1000;
@Override
protected Object doInBackground() throws Exception {
for (int index = 0; index < MAX; index++) {
Thread.sleep(250);
setProgress(Math.round((index / (float)MAX) * 100f));
}
return null;
}
}
事件通知,从而可以安全地从内部更新UI。
完全可运行的例子......
PropertyChange
答案 1 :(得分:0)
您可以使用SwingUtilities.invokeLater创建一个执行GUI更新并在GUI线程中调用它的新Runnable