IBM Skip to main content
Search for:   within 
      Search help  
     IBM home  |  Products & services  |  Support & downloads   |  My account

developerWorks > Java technology
developerWorks
Magic with Merlin: Indeterminate progress bars
Discuss99 KBe-mail it!
Contents:
Basic progress bar usage
Indeterminate usage
Conclusion
Resources
About the author
Rate this article
Related content:
Java theory and practice: Hey, where'd my thread go?
Scheduling recurring tasks in Java applications
IBM developer kits for Java (downloads)
Subscriptions:
dW newsletters
dW Subscription
(CDs and downloads)
A subtle, but important update to JProgressBar

Level: Introductory

John Zukowski (mailto:jaz@zukowski.net?cc=&subject=Indeterminate progress bars)
President, JZ Ventures, Inc.
18 November 2003

Column iconDevelopers 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
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
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
Showing 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
Indeterminate

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

About the author
John Zukowski conducts strategic Java consulting with JZ Ventures, Inc., offers technical support through AnswerSquad.com, and is working with SavaJe Technologies to develop a next-generation mobile phone platform. His latest books are Mastering Java 2, J2SE 1.4 (Sybex, April 2002) and Learn Java with JBuilder 6 (Apress, March 2002). Reach him at mailto:jaz@zukowski.net?Subject=Magic with Merlin.


Discuss99 KBe-mail it!

What do you think of this document?
Killer! (5) Good stuff (4) So-so; not bad (3) Needs work (2) Lame! (1)

Send us your comments or click Discuss to share your comments with others.



developerWorks > Java technology
developerWorks
  About IBM  |  Privacy  |  Terms of use  |  Contact