Lup
Lup

Reputation: 27

Using Timer to repaint in the fixed time then continuing calculation

Currently, I am making a Java program for graph visualization Prim's algorithm in finding minimum spanning tree.

Here is the image of my program's output

while(condition){
    //Find the min vertex and min edges
    Vertex vertex = findMinVertex();
    Edge[] edges = findMinEdges();

    //Then, for each vertex and edges I found, I will change the color of 
    //them and pause the program for 3 seconds, so user can see how 
    //algorithm works.

    repaintAndPause(3000);
}
.
.
private void repaintAndPause(int time){
    long start = System.currentTimeMillis();
    long end = start + speed;

    //Here is the timer for repainting.
    Timer timer = new Timer(speed, new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e){
            GraphPanel.this.repaint();
        }
    });
    timer.setRepeats(false);
    timer.setDelay(0);
    timer.start();

    //And here is for pausing the program, a while loop without any commands.
    while(System.currentTimeMillis() < end){}
}

However, I don't know why but the program doesn't work. Yes, there are the pauses of program but, all the edges and vertices are just changed the color at the end of program. They aren't changed every 3 seconds.

Could someone please tell me where I did wrong?

Thank you and hope you have a nice day!

Upvotes: 1

Views: 53

Answers (1)

AJNeufeld
AJNeufeld

Reputation: 8695

Could someone please tell me where I did wrong?

Yes. You are putting a busy-loop in the Event Dispatching Thread.

    while(System.currentTimeMillis() < end){}

You code reads:

  1. do some calculation (busy)
  2. when done, post a "repaint" message, to redraw the panel when not busy
  3. continue being very busy doing nothing for 3 seconds
  4. continue being busy by repeating steps 1 through 4.

The Event Dispatching Thread never finishes processing the first "event" until the end of the algorithm, after the while (condition) loop finally finishes.

You want:

Timer timer = new Timer(speed, new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
       /* Code to perform one step of Prim's algorithm here */
       /* Change edge/vertex colour for step */
       /* Call timer.stop(), once done */

       GraphPanel.this.repaint();
    }
});
timer.setRepeats(true);
timer.setDelay(3000);
timer.start();

On every tick of the timer (once every 3 seconds), one step of the algorithm is performed.

Note this means that each step of the algorithm must run with any partial results stored into class members, so the the next step will be able to retrieve all the information it needs to continue. Stack variables can only be used inside one step; they cannot be used to hold inter-step values.

You could rework the algorithm to use a SwingWorker to run the calculation in its own background thread, and publish intermediate results when computed. The EDT could then repaint as intermediate results are produced. With a Thread#sleep() call, this background thread could delay production of intermediate results to once per 3 seconds.

Alternately, you could run the algorithm, and store multiple copies of the output, once for each 'step'. Then your Panel timer could simply show the output of the next step.

Upvotes: 1

Related Questions