Swing Progress Bar通过Worker更新到EventDispatch线程

时间:2014-12-23 22:34:10

标签: java multithreading swing progress-bar java-6

我有一个 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...

无论如何,我相信我需要做些什么才能在正确的线程上执行这些更新,对吗?怎么样?

2 个答案:

答案 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