在处理时更新JProgressBar



我知道这个主题已经出现在很多问题上,并且已经得到了回答,但我仍然无法理解。

我只想更新progressBar,同时提取一个大xml文件的一些东西。我认为在另一个线程中进行耗时的循环就足够了,但是?。。我所得到的只是progressBar要么根本没有显示,要么在它关闭之前在最后更新。

在应用程序启动附近的某个地方举例,我有:

public class SomeClass {
    private SomeClass () {
        myXMLParser reader = new myXMLParser();
        CoolStuff fromXml = reader.readTheXml();
    }
}

同时使用JProgressBar:显示和更新JDialog

public class LoadingDialog extends JDialog {
    private JProgressBar progressBar;
    /* ... */
    public void progress() {
        progressBar.setValue(progressBar.getValue() + 1);
    }
}

所以我有了myXMLParser:

public class myXMLParser {
    private LoadingDialog loadingDialog = new LoadingDialog();
    public CoolStuff readTheXml() {
        CoolStuff fromXml = new CoolStuff();
        while(manyIterations) {
            loadingDialog.progress();
            fromXml.add(some() + xml() + reading());
        }
        return fromXml;
    }
}

我在SwingWorker和使用PropertyChange事件更新progressBar方面看到了很多东西,但总是给出一体式的例子,处理和progressBar在同一个类中,类在类中,由于我开始学习Java,我无法将其转化为我的情况。

有什么帮助吗?。。有什么(不太明显的)建议吗?

编辑:所以多亏了btantlinger,它就这样工作了:

public class SomeClass {
    private SomeClass () {
        myXMLParser reader = new myXMLParser();
        new Thread(new Runnable() {
            @Override
            public void run() {
                CoolStuff fromXml = reader.readTheXml();
            }
        }).start();
    }
}
public class LoadingDialog extends JDialog {
    private JProgressBar progressBar;
    /* ... */
    public void progress() {
        progressBar.setValue(progressBar.getValue() + 1);
    }
}
public class myXMLParser {
    private LoadingDialog loadingDialog = new LoadingDialog();
    public CoolStuff readTheXml() {
        CoolStuff fromXml = new CoolStuff();
        while(manyIterations) {
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    loadingDialog.progress();
                }
            });
            fromXml.add(some() + xml() + reading());
        }
        return fromXml;
    }
}

您必须更新Swing Event Dispatch线程上的JProgress栏。不能在任何其他线程上修改Swing组件。

您唯一的其他选择是在启动线程之前将JProgress栏设置为"不确定",进度栏将来回移动。

E.g

progBar.setIndeterminate(true);

请参阅SwingWorker javadoc:http://docs.oracle.com/javase/6/docs/api/javax/swing/SwingWorker.html

如果您不想使用SwingWorker,另一个选项是SwingUtilities.invokeLater方法

//inside your long running thread when you want to update a Swing component
SwingUtilities.invokeLater(new Runnable() {
    public void run() {
        //This will be called on the EDT
        progressBar.setValue(progressBar.getValue() + 1);

    }
});

除了@btantlinger提供的代码外,我在测试后发现,它需要额外的一行代码才能在处理时更新UI线程上的进度条。请参见下文。

   SwingUtilities.invokeLater(new Runnable() {
       public void run() {
           progressBar.setValue((int)percentage);
           //below code to update progress bar while running on thread
           progressBar.update(progressBar.getGraphics());
       }
     });   

最新更新