问题
I know the subject has already been seen on many Questions and has been answered, but still, I can't get trough it.
I just want to update a progressBar while extracting some stuff of a large xml file. I thought it was enough to have the time-consuming loop in a different thread but ?.. All I managed to get is the progressBar either not showed at all, or updated at the end, just before it's closed.
Instanced somewhere near the launch of the application, I have:
public class SomeClass {
private SomeClass () {
myXMLParser reader = new myXMLParser();
CoolStuff fromXml = reader.readTheXml();
}
}
while showing and updating a JDialog with a JProgressBar:
public class LoadingDialog extends JDialog {
private JProgressBar progressBar;
/* ... */
public void progress() {
progressBar.setValue(progressBar.getValue() + 1);
}
}
So I have this 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;
}
}
I have seen many things with SwingWorker
and using PropertyChange
events update the progressBar, but examples are always given all-in-one, with the processing and the progressbar within the same class, and with classes within classes, and since I begin in Java, I wasn't able to translate that to my situation.
Any help ?.. Any (not too obvious) advices ?
Edit: So thanks to btantlinger it worked like that:
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;
}
}
回答1:
You MUST update the JProgress bar on the Swing Event Dispatch Thread. You cannot modify Swing components on any other thread.
Your only other alternative would be to set the JProgress bar "indeterminate" before you start your thread where the progress bar will just go back and forth.
E.g
progBar.setIndeterminate(true);
See the SwingWorker javadoc: http://docs.oracle.com/javase/6/docs/api/javax/swing/SwingWorker.html
If you don't want to use the SwingWorker, another option is the SwingUtilities.invokeLater
method
//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);
}
});
回答2:
In addition to the code provided by @btantlinger, I found after testing that it required an additional line of code in order to update the progress bar on the UI thread while processing. See below.
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());}
});
来源:https://stackoverflow.com/questions/9578694/updating-a-jprogressbar-while-processing