This document outlines a proposal for indeterminate progress bars -- GUI components that look similar to normal progress bars and, like normal progress bars, use animation to show that a time-consuming operation is occurring. Unlike normal progress bars, indeterminate progress bars do not show the degree of completeness of the operation. This document has the following sections:
JProgressBar
constructors) will be determinate. You will be able to make any
JProgressBar
indeterminate using the setIndeterminate
method: pb.setIndeterminate(true);
An indeterminate progress bar animates constantly. You can stop the animation and clear the progress bar by making the progress bar determinate and setting the current value to the minimum. For example:
pb.setValue(pb.getMinimum()); pb.setIndeterminate(false);
You can switch from determinate to indeterminate mode, and vice versa, at any time.
When a progress bar is indeterminate, it ignores its model (a
BoundedRangeModel
). However, the model should exist and contain
legal data, since L&Fs that haven't been updated for indeterminate progress
bars are likely to use the model.
BasicProgressBarUI
class.
Methods for painting:
protected void paintIndeterminate(Graphics g, JComponent c)
protected void paintDeterminate(Graphics g, JComponent c)
Methods for setting and getting the index of the current frame of animation, and for getting the time interval between frames:
protected int getAnimationIndex()
protected void setAnimationIndex(int newValue)
protected void incrementAnimationIndex()
protected int getRepaintInterval()
Methods for starting and stopping custom animation threads:
protected void startAnimationTimer()
protected void stopAnimationTimer()
The paint
method that currently performs all painting for the
progress bar will delegate all its drawing to either
paintDeterminate
or paintIndeterminate
, depending on
the value of the progress bar's indeterminate property. When the progress bar is
in indeterminate mode, the paint
method (and thus the
paintIndeterminate
method) executes every repaint interval
milliseconds. (You can get the repaint interval by invoking
getRepaintInterval
.) The paintIndeterminate
method
should paint the progress bar to match the animation state, which is specified
by the getAnimationIndex
method.
If you override paintIndeterminate
, you'll probably also have to
override incrementAnimationIndex
so that it cycles correctly
through the valid values. The first value (representing the first drawing) is 0.
By convention, the second is 1, the third is 2, and so on. The last legal value
is, by convention, the total number of drawings in the animation cycle, minus
one. To determine the total number of drawings, you may need to take into
account the repaint interval (returned by getRepaintInterval
) and
perhaps the component size. As the "by convention" implies, you can implement
the animation index to have any meaning and values you wish, as long as zero
indicates the beginning of the animation cycle.
If you don't want to use the animation thread we provide, you must override
the two xxxAnimationTimer
methods. You can then provide
your own implementation that periodically increments the animation index and
invokes repaint
on the progress bar.
Converting an existing L&F to indeterminate progress bars is relatively
straightforward. If the L&F's progress bar UI class doesn't override
paint
(or does but also invokes super.paint
), then
support for indeterminate progress bars is automatic. WindowsProgressBarUI,
MotifProgressBarUI, and MetalProgressBarUI are in this lucky camp.
If the L&F's progress bar UI class is a subclass of
BasicProgressBarUI
and overrides paint
without
invoking the superclass version, then determinate mode will still work, but
indeterminate mode will look the same as determinate mode.
Existing drawing code should be moved out of the paint
method
and into the new paintDeterminate
method. Code for indeterminate
painting should go in the new paintIndeterminate
method. If at all
possible, the paint
method should not be overridden unless it
invokes super.paint
. The reason: the
BasicProgressBarUI
implementation of the paint
method
may work with the default animation thread to enhance performance and behavior.
The Mac look and feel (both the no-longer-maintained Sun version and the
Apple version) is an example of a look and feel that overrides
paint
without invoking the superclass version.
If you already have a thread scheme for indeterminate painting, you can
continue to use that scheme by overriding startAnimationTimer
and
stopAnimationTimer
. Or you can just delete your thread code and use
our scheme.
BasicProgressBarUI
class contains most of our implementation of
indeterminate progress bars. Aside from the drawing code, most of the code is in
two private inner classes: Animator
, which implements the animation
thread, and PropertyChangeHandler
, which listens for changes to and
from indeterminate mode.
The Animator
implements the default animation thread, using the
Swing Timer
class. An Animator
instance is created if necessary by the
BasicProgressBarUI
startAnimationTimer
method, which
the property handler invokes when the progress bar switches to indeterminate
mode. When the progress bar is indeterminate, the Animator
timer
fires an action event once every repaint interval milliseconds.
Animator
's action event handler invokes
incrementAnimationIndex
, followed by repaint
(which
causes paintIndeterminate
to run). Repaint interval is a
UI default that's checked by startAnimationTimer
.
The PropertyChangeHandler
registers itself as a property
listener on the progress bar. When it detects the "indeterminate" property
changing, the handler notes the change and invokes either
stopAnimationTimer
or startAnimationTimer
.
javax.swing.JProgressBar
: public void setIndeterminate(boolean newValue): /** * Sets the indeterminate property of the progress bar. * An indeterminate progress bar continuously displays animation * indicating that an operation of unknown length is occurring. * By default, this property is false. * * for examples of using indeterminate progress bars. * * @param newValue true if the progress bar * should change to indeterminate mode; * false if it should revert to normal * * @see #isIndeterminate * * @since 1.4 */ public boolean isIndeterminate(): /** * Returns the value of the indeterminate property. * By default, the progress bar is determinate * and this method returns false. * * @return true if the progress bar is indeterminate; * otherwise, false * @see #setIndeterminate * * @since 1.4 */
In javax.swing.plaf.basic.BasicProgressBarUI
:
protected void paintIndeterminate(Graphics g, JComponent c):
/**
* All-purpose paint method that should do the right thing for almost all
* bouncing-box indeterminate progress bars.
* You can customize the painting by setting a few values in
* the defaults table.
* Naturally, override this if you are making a barber-pole,
* circular, or semi-circular progress bar.
*
* @see #paintDeterminate
*
* @since 1.4
*/
protected void paintDeterminate(Graphics g, JComponent c)
[contains the same code and comment as in the 1.3 paint method]:
/**
* All-purpose paint method that should do the right thing for most
* linear, determinate progress bars. By setting a few values in
* the defaults
* table, things should work just fine to paint your progress bar.
* Naturally, override this if you are making a circular or
* semi-circular progress bar.
*
* @see #paintIndeterminate
*
* @since 1.4
*/
protected int getAnimationIndex():
/**
* Gets the index of the current animation frame.
*
* @since 1.4
*/
protected void setAnimationIndex(int newValue):
/**
* Sets the index of the current animation frame
* to the specified value.
*
* @since 1.4
*/
protected void incrementAnimationIndex():
/**
* Increments the index of the current animation frame,
* making sure that the value is not too large.
* This method is invoked by the default animation thread.
* If the value would be too large,
* this method sets the index to 0.
* Subclasses often need to override this method
* to ensure that the index does not go over
* the number of frames needed for the particular
* progress bar instance.
*
* @since 1.4
*/
protected int getRepaintInterval():
/**
* Returns the number of milliseconds between
* successive invocations of paintIndeterminate
.
* The value is meaningful
* only if the progress bar is in indeterminate mode.
* The default animation thread implementation
* updates the repaint interval
* every time the progress bar enters indeterminate mode,
* setting it to the value specified by
* the "ProgressBar.repaintInterval" UI default.
*
* @since 1.4
*/
protected void startAnimationTimer():
/**
* Starts the animation thread, creating and initializing
* it if necessary. This method is invoked when
* the progress bar changes to
* indeterminate mode.
* If you implement your own animation thread,
* you must override this method.
*
* @since 1.4
*/
protected void stopAnimationTimer():
/**
* Stops the animation thread. This method is invoked when
* the progress bar changes from
* indeterminate to determinate mode
* and when this UI is uninstalled.
* If you implement your own animation thread,
* you must override this method.
*
* @since 1.4
*/