How to use SwingWorker with Java Sorting classes e.g. Bubble Sort

53 Views Asked by At

I am trying to create a Java Sorting Visualizer using SwingWorker to run the sorting algorithm step by step in a separate thread, and publish intermediate states to update the UI (I am going to say using the Event Dispatch Thread) but I am having trouble understanding how to use SwingWorker for this. Below is my code:


    package visualizer;
    
    import visualizer.ui.SortingLogic;
    import visualizer.ui.SortingWindow;
    
    import javax.swing.*;
    import java.util.Arrays;
    
    public class Main {
        public static void main(String[] args) {
            SwingUtilities.invokeLater(() -> {
               new SortingWindow();
    
            });
    
    
            //System.out.println("Hello world!");
        }
    }
    package visualizer.ui;
    
    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.util.Arrays;
    
    public class SortingWindow {
        int [] arrayToSort;
        SortingVisualizer visualizer;
        SortingLogic sortingLogic;
        JButton startButton, stopButton, resetButton;
    
        public SortingWindow(){
            //System.out.println("SortingWindow is being called");
            initiliaze();
        }
        private void initiliaze() {
            JFrame frame = new JFrame();
            frame.setTitle("Sorting Visualizer");
            frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
            frame.setSize(1000, 800);
            frame.setLocationRelativeTo(null);
            frame.setResizable(true);
    
            JPanel panelBottom = new JPanel();
            panelBottom.setLayout(new FlowLayout(FlowLayout.CENTER, 10, 5));
            frame.add(panelBottom, BorderLayout.PAGE_END);
            panelBottom.setBackground(Color.ORANGE);
            //Creates Panel that holds Start and Reset Buttons
    
            /*JPanel panelTop = new JPanel();
            panelTop.setLayout(new FlowLayout(FlowLayout.CENTER, 10, 5));
            frame.add(panelTop, BorderLayout.PAGE_START);
            panelTop.setBackground(Color.blue);
            //Creates top Panel that holds currently sorting*/
    
            String [] sortOptions = {"Bubble Sort", "Selection Sort", "Insertion Sort",
                    "Merge Sort", "Quick Sort", "Heap Sort", "Counting Sort", "Radix Sort",
                    "Bucket Sort", "Shell Sort"};
            JComboBox sortingOptionsDropdown = new JComboBox(sortOptions);
            panelBottom.add(sortingOptionsDropdown);
            //Adds the drop-down menu to the bottom panel
            /*https://docs.oracle.com/javase/tutorial/uiswing/components/combobox.html*/
    
            startButton = new JButton("Start");
            stopButton = new JButton("Stop");
            resetButton = new JButton("Reset");
            panelBottom.add(startButton);
            panelBottom.add(stopButton);
            panelBottom.add(resetButton);
            //Adds buttons for starting and stopping to JPanel
    
            stopButton.setEnabled(false);
            resetButton.setEnabled(false);
    
            /*JLabel currentlySorting = new JLabel("Currently Sorting");
            panelTop.add(currentlySorting);
            currentlySorting.setText("Currently Sorting: " + sortingOptionsDropdown.getSelectedItem()
                    + " \tTime Elapsed: ");
            currentlySorting.setForeground(Color.gray);
            currentlySorting.setLayout(new FlowLayout(FlowLayout.LEFT, 10, 5));
            //Adds labels for Currently sorting to the top label*/
    
    
    
            sortingLogic = new SortingLogic();
            arrayToSort = sortingLogic.generateRandomIntArray(5, 1000, 30);
            visualizer = new SortingVisualizer(arrayToSort);
            sortingLogic.setArrayToSort(arrayToSort);
            sortingLogic.setVisualizer(visualizer);
    
            System.out.println(Arrays.toString(arrayToSort));
            //initializes a random array
    
            frame.getContentPane().add(visualizer);
            startButton.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    String selectedAlgorithm = (String) sortingOptionsDropdown.getSelectedItem();
                    if (selectedAlgorithm != null){
                        if (!sortingLogic.isSorted(arrayToSort)) {
                            sortingLogic.setSortingAlgorithm(selectedAlgorithm);
                            sortingLogic.startSorting();
                        }else {
                            System.out.println("Array is sorted");
                        }
                    }
                    startButton.setEnabled(false);
                    stopButton.setEnabled(true);
                    resetButton.setEnabled(true);
                    //System.out.println("Start has been clicked");
                }
            });//Performs sort that is selected under dropdownOptions and checks that it is not null or already sorted
            stopButton.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    sortingLogic.stopSorting();
                }
            });
            resetButton.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    //System.out.println("Reset has been clicked");
                    sortingLogic.stopSorting(); // Stop the sorting algorithm
                    sortingLogic.resetArray();
                    startButton.setEnabled(true);
                    stopButton.setEnabled(false);
                    resetButton.setEnabled(false);
                }
    
            });
    
            frame.setVisible(true);
        }
    
    
    
    }
    
    package visualizer.ui;
    
    
    import visualizer.algorithms.BubbleSort;
    import visualizer.algorithms.SelectionSort;
    import visualizer.algorithms.SortingInterface;
    
    import java.util.Arrays;
    import java.util.Random;
    
    public class SortingLogic {
        private SortingVisualizer visualizer;
        private SortingInterface currentAlgorithm;
        private int[] arrayToSort;
        public SortingLogic() {
            //System.out.println("SortingLogic is being called");
        }
        public void setVisualizer(SortingVisualizer visualizer) {
            this.visualizer = visualizer;
        }
        public int [] generateRandomIntArray(int min, int max, int length) {
            arrayToSort = new int[length];
            Random randNumGenerator = new Random();
            for (int i = 0; i < length; i++) {
                arrayToSort[i] = randNumGenerator.nextInt(max - min + 1) + min;
            }
            return arrayToSort;
        }
        public void setSortingAlgorithm(String algorithm) {
            switch (algorithm) {
                case "Bubble Sort":
                    currentAlgorithm = new BubbleSort(visualizer);
                    break;
                case "Selection Sort":
                    currentAlgorithm = new SelectionSort(visualizer);
                    break;
                /*case "Insertion Sort":
                    currentAlgorithm = new InsertionSort(visualizer);*/
                default:
                    break;
            }
        }
        public void startSorting() {
            if (currentAlgorithm != null)
                currentAlgorithm.toSort(visualizer);
        }
        public void stopSorting() {
            if (currentAlgorithm != null) {
                currentAlgorithm.stopSorting();
            }
        }
        public int[] getArrayToSort() {
            return arrayToSort;
        }
        public void setArrayToSort(int[] newArray) {
            this.arrayToSort = newArray;
        }
        public void resetArray() {
            // Generate a new random array and update the visualizer
            arrayToSort = generateRandomIntArray(1, 1000, 30);
            visualizer.setArrayToSort(arrayToSort);
            visualizer.updateVisualizationPanel();
        }
        public boolean isSorted(int [] arrayToSort){
            for (int i = 0; i < arrayToSort.length; i++){
                if (arrayToSort[i] > arrayToSort[i + 1]){
                    return false;
                }
            }
            return true;
        }
    
    }
    package visualizer.ui;
    
    import javax.swing.*;
    import java.awt.*;
    import java.util.Arrays;
    
    public class SortingVisualizer extends JPanel{
        private int[] arrayToSort;
    
        public int[] getArrayToSort() {
            return arrayToSort;
        }
    
        public void setArrayToSort(int[] arrayToSort) {
            this.arrayToSort = arrayToSort;
        }
    
        public SortingVisualizer(int[] arrayToSort) {
            this.arrayToSort = Arrays.copyOf(arrayToSort, arrayToSort.length);
            //System.out.println("SortingVisualizer is being called");
        }
            protected void paintComponent(Graphics g){
                super.paintComponent(g);
                int barWidth = getWidth() / arrayToSort.length;
                //System.out.println(Arrays.toString(arrayToSort) + "array within Visualizer's Paint Component");
    
                for (int j = 0; j < arrayToSort.length; j++) {//Enhanced for loops look at the values not the indices, so we do not use it
                    int maxArrayValue = Arrays.stream(arrayToSort).max().getAsInt();
                    int barHeight = (int) ((double) arrayToSort[j] / maxArrayValue * getHeight());                int x = j * barWidth;
                    int y = getHeight() - barHeight;
    
                    g.setColor(Color.red);
                    g.fillRect(x, y, barWidth, barHeight);
                    //Fills in a rectangular column
                    g.setColor(Color.black);
                    g.drawRect(x, y, barWidth, barHeight);
                    //Creates a border for said columns
    
                    //System.out.println("SortingVisualizer: /nBar Height " + barHeight +  "barWidth " + barWidth + "x " + x + "y" + y);
                }
            }
        public void updateVisualizationPanel() {
            //System.out.println("Repaint has been called");
            repaint(); // Trigger a repaint of the panel
        }
    }
    
    package visualizer.algorithms;
    
    import visualizer.ui.SortingVisualizer;
    
    public interface SortingInterface {
        void toSort(SortingVisualizer visualizer);
        void stopSorting();
    
    
    }



