Basic Indeterminate JProgress Bar Usage

Bill VB picture Bill VB · May 4, 2012 · Viewed 18.1k times · Source

I simply want to have an indeterminate JProgressBar animate in the bottom left corner of my frame when a long download is being done.

I've looked through many tutorials, none of which are clear to me. I simply want to have it animate while the file is being downloaded in the background. Each way I've tried this, it doesn't animate the progress bar until after the download is done.

I need help knowing where to place my download() call.

class MyFunClass extends JFrame {
  JProgressBar progressBar = new JProgressBar();

  public void buttonClicked() {
    progressBar.setVisible(true);
    progressBar.setIndeterminate(true);

    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        progressBar.setIndeterminate(true);
        progressBar.setVisible(true);

        // Do I do my download() in here??

    }});

    // Do download() here???
    progressBar.setVisible(false);
  }
}

Thanks in advance!



Solution

Edit: For those who have a similar issue to me in the future, this is the basic solution for a basic problem. This isn't my code verbatim, but a general sketch. Inside buttonClicked():

public void buttonClicked() {
  class MyWorker extends SwingWorker(String, Object) {
     protected String doInBackground() {
       progressBar.setVisible(true);
       progressBar.setIndeterminate(true);

       // Do my downloading code
       return "Done."
     }

     protected void done() {
        progressBar.setVisible(false)
     }
  }

  new MyWorker().execute();

}

Answer

Hovercraft Full Of Eels picture Hovercraft Full Of Eels · May 4, 2012

Your current code shows no creation of a background thread, but rather it shows you trying to queue code on the Swing thread from within the Swing thread which doesn't make sense for this problem (although there are occasional times when you may want to do this, but again, not here). The only way for this to succeed is to use a background thread. The standard Oracle JProgressBar tutorial and Concurrency in Swing goes through all of this.

The basic thing is that you must update the JProgressBar from the Swing Thread will doing your long-running process in the background thread, such as that provided by a SwingWorker object. There are too many details for us to review all here, and so all I can do is provide a link, but we'll be happy to help you understand the details once you review the tutorials. Just check the tutorials and come on back with your specific questions if you're still stuck.

Edit 1
You state:

can I just create a new thread object within the buttonClicked() function?

Yes, you can create a SwingWorker object inside of the buttonClicked() method and execute it there.

The thing is I have my API and library of all the functionality that I'm developing the GUI to, and it seems like a longwinded workaround to wrap that function call in a thread.

Sorry, but I have no idea what you're saying here or what issues you think threading will cause. The buttonClicked() method likely must run on the EDT and not in a background thread.

Also note that in most of my more complex Swing GUI's, I often do my file downloading in a different (model) object and create my SwingWorker in a different object still (control) from the GUI object (the view). It may seem more complicated to do it this way, but it's a lot easier to debug, maintain and enhance my program when I do it this way, especially when I heavily use interfaces to allow me to test all program components in isolation.

Edit 2
Some corrections to your solution post. You posted:

public void buttonClicked() {
  class MyWorker extends SwingWorker(String, Object) {
     protected String runInBackground() {
       progressBar.setVisible(true);
       progressBar.setIndeterminate(true);

       // ...

which has problems

  • it's doInBackground(), not runInBackground()
  • but more importantly, you're making Swing calls from within a background thread, something that should never be done (unless the call is thread safe, and even then...).

So change it:

public void buttonClicked() {
  progressBar.setVisible(true);
  progressBar.setIndeterminate(true);
  class MyWorker extends SwingWorker<String, Void> {
     protected String doInBackground() {

       // ...