0

So, I got this working with ONE JProgressBar. How do I update two individual progress bars? I'm executing a download in the doInBackground() worker thread/swingworker method. I want to update two bars, the first is a total, the second is a section of the total. For example, 21/100 //total 21/50 /halvsies

I already asked a question here and finally got this threading thing figured out. I'm now looking to up the ante so to speak and get two progressbars going. Thanks for reading, ~Kyte

Community
  • 1
  • 1
Kyte
  • 834
  • 2
  • 12
  • 27

4 Answers4

2

You could take advantage of the property change support by firing a new property change event when you update the "section" progress.

There are a number of ways you could achieve, depending on the information you have available.

You could call it directly using something like

firePropertyChange("sectionProgress", oldProgress, newProgress);

Now obviously, you run into the dreaded ETD sync issue, as the firePropertyChange method is not thread safe.

But you could create a simple Updater class that implements Runnable inside your SwingWorker

private class TwoWorker extends SwingWorker<Double, Double> {

    protected Double doInBackGround() throws Exception {

        //... Do some work

        SwingUtilities.invokeLater(new Updater(oldProgress, newProgress));

    }

    public class Updater implements Runnable {

        private int oldProgress;
        private int newProgress;

        public Updater(int oldProgress, int newProgress) {
            this.oldProgress = oldProgress;
            this.newProgress = newProgress;
        }

        public void run() {
            firePropertyChange("sectionProgress", oldProgress, newProgress);
        }   

    }

}
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
2

You could take advantage of the SwingWorker<T,V> type parameter V that is used for carrying out intermediate results in publish and process methods. For example:

class DownloadProgress {
    private int totalProgress;
    private int currentTaskProgress;

    public DownloadProgress(int totalProgress, int currentTaskProgress) {
        this.totalProgress = totalProgress;
        this.currentTaskProgress = currentTaskProgress;
    }
}

public class DownloadWorker extends SwingWorker<Double, DownloadProgress> {

    @Override
    protected Double doInBackground() throws Exception {
        ...
        publish(new DownloadProgress(1, 50));
    }

    @Override
    protected void process(List<DownloadProgress> progressList) {
        for (DownloadProgress p : progressList){
            //update progress bars
        }
    }
}
tenorsax
  • 21,123
  • 9
  • 60
  • 107
2

Here is a quick example (@Max already said that):

enter image description here

import java.awt.*;
import java.awt.event.*;
import java.util.List;
import java.util.Random;
import javax.swing.*;
public class TwoProgressBarsTest {
  private final JTextArea area     = new JTextArea();
  private final JPanel statusPanel = new JPanel(new BorderLayout(0,2));
  private final JButton runButton  = new JButton(new RunAction());
  private SwingWorker<String, DownloadProgress> worker;
  public JComponent makeUI() {
    area.setEditable(false);
    JPanel p = new JPanel(new BorderLayout(5,5));
    p.add(new JScrollPane(area));
    p.add(runButton, BorderLayout.NORTH);
    p.add(statusPanel, BorderLayout.SOUTH);
    p.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    return p;
  }
  class RunAction extends AbstractAction {
    public RunAction() {
      super("run");
    }
    @Override public void actionPerformed(ActionEvent evt) {
      final JProgressBar bar1 = new JProgressBar();
      final JProgressBar bar2 = new JProgressBar();
      runButton.setEnabled(false);
      statusPanel.add(bar1, BorderLayout.NORTH);
      statusPanel.add(bar2, BorderLayout.SOUTH);
      statusPanel.revalidate();
      worker = new SwingWorker<String, DownloadProgress>() {
        @Override public String doInBackground() {
          int current = 0;
          int lengthOfTask = 12; //filelist.size();
          publish(new DownloadProgress(Target.LOG, "Length Of Task: "+lengthOfTask));
          publish(new DownloadProgress(Target.LOG, "\n-------------------------\n"));
          while(current<lengthOfTask && !isCancelled()) {
            if(!bar1.isDisplayable()) {
              return "Disposed";
            }
            try {
              convertFileToSomething();
            } catch(InterruptedException ie) {
              return "Interrupted";
            }
            publish(new DownloadProgress(Target.LOG, "*"));
            publish(new DownloadProgress(Target.TOTAL, 100*current/lengthOfTask));
            current++;
          }
          publish(new DownloadProgress(Target.LOG, "\n"));
          return "Done";
        }
        private final Random r = new Random();
        private void convertFileToSomething() throws InterruptedException {
          int current = 0;
          //long lengthOfTask = file.length();
          int lengthOfTask = 10+r.nextInt(50);
          while(current<=lengthOfTask && !isCancelled()) {
            int iv = 100 * current / lengthOfTask;
            Thread.sleep(20); // dummy
            publish(new DownloadProgress(Target.FILE, iv+1));
            current++;
          }
        }
        @Override protected void process(List<DownloadProgress> chunks) {
          for(DownloadProgress s: chunks) {
            switch(s.component) {
            case TOTAL:
              bar1.setValue((Integer)s.value);
              break;
            case FILE:
              bar2.setValue((Integer)s.value);
              break;
            case LOG:
              area.append((String)s.value);
              break;
            }
          }
        }
        @Override public void done() {
          runButton.setEnabled(true);
          statusPanel.removeAll();
          statusPanel.revalidate();
          String text = null;
          if(isCancelled()) {
            text = "Cancelled";
          } else {
            try {
              text = get();
            } catch(Exception ex) {
              ex.printStackTrace();
              text = "Exception";
            }
          }
          area.append(text);
          area.setCaretPosition(area.getDocument().getLength());
        }
      };
      worker.execute();
    }
  }
  public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
      @Override public void run() { createAndShowGUI(); }
    });
  }
  public static void createAndShowGUI() {
    JFrame f = new JFrame();
    f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    f.getContentPane().add(new TwoProgressBarsTest().makeUI());
    f.setSize(320, 240);
    f.setLocationRelativeTo(null);
    f.setVisible(true);
  }
}
enum Target { TOTAL, FILE, LOG }
class DownloadProgress {
  public final Object value;
  public final Target component;
  public DownloadProgress(Target component, Object value) {
    this.component = component;
    this.value = value;
  }
}
aterai
  • 9,658
  • 4
  • 35
  • 44
2

You could go the bare-metal route:

Whenever you want it to be updated:

EventQueue.invokeLater(new Runnable(){
    public void run(){
        firstProgressBar.setValue(someInt);
        secondProgressBar.setValue(someOtherInt);
    }
});
Charlie
  • 8,530
  • 2
  • 55
  • 53
  • This was the quickest (and most reliable) fix given how I have my class set up. Thanks to all who commented! – Kyte Jul 25 '12 at 02:45