0

Here is my example code:

package javaapplication35;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.logging.Level;
import java.util.logging.Logger;
import static javaapplication35.ProgressBarExample.customProgressBar;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingWorker;

public class ProgressBarExample {

final static JButton myButton =new JButton("Start");
final static JProgressBar customProgressBar = new JProgressBar();
private static final JPanel myPanel = new JPanel();

public static void main(String[] args) {
    customProgressBar.setMaximum(32);
    customProgressBar.setStringPainted(true);
    myPanel.add(customProgressBar);
    myPanel.add(myButton);

    myButton.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e)
        {

            Thread firstly =new Thread(new Runnable (
            ) {
                @Override
                public void run() {
                    Calculations a = new  Calculations();
                    a.doCaculations();
                }
            });          

            Thread secondly =new Thread(new Runnable (
            ) {
                @Override
                public void run() {
                    JOptionPane.showMessageDialog(null,"just finished");
                }
            }); 

            firstly.start();
            try {
                firstly.join();
            } catch (InterruptedException ex) {
                Logger.getLogger(ProgressBarExample.class.getName()).log(Level.SEVERE, null, ex);
            }


            secondly.start(); 
        }
    });          

    JOptionPane.showMessageDialog(null, myPanel, "Progress bar test", JOptionPane.PLAIN_MESSAGE);

 }

}

class Calculations {
public void doCaculations() {

     new SwingWorker<Void, Void>() {
        @Override
        protected Void doInBackground() throws Exception {
            int value = 0;
            while (value < customProgressBar.getMaximum()) {
                Thread.sleep(250);
                value ++;
                customProgressBar.setValue(value);
            }
            return null;
        }
    }.execute();
}   

 private void doOtherStaff(){
    //more methods, that don't need to run in seperate threads,  exist
 }

}

There are 2 Threads. The firstly thread creates a Calculations class insance and then runs a doCaculations() method on it. The secondly thread pops-up a message.

The doCaculations() method in my "real" code performs some time consuming maths and in order to simulate the time spent I added that Thread.sleep(250);. I need to inform the user on the progress of the calculations so I am using the progressbar, that is updated by the doCaculations() method.

I am trying to make the code work in a way that the secondly thread runs after the firstly thread finishes. But I cannot make it work. What happens is that the pop-up message pops-up immediately (and that means that it's thread run before I want it to run).

Note:The "just finished" message is there just to test the code. In my "real" program a method would be in it's place. I am making this note because if I just wanted a message to show I could just place it in the end of the doCaculations() method, and everything would work fine.

I know I must be doing wrong with the Thread handling but I cannot find it. Any ideas?

PS: A thought: Actually the doCaculations() method has its own thread. So it runs "in a SwingWorker inside a Thread". Iguess the firstly.join(); works correctly. But after the doCaculations() method is called the fistrly thread is considered finished, and that's why the code goes on with the secondly thread, not knowing that the doCaculations() thread is still doing something.

geo
  • 517
  • 1
  • 9
  • 28

3 Answers3

2

Try

a.doCaculations();
a.join();

edit:
Since you are using SwingWorker my previous answer is incorrect, but, as in you comment, you've extended Thread, the following should work for you:

Thread a = new Calculations();
a.start();
a.join();

Don't forget, that you have to override run method in Calculations class, like:

class Calculations extends Thread {
    @Override
    public void run() {
        //your code here
    }    
}
qiGuar
  • 1,726
  • 1
  • 18
  • 34
  • I used 'extends Thread' for the class Calculations, in order to use the join method on a, but nothing changes. Could you give more details? – geo Feb 14 '14 at 10:36
  • Oh, yes, my mistake. Will update now my post to use with Thread. – qiGuar Feb 14 '14 at 11:06
  • Thanks for your answers. As I commented to another answer too, the class Calculations has other methods apart from 'doCaculations();, that might or might not run in their own threads. What should I change to your suggestion? – geo Feb 14 '14 at 11:48
  • If I understood you correctly, you'd like your progress bar to move as you do your calculations. I would put a method to update progress bar in the end of the cycle body. It would help, if you updated your post, so that we could see relevant working code. – qiGuar Feb 14 '14 at 11:57
  • It's like you understood. My actual calculations are Mathematics calculations too complex to post here. That's why I placed 'Thread.sleep(250);' to simulate the time spent, instead. But if you want to try a working example with real maths think you could place any time consuming mathematic formula you can imagine instead of 'Thread.sleep(250);'. But I don't think that what calculations are done matters. Only that they take time, and that as they progress I want to update the progressbar. – geo Feb 14 '14 at 12:09
  • What is the issue with `while (value < ustomProgressBar.getMaximum())` ? – qiGuar Feb 14 '14 at 12:19
  • I used this as a way to simulate a for loop. Could be for (int i=0; i<10000; i++){....}. In that case the ProgressBar maximum would have to be set to 10000 beforehand. – geo Feb 14 '14 at 12:36
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/47507/discussion-between-qiguar-and-geo) – qiGuar Feb 14 '14 at 13:07
2

