|
|
|
Contents: |
|
|
|
Related content: |
|
|
|
Subscriptions: |
|
|
| A subtle, but important update to JProgressBar
John
Zukowski (mailto:jaz@zukowski.net?cc=&subject=Indeterminate
progress bars) President, JZ Ventures, Inc. 18 November 2003
Developers use a JProgressBar
component to show users how far along a task has progressed. For really
long tasks or those where it's difficult to figure out exactly how far
along that task is, the Merlin release adds an indeterminate mode to
JProgressBar . This month, columnist John Zukowski provides
a refresher on using JProgressBar and discusses its new
indeterminate mode. Share your thoughts on this article with the author
and other readers in the accompanying discussion
forum. (You can also click Discuss at the
top or bottom of the article to access the forum.)
Some changes in the Java 2 SDK, Standard Edition, version 1.4 are big,
such as the addition of new components like JSpinner , new
layout managers like SpringLayout , or new APIs like the Java
Logging API. Other changes, such as slight improvements or tweaks to
existing APIs, are less dramatic. This month's tip on the
JProgressBar component is of the latter variety. It's subtle,
but important.
Basic progress bar
usage
JProgressBar is part of the original set
of Swing components. It offers a simple way to graphically show a
process's completion progress. As the process progresses, a bar extends
across the component until the job is completed and the bar is filled. The
movement of the bar is usually part of some multithreaded task, which
helps to avoid blocking progress from the rest of the application, like
regular screen updates. While there's no specific rule that says a
progress bar must move in linear steps, as a user I would find it a little
weird to see the progress move from 10 percent to 35 percent, then back to
27 percent, then up to 80 percent before ending at 0 percent.
You construct a JProgressBar using one of the five
constructors, shown in Listing 1: Listing 1.
JProgressBar constructors
public JProgressBar()
public JProgressBar(int orientation)
public JProgressBar(int minimum, int maximum)
public JProgressBar(int orientation, int minimum, int maximum)
public JProgressBar(BoundedRangeModel model)
|
JProgressBar lets you initialize the orientation and range
of values. Orientation is done through the VERTICAL or
HORIZONTAL constants of JProgressBar .
HORIZONTAL is the default.
After you create the component and show it on the screen, you kick off
a secondary thread to perform the task whose progress needs measuring. You
then periodically update the current value of the progress bar with the
setValue() method to indicate the current progress of the
task. Listing 2 shows a simple example of setValue() : Listing 2. Simple JProgressBar usage
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.lang.reflect.*;
public class ProgressSample {
static class BarThread extends Thread {
private static int DELAY = 500;
JProgressBar progressBar;
public BarThread(JProgressBar bar) {
progressBar = bar;
}
public void run() {
int minimum = progressBar.getMinimum();
int maximum = progressBar.getMaximum();
Runnable runner = new Runnable() {
public void run() {
int value = progressBar.getValue();
progressBar.setValue(value+1);
}
};
for (int i=minimum; i<maximum; i++) {
try {
SwingUtilities.invokeAndWait(runner);
// Our task for each step is to just sleep
Thread.sleep(DELAY);
} catch (InterruptedException ignoredException) {
} catch (InvocationTargetException ignoredException) {
}
}
}
}
public static void main(String args[]) {
// Initialize
final JProgressBar aJProgressBar = new JProgressBar(0, 100);
final JButton aJButton = new JButton("Start");
ActionListener actionListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
aJButton.setEnabled(false);
Thread stepper = new BarThread(aJProgressBar);
stepper.start();
}
};
aJButton.addActionListener(actionListener);
JFrame theFrame = new JFrame("Progress Bars");
theFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container contentPane = theFrame.getContentPane();
contentPane.add(aJProgressBar, BorderLayout.NORTH);
contentPane.add(aJButton, BorderLayout.SOUTH);
theFrame.setSize(300, 100);
theFrame.show();
}
}
|
When you first run this code, you'll see a screen similar to Figure
1.
Figure 1. Starting screen
You click the button to start the secondary task and update the
progress bar as it runs. Figure 2 shows the bar in the middle of its
run.
Figure 2. Screen showing progress
Nothing too fancy going on here. The main code creates the GUI with a
button and progress bar. When you select the button, it triggers the
action to update the progress bar. The progress bar is meant to measure
some task. In the example program, that task is to just sleep for a half
second, 100 different times.
By default, there is no graphical indication of progress besides the
bar. By adding the line of code shown below, you can have the bar show
what percentage of the task is completed as the task progresses:
aJProgressBar.setStringPainted(true);
|
Figure 3 shows our screen with the new code added:
Figure 3. Showing completion percentage
Indeterminate
usage Starting with the Merlin release,
JProgressBar supports yet another mode -- indeterminate.
You use this mode for long tasks with no fixed number of steps. It shows
constant animation to indicate something is going on, but it doesn't
indicate what percentage has completed. If -- or when -- you determine how
long a task will take, you can switch back to determinate mode. While in
indeterminate mode, though, JProgressBar shows a bar that
goes back and forth within the display area.
Listing 3 shows
an example of this mode. The new method here is just
setIndeterminate() . A value of true means
indeterminate, while false is normal or determinate. Listing 3. Indeterminate progress bars
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class ProgressSample2 {
public static void main(String args[]) {
final JProgressBar aJProgressBar = new JProgressBar(0, 100);
aJProgressBar.setIndeterminate(true);
JButton aJButton = new JButton("Toggle");
ActionListener actionListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
boolean indeterminate = aJProgressBar.isIndeterminate();
aJProgressBar.setIndeterminate(!indeterminate);
}
};
aJButton.addActionListener(actionListener);
JFrame theFrame = new JFrame("Indeterminate");
theFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container contentPane = theFrame.getContentPane();
contentPane.add(aJProgressBar, BorderLayout.NORTH);
contentPane.add(aJButton, BorderLayout.SOUTH);
theFrame.setSize(300, 100);
theFrame.show();
}
}
|
Figure 4 shows
the associated screen (you'll have to imagine the bar moving back and
forth). The button toggles the progress bar between the indeterminate and
determinate modes.
Figure 4. Indeterminate mode
There are two new UI defaults available to allow you to change the
repaint interval and cycle time: ProgressBar.repaintInterval
and ProgressBar.cycleTime . Changing these settings -- as
shown below -- changes the display speed. The cycle time must be an even
multiple of the repaint interval, so if the interval is 100, then the
cycle time could be 200, 500, or 1000 -- but not 750.
UIManager.put("ProgressBar.repaintInterval", new Integer(150));
UIManager.put("ProgressBar.cycleTime", new Integer(1050));
|
Note that you need to set these settings before you
create the progress bar.
Conclusion There's
much more to the JProgressBar , but none of its other features
changed with the 1.4 release. We've simply reviewed the old way of using
the component and introduced its new features under Merlin. You might also
consider using ProgressMonitor or
ProgressMonitorInputStream to monitor the progress of those
long tasks. Both take advantage of the JProgressBar
internally.
Resources
|
|