javaswingsortinganimationevent-dispatch-thread

Java swing repainting while computing: animating sorting algorithm


http://www.youtube.com/watch?v=M0cNsmjK33E

I want to develop something similar to the link above using Java Swing. I have the sorting method and did while repaint but when I triggered the sorting, instead of showing the bars slowly sorting itself, it freezes and then unfreezes when the array has been fully sorted.

How do I fix this? Edit: sorry forgot about the codes. its a very simple gui. and another class for sorting which sorts the whole array

public class SortGUI {
JFrame frame;
int frameWidth = 1000, frameHeight = 1000;
int panelWidth, panelHeight;
DrawPanel panel;
JPanel panel2;
JScrollPane scroll;
JViewport view;

static int[] S = new int[50000];

public static void main(String[] args) throws InterruptedException {
    SortGUI app = new SortGUI();
    initializeArray();        
    app.go(); 
}

public static void initializeArray()
{
         for (int i = 0; i < S.length; i++) {
     S[i] = (int) (Math.random() * 16581375);
     }
}

public void go() throws InterruptedException {
    //Frame
    frame = new JFrame();
    frame.setSize(frameWidth, frameHeight);
    frame.setVisible(true); 
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  

    //panel
    panel = new DrawPanel();
    scroll = new JScrollPane(panel,JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);


    //Layout
    frame.add(scroll);
    frame.addKeyListener(new keyListener());

    while(true)
    {               
        panel.repaint();
    }
   }


public class DrawPanel extends JPanel
{   
    public DrawPanel()
    {
        this.setPreferredSize(new Dimension(50000,930));
    }

    public void paintComponent(Graphics g) 
    {          
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, this.getWidth(), this.getHeight());
        for(int i = 0; i < S.length; i++)
        {
            int red = S[i] / 65025;
            int green = (S[i] > 65025)? S[i] % 65025 : 0;
            int blue = green;
            blue %= 255;
            green /= 255;

             g.setColor(new Color(red,green,blue));
            g.fillRect(i, 900 - (S[i] / 18500), 1, S[i] / 18500);
        }
    }
}

  public class keyListener implements KeyListener{


    public void keyTyped(KeyEvent ke) {

    }


    public void keyPressed(KeyEvent ke) {
      if(ke.getKeyChar() == '1')
      {
   sorter.bubbleSort(S);
      }
    }


    public void keyReleased(KeyEvent ke) { 
    }

  }
}

Solution

  • Note: I started writing this before the question was deleted

    Most likely your using some looping mechanism and praying that each iteration, the ui with be updated. That's a wrong assumption. The UI will not be update until the loop is finished. What you are doing is what we refer to as blocking the Event Dispatch Thread(EDT)

    See How to use a Swing Timer. Make "iterative" updates in the ActionListener call back. For instance, if you want to animate a sorting algorithm, you need to determine what needs to be updated per "iteration" of the timer callback. Then each iteration repaint the ui.

    So your Timer timer could look something like

    Timer timer  = new Timer(40, new ActionListener(){
        @Override
        public void actionPerformed(ActionEvent e) {
            if (sortingIsDone()) {
                ((Timer)e.getSource()).stop();
            } else {
                sortOnlyOneItem();
            }
            repaint();
        }
    });
    

    Your sortOnlyOneItem method should only, well, perform a sort for just one item. And have some sort of flag to check if the sorting is done, then stop the timer.


    Other notes:


    Here's a complete example. I'm glad you figured it out on your own. I was working on this example before I saw that you got it.

    enter image description here

    import java.awt.Dimension;
    import java.awt.Graphics;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.util.Arrays;
    import java.util.Collections;
    
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.SwingUtilities;
    import javax.swing.Timer;
    
    public class SelectionSortAnimate extends JPanel {
    
        private static final int NUM_OF_ITEMS = 20;
        private static final int DIM_W = 400;
        private static final int DIM_H = 400;
        private static final int HORIZON = 350;
        private static final int VERT_INC = 15;
        private static final int HOR_INC = DIM_W / NUM_OF_ITEMS;
    
        private JButton startButton;
        private Timer timer = null;
        private JButton resetButton;
    
        Integer[] list;
        int currentIndex = NUM_OF_ITEMS - 1;
    
        public SelectionSortAnimate() {
            list = initList();
    
            timer = new Timer(200, new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    if (isSortingDone()) {
                        ((Timer) e.getSource()).stop();
                        startButton.setEnabled(false);
                    } else {
                        sortOnlyOneItem();
                    }
                    repaint();
                }
            });
            startButton = new JButton("Start");
            startButton.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    timer.start();
                }
            });
            resetButton = new JButton("Reset");
            resetButton.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    list = initList();
                    currentIndex = NUM_OF_ITEMS - 1;
                    repaint();
                    startButton.setEnabled(true);
                }
            });
            add(startButton);
            add(resetButton);
        }
    
        public boolean isSortingDone() {
            return currentIndex == 0;
        }
    
        public Integer[] initList() {
            Integer[] nums = new Integer[NUM_OF_ITEMS];
            for (int i = 1; i <= nums.length; i++) {
                nums[i - 1] = i;
            }
            Collections.shuffle(Arrays.asList(nums));
            return nums;
        }
    
        public void drawItem(Graphics g, int item, int index) {
            int height = item * VERT_INC;
            int y = HORIZON - height;
            int x = index * HOR_INC;
            g.fillRect(x, y, HOR_INC, height);
        }
    
        public void sortOnlyOneItem() {
            int currentMax = list[0];
            int currentMaxIndex = 0;
    
            for (int j = 1; j <= currentIndex; j++) {
                if (currentMax < list[j]) {
                    currentMax = list[j];
                    currentMaxIndex = j;
                }
            }
    
            if (currentMaxIndex != currentIndex) {
                list[currentMaxIndex] = list[currentIndex];
                list[currentIndex] = currentMax;
            }
            currentIndex--;
        }
    
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            for (int i = 0; i < list.length; i++) {
                drawItem(g, list[i], i);
            }
        }
    
        @Override
        public Dimension getPreferredSize() {
            return new Dimension(DIM_W, DIM_H);
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    JFrame frame = new JFrame("Sort");
                    frame.add(new SelectionSortAnimate());
                    frame.pack();
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    }