In java you can use swingworker and in the done() method call your Dialog

In android you can use AsyncTask for calling the new thread and in the OnPostExecute method, call show message dialog.

Kevin Joymungol
  • 1,764
  • 4
  • 20
  • 30
1

Your Calculations class must extend SwingWorker. You do your calculations in doInBackground()

public class Calculations extends SwingWorker<Void, Void>{

    @Override
    protected Void doInBackground() throws Exception {
        System.out.println("Calculating.");
        Thread.sleep(3000);
        return null;
    }
}   

And in your actionPerformed() you use Calculations like this.

    public void actionPerformed(ActionEvent e)
    {
      //FISRT run method
      Calculations a = new  Calculations();
      a.execute(); // Start calculations
      try {
        a.get(); // Wait for calculations to finish
      } catch (InterruptedException | ExecutionException e1) {
        e1.printStackTrace();
      }
      //THEN inform that just finished
      JOptionPane.showMessageDialog(null,"just finished");
    }

EDIT: If you have multiple methods that you would like to run in a SwingWorker you can keep your code almost like it is. But only add these lines.

public class Calculations{
    protected void calculate() {
        SwingWorker sw = new SwingWorker(){
            @Override
            protected Object doInBackground() throws Exception {
                System.out.println("Calculating.");
                Thread.sleep(3000);
                return null;
            }
        };
        sw.execute(); //Start
        try {
            sw.get(); //Wait
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }
}

In each method of Calculations you create a new SwingWorker like you did and wait for it to finish by calling SwingWorker.get();

FuryFart
  • 2,304
  • 4
  • 27
  • 43
  • If I cannot use extends SwingWorker, because the class Calculations has other methods apart from 'doCaculations();'? – geo Feb 14 '14 at 10:45
  • Thanks for your answer. I modified my code using your suggestions. It does make the message dialog pop-up when the doCaculations() method finishes, but meanwhile the progress bar is not updated as it is supposed to be do. It just jumps to 100% when doCaculations() finishes – geo Feb 14 '14 at 11:49
  • I am not familiar with Swing, ProgressBar etc. but i suggest you to update the value of the ProgressBar or its Model BoundedRangeModel in the SwingWorker as the calculation precedes. – FuryFart Feb 14 '14 at 12:09
  • That's what how it worked at start. But in my actual software calculations take half a minute, and meanwhile the program freezes. Moreover and the progress bar doesn't update. It just jumps to 100% when all finishes. That's why I moved the calculations to another thread. – geo Feb 14 '14 at 12:21
  • SwingWorker.get() stops the UI Thread until the calculation finishes. So the progress bar is not updated. Blocking the UI Thread with SwingWorker.get() is wrong then. Instead of blocking the UI Thread it should be notified once the calculation is finished and only then show the dialog. – FuryFart Feb 14 '14 at 12:51