0

I have a Bubble Sort algorithm which I want to visualize with SWING in a JFrame. It goes well, if I call the function in a standalone position, but doesn't if I call it from a JButton's ActionListener. (Actually it works, only it doesn't render the array continously - as it should and does in the other case - only in the beginning and the end of the sorting.) Any idea why?

GUI and Main class:

public class sortings {
    
    public static void main(String[] args) {
        
        //create, fill up and print array of 100 elements
        int[] arr = new int[100];
        
        for (int i=0; i<100; i++) {
            int element = ThreadLocalRandom.current().nextInt(1, 100);
            arr[i] = element;
        }
        
        for (int i=0; i<arr.length; i++) {
            System.out.print(arr[i] + ",");
        }
        
        //set up GUI
        Frame frame = new Frame();
        JPanel menuPanel = new JPanel();
        JButton button = new JButton("sort");
        
        Container contentPane = frame.getContentPane();
        contentPane.setPreferredSize(new Dimension(600, 450));
        frame.setLayout(new GridLayout(2,1));
        
        menuPanel.setSize(600, 50);
        menuPanel.add(button);
        
        BubbleSort bs = new BubbleSort(arr);
        
        frame.add(menuPanel);
        frame.add(bs);
        frame.pack();
        
        button.addActionListener((ActionEvent e) -> {
            bs.bubbleSort(); // <- if called from here it renders the array only in the beginning and the end of sorting
        });
        
        bs.bubbleSort(); // <- if called from here it renders the array during sorting continously, as it should
               
        //BubbleSort bs = new BubbleSort(arr);
        //bs.bubbleSort();
    }
}

BubbleSort class and method:

public class BubbleSort extends JPanel {
    
    int[] arr;
    
    public BubbleSort(int[] arr) {
        setSize(600, 400);
        this.arr = arr;
    }
    
    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        for (int i = 0; i < this.arr.length; i++) {
            g.drawLine(i*2+50,50, i*2+50, 50+this.arr[i]);
        }
    }
    
    public void bubbleSort() {
            
        int temp;
        
        for (int i=0; i < 100; i++) {
            for (int j=0; j < this.arr.length-1; j++) {
                if (this.arr[j] < this.arr[j+1]) {
                    temp = this.arr[j];
                    this.arr[j] = this.arr[j+1];
                    this.arr[j+1] = temp;
                    
                    try
                    {
                        Thread.sleep(5);
                    }
                    catch(InterruptedException ex)
                    {
                        Thread.currentThread().interrupt();
                    }
                    
                    repaint();
                }
            }
        }
    }
}
  • If you call `bs.bubblesort()` from the ActionListener it will block the EventDispatchThread. As long as that thread is blocked no other events will be processed. Specifically there will be no UI updates. If you call `bs.bubblesort()` from the main thread the EventDispatchThread can run and can update the UI. – Thomas Kläger Jan 16 '21 at 18:14
  • Thanks Thomas! Is there any workaround this? I mean I really would like to call this function via that button. – Sebestyén Szabó Jan 16 '21 at 18:29
  • 1
    The solution is to start a separate thread from the ActionListener and run the `bs.bubblesort();` in that separate thread. – Thomas Kläger Jan 16 '21 at 18:33
  • @SebestyénSzabó, It may work with a Thread but that is not the (complete) solution. Swing components should be update on the Event Dispatch Thread (EDT) otherwise you can have random problems. See: [Bubble Sort Animation](https://stackoverflow.com/questions/64196198/bubble-sort-animation) for two approaches to solving the problem so that the code is executed correctly on the EDT. – camickr Jan 16 '21 at 21:04

0 Answers0