问题
I need to find a way to use the Swing Timer with a progress bar. I tried using Thread.sleep(), but it crashed the app when I used it. Any ways to use the Swing Timer instead of the Sleep()?
public void piiEros(int dist)
{
Pii pii = new Pii();
pii.setVisible(true);
for(int pc = 0;100 > pc; pc++)
{
try {
Thread.sleep(dist/100);
} catch (InterruptedException ex) {
Logger.getLogger(Trav.class.getName()).log(Level.SEVERE, null, ex);
}
pii.pg.setValue(pc);
}
pii.dispose();
o.Eros();
}
NOTES: Pii is a class with th Progress Bar. Dist is the speed at which it loads. Trav is the class the method is in. Pc stands for %, how much is done is displyed on the bar. o.Eros opens anotherr GUI.
回答1:
It's probably easier (in the long run) to use a SwingWorker
. It supplies a number of useful methods for updating the UI (from the context of the Event Dispatching Thread) while allowing to continue executing in the background...
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestSwingWorker02 {
public static void main(String[] args) {
new TestSwingWorker02();
}
public TestSwingWorker02() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
JProgressBar pb = new JProgressBar();
add(pb);
new ProgressWorker(pb, 40).execute();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
public class ProgressWorker extends SwingWorker<Void, Integer> {
private int delay;
private JProgressBar pb;
public ProgressWorker(JProgressBar progressBar, int delay) {
this.pb = progressBar;
this.delay = delay;
}
@Override
protected void process(List<Integer> chunks) {
// Back in the EDT...
pb.setValue(chunks.get(chunks.size() - 1)); // only care about the last one...
}
@Override
protected Void doInBackground() throws Exception {
for (int index = 0; index < 100; index++) {
publish(index);
Thread.sleep(delay);
}
return null;
}
@Override
protected void done() {
// Back in the EDT...
//pii.dispose();
//o.Eros();
}
}
}
The SwingWorker
allows you to separate the logic. In the doInBackground
method you can focus on that part of the code that needs to operate outside the EDT, you can publish
updates back to the EDT and process
them separately. When it's all done
you can clean up as required.
SwingWorker
also provides a progress monitoring functionality, so, in your case, this would you wouldn't have to use the publish
/process
portion of the API if you didn't want to. This would allow you to attach a PropertyChangeListener
to a the worker without the need to expose the progress bar to it. (But I did for the example)
public class ProgressWorker extends SwingWorker<Void, Integer> {
private int delay;
private JProgressBar pb;
public ProgressWorker(JProgressBar progressBar, int delay) {
this.pb = progressBar;
this.delay = delay;
// You can use a property change listener to monitor progress updates...
addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if ("progress".equalsIgnoreCase(evt.getPropertyName())) {
pb.setValue((Integer)evt.getNewValue());
}
}
});
}
@Override
protected Void doInBackground() throws Exception {
for (int index = 0; index < 100; index++) {
setProgress(index);
Thread.sleep(delay);
}
return null;
}
@Override
protected void done() {
// Back in the EDT...
//pii.dispose();
//o.Eros();
}
}
回答2:
you can change your piiEros
method in this way:
public void piiEros(int dist)
{
final Pii pii = new Pii();
pii.setVisible(true);
javax.swing.Timer timer = new javax.swing.Timer(dist/100, new ActionListener()
{
public void actionPerformed(ActionEvent evt)
{
pii.pg.setValue(pg.getValue()++);
if ( pii.pg.getValue() > 100 )
{
timer.stop();
pii.dispose();
o.Eros();
}
}
});
timer.setInitialDelay(0);
timer.setRepeats(true);
timer.start();
}
来源:https://stackoverflow.com/questions/15668715/how-to-use-the-swing-timer-to-delay-the-loading-of-a-progress-bar