Basic Indeterminate JProgress Bar Usage
Asked Answered
C

1

6

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);      <-- should be on the EDT
       progressBar.setIndeterminate(true);<-- should be on the EDT

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

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

  new MyWorker().execute();

}
Clariceclarie answered 4/5, 2012 at 3:42 Comment(2)
You should take a look at docs.oracle.com/javase/tutorial/uiswing/components/… even though it seems complicated. What you need to do is run the download in another thread (backgroundworker). Then the main (gui) thread does the progressBar animation. The way you are doing it is actually the other way around.Flavio
Please see Edit 2 to my answer to crrect some problems.Avicenna
A
10

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() {

       // ...
Avicenna answered 4/5, 2012 at 3:48 Comment(3)
can I just create a new thread object within the buttonClicked() function? 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.Clariceclarie
Thank you for your time so far. I'm going along with that approach and I'll mark the answer accepted once I get this working. It's a wee frustrating that building a simple GUI for my otherwise well constructed protocol library is turning out to take so much more time and code than I thought it originally would be..Clariceclarie
@B.VB: frustrating yes, but unavoidable, in any language. You can't step on the thread that is interacting with the user or drawing the GUI if you want your GUI to remain responsive, and so background threading for these situations is a must.Avicenna

© 2022 - 2024 — McMap. All rights reserved.