Search code examples
javaswingevent-dispatch-thread

How do I repaint each iteration of a sorting algorithm before the algorithm ends?


I am new to using Java Swing and working on a sorting algorithm visualizer. I have set out the rectangles and gave the basics done just for testing, but I ran into some difficulties. I wanted to use the repaint() function to repaint the rectangles every time I changed it after one iteration of sort, but the program does not seem to be doing it step by step, rather it skips to the array fully sorted. I tried adding a delay but that makes the program not work at all.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Random;
import java.util.concurrent.TimeUnit;

@SuppressWarnings("serial")
class Panel extends JPanel implements ActionListener, KeyListener {
    // All Global varaibles
    private Timer myTimer= new Timer( 30, this );
    int width = 100;
    int height_bounds = 400;
    Random rand = new Random();
    int[] height = new int[width];

    public Panel(){
        for (int i = 0; i < width; i++) {
            height[i] = rand.nextInt(height_bounds)+50;
        }
        myTimer.start();
    }

    public void paintComponent(Graphics gr){
            super.paintComponent(gr);
            //setBackground(new Color(0,0,0));
            for (int i=0; i<width; i++) {
                gr.drawRect(i*10+81, 740-height[i], 4, height[i]);
            }
    }

    @Override
    public void keyPressed(KeyEvent ev) {}
    @Override
    public void keyReleased(KeyEvent arg0) {}
    @Override
    public void keyTyped(KeyEvent arg0) {}
    @Override
    public void actionPerformed(ActionEvent e) {
            
        for (int i = 0; i < width; i++){
            for (int j = 0; j < width-1; j++){
                if (height[j] > height[j+1]) 
                { 
                    // swap arr[j+1] and arr[i] 
                    int temp = height[j]; 
                    height[j] = height[j+1]; 
                    height[j+1] = temp;
                } 
            }
          repaint();
        }
        
    }
}

Solution

  • If you are going doing your sorting in actionPerformed then you are blocking UI from beeing redrawn since it is executed by the exact same thread that would repaing UI for you. Move processing to separate thread and schedule repaint from therem eg

    public void actionPerformed(ActionEvent e) {
        new Thread(()=>{    
        for (int i = 0; i < width; i++){
            for (int j = 0; j < width-1; j++){
                if (height[j] > height[j+1]) 
                { 
                    // swap arr[j+1] and arr[i] 
                    int temp = height[j]; 
                    height[j] = height[j+1]; 
                    height[j+1] = temp;
                } 
            }
          SwingUtils.invokeLater(()=>repain());
          Thread.sleep(500); // add some meaningfull value
        }
        }).start();
    }
    

    Obviously you should use thread pool instead of creating new tread, block multiple thread starting at the same time after every click and probably use SwingWorker for that, but it should give you an idea of the flow.