I started to create a Seperate SwingWorker Class so it may not be complete to the experienced eye.

Before using SwingWorker I was trying to do it using a Timer instead but that was not doing it step-by-step so I switched to SwingWorker. Specifically because it would allow me to do Multi-threading.

What is currently happening: Once you hit start nothing happens, I believe that us just because I do not make any calls to the BubbleSort (fully expect to implement the rest) in the ActionListener. But that is because I need the Sorting classes to work with the SwingWorker first

What I am expecting: Once the user hits the Start button they see the bars being sorted step-by-step

Any tips, comments, or concerns or duly appreciated!

EDIT

I was able to remove the For Loops and do it step-by-step as Hovercraft Full Of Eels and David Conrad suggested and this shows in the visualization panel

public BubbleSort(SortingVisualizer visualizer) {
        if (visualizer == null) {
            throw new IllegalArgumentException("Visualizer cannot be null");
        }
        this.visualizer = visualizer;
        this.arr = visualizer.getArrayToSort();
        this.i = 0;
        this.j = 0;
        this.timer = new Timer(100, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if(i < arr.length - 1){
                    if(j < arr.length - i - 1){
                        if(arr[j] > arr[j + 1]){
                            int temp = arr[j];
                            arr[j] = arr[j + 1];
                            arr[j + 1] = temp;

                            visualizer.updateVisualizationPanel();
                        }
                        j++;
                    }else{
                        j = 0;
                        i++;
                    }
                }else{
                    timer.stop();
                }

            }
        });
    }
0

There are 0 best solutions below