更新JProgressBar进度条的同时进行处理

6

我知道这个主题已经在很多问题上被讨论并得到了解答,但是我仍然无法理解。

我只是想在提取大型xml文件的一些内容时更新进度条。我认为只需要将耗时的循环放在不同的线程中,但是...我设法做到的是要么根本没有展示进度条,要么在关闭之前更新。

在应用程序启动附近的某个地方实例化:

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的内容,但是这些例子总是将处理和进度条放在同一个类中,并且还有嵌套类,因此由于我刚开始学习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;
    }
}
2个回答

11

你必须在Swing事件分发线程上更新JProgress bar。你不能在其他任何线程上修改Swing组件。

你唯一的另一个选择是在启动进度条的线程之前将JProgress bar设置为“不确定”,这样进度条将来回移动。

例如

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);


    }
});

3

除了@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());
       }
     });   

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接