Sometimes a task running within a program might take a while to complete. A user-friendly program provides some indication to the user that the task is occurring, how long the task might take, and how much work has already been done. One way of indicating work, and perhaps the amount of progress, is to use an animated image.
Another way of indicating work is to set the wait cursor, using the Cursor
class and the Component
-defined setCursor
method. For example, the following code makes the wait cursor be displayed when the cursor is over container
(including any components it contains that have no cursor specified):
container.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
To convey how complete a task is, you can use a progress bar like this one:
Sometimes you can't immediately determine the length of a long-running task, or the task might stay stuck at the same state of completion for a long time. You can show work without measurable progress by putting the progress bar in indeterminate mode. A progress bar in indeterminate mode displays animation to indicate that work is occurring. As soon as the progress bar can display more meaningful information, you should switch it back into its default, determinate mode. In the Java look and feel, indeterminate progress bars look like this:
Swing provides three classes to help you use progress bars:
JProgressBar
ProgressMonitor
ProgressMonitorInputStream
getProgressMonitor
and configure it as described in How to Use Progress Monitors.
After you see a progress bar and a progress monitor in action, Deciding Whether to Use a Progress Bar or a Progress Monitor can help you figure out which is appropriate for your application.
Using Determinate Progress BarsHere's a picture of a small demo application that uses a progress bar to measure the progress of a task that runs in its own thread:
The following code, from ProgressBarDemo.java
, creates and sets up the progress bar:
//Where member variables are declared: JProgressBar progressBar; ... //Where the GUI is constructed: progressBar = new JProgressBar(0, task.getLengthOfTask()); progressBar.setValue(0); progressBar.setStringPainted(true);
The constructor that creates the progress bar sets the progress bar's minimum and maximum values. You can also set these values with setMinimum
and setMaximum
. The minimum and maximum values used in this program are 0 and the length of the task, which is typical of many programs and tasks. However, a progress bar's minimum and maximum values can be any value, even negative. The code snippet also sets the progress bar's current value to 0.
The call to setStringPainted
causes the progress bar to display, within its bounds, a textual indication of the percentage of the task that has completed. By default, the progress bar displays the value returned by its getPercentComplete
method formatted as a percent, such as 33%. Alternatively, you can replace the default with a different string by calling setString
. For example,
if (/*...half way done...*/) progressBar.setString("Half way there!");
When the user clicks Start, an instance of the inner class Task
is created and executed.
public void actionPerformed(ActionEvent evt) { startButton.setEnabled(false); setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); done = false; task = new Task(); task.addPropertyChangeListener(this); task.execute(); }
Task
is a subclass of javax.swing.SwingWorker
. The Task
instance does three important things for ProgressBarDemo
:
doInBackground
in a separate thread. This is where the long-running task is actually executed. Using a background thread instead of the event-dispatching thread prevents the user interface from freezing while the task is running.done
method in the event-dispatching thread.progress
, that is updated to indicate the progress of the task. The propertyChange
method is invoked each time progress
changes.See Worker Threads and SwingWorker in Concurrency in Swing for more information about SwingWorker
.
The background task in ProgressBarDemo
simulates a real task by reporting random amounts of progress at random intervals. The propertyChange
method responds to changes in the task's progress
property by updating the progress bar:
public void propertyChange(PropertyChangeEvent evt) { if (!done) { int progress = task.getProgress(); progressBar.setValue(progress); taskOutput.append(String.format( "Completed %d%% of task.\n", progress)); }
When the background task is complete, the task's done
method resets the progress bar:
public void done() { //Tell progress listener to stop updating progress bar. done = true; Toolkit.getDefaultToolkit().beep(); startButton.setEnabled(true); setCursor(null); //turn off the wait cursor progressBar.setValue(progressBar.getMinimum()); taskOutput.append("Done!\n"); }
Note that the done
method sets the done
field to true
, preventing propertyChange
from making further updates to the progress bar. This is necessary because the final updates to the progress
property may occur after done
is invoked.
In ProgressBarDemo2
indeterminate mode is set until actual progress begins:
public void propertyChange(PropertyChangeEvent evt) { if (!done) { int progress = task.getProgress(); if (progress == 0) { progressBar.setIndeterminate(true); taskOutput.append("No progress yet\n"); } else { progressBar.setIndeterminate(false); progressBar.setString(null); progressBar.setValue(progress); taskOutput.append(String.format( "Completed %d%% of task.\n", progress)); } } }
The other changes in the code are related to string display. A progress bar that displays a string is likely to be taller than one that doesn't, and, as the demo designers, we've arbitrarily decided that this progress bar should display a string only when it's in the default, determinate mode. However, we want to avoid the layout ugliness that might result if the progress bar changed height when it changed modes. Thus, the code leaves in the call to setStringPainted(true)
but adds a call to setString("")
so that no text will be displayed. Later, when the progress bar switches from indeterminate to determinate mode, invoking setString(null)
makes the progress bar display its default string.
One change we did not make was removing the call to progressBar.setValue
from the progress
event handler. The call doesn't do any harm because an indeterminate progress bar doesn't use its value property, except perhaps to display it in the status string. In fact, keeping the progress bar's data as up-to-date as possible is a good practice, since some look and feels might not support indeterminate mode.
Now let's rewrite ProgressBarDemo to use a progress monitor instead of a progress bar. Here's a picture of the new demo program, ProgressMonitorDemo:
Try this:A progress monitor cannot be used again, so a new one must be created each time a new task is started. This program creates a progress monitor each time the user starts a new task with the Start button.
Here's the statement that creates the progress monitor:
progressMonitor = new ProgressMonitor(ProgressMonitorDemo.this, "Running a Long Task", "", 0, task.getLengthOfTask());
This code uses ProgressMonitor
's only constructor to create the monitor and initialize several arguments:
null
for this argument, the note is omitted from the dialog. The example updates the note each time the progress
property changes. It updates the monitor's current value at the same time:
int progress = task.getProgress(); String message = String.format("Completed %d%%.\n", progress); progressMonitor.setNote(message); progressMonitor.setProgress(progress); taskOutput.append(message);
By default, a progress monitor waits a minimum of 500 milliseconds before deciding whether to pop up the dialog. It also waits for the progress to become more than the minimum value. If it calculates that the task will take more than 2000 milliseconds to complete, the progress dialog appears. To adjust the minimum waiting period, invoke setMillisToDecidedToPopup
. To adjust the minimum progress time required for a dialog to appear, invoke setMillisToPopup
.
By the simple fact that this example uses a progress monitor, it adds a feature that wasn't present in the version of the program that uses a progress bar: The user can cancel the task by clicking the Cancel button on the dialog. Here's the code in the example that checks to see if the user canceled the task or if the task exited normally:
if (progressMonitor.isCanceled() || task.isDone()) { progressMonitor.close(); Toolkit.getDefaultToolkit().beep(); if (progressMonitor.isCanceled()) { task.cancel(true); taskOutput.append("Task canceled.\n"); } else { taskOutput.append("Task completed.\n"); } startButton.setEnabled(true); }
Note that the progress monitor doesn't itself cancel the task. It provides the GUI and API to allow the program to do so easily.
Deciding Whether to Use a Progress Bar or a Progress MonitorUse a progress bar if:
Use a progress monitor if:
isCanceled
method to find out if the user pressed the Cancel button.setNote
method so that the task can provide further information about what it's doing. For example, an installation task might report the name of each file as it's installed.If you decide to use a progress monitor and the task you are monitoring is reading from an input stream, use the ProgressMonitorInputStream
class.
The following tables list the commonly used API for using progress bars and progress monitors. Because JProgressBar
is a subclass of JComponent
, other methods you are likely to call on a JProgressBar
are listed in The JComponent Class. Note that ProgressMonitor
is a subclass of Object
and is not a visual component.
The API for monitoring progress falls into these categories:
This following examples use JProgressBar
or ProgressMonitor
.
ProgressBarDemo
This section Uses a basic progress bar to show progress on a task running in a separate thread. ProgressBarDemo2
This section Uses a basic progress bar to show progress on a task running in a separate thread. ProgressMonitorDemo
This section Modification of the previous example that uses a progress monitor instead of a progress bar.
If you are programming in JavaFX, see Progress Bar and Progress Indicator.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4