I am attempting to create a sorting visualizer in Java using Swing. So far, my program asks the user for the sorting algorithm of their choice (I have excluded the code for selection menu here) and then visually sorts an unsorted array. The only sorting algorithm that I have implemented so far for GUI testing purposes is insertion sort.
Below is the insertion sort algorithm:
public class InsertionSort extends Sorter { // Sorter is an abstract class
@Override
public void sort(ArrayVisualization array) { // ArrayVisualization object to change array values
for (int i = 0; i < array.getArraySize(); i++) {
int j = i - 1;
int key = array.getArrayValue(i);
while (j >= 0 && array.getArrayValue(j) > key) {
array.delayedSwap(j, j+1); // calls delayedSwap method continually-PROBLEM
--j;
}
}
}
@Override
public String toString() {
return "Insertion Sort";
}
}
I am unable to correctly visualize the swaps between the various indices. At first, I attempted using Thread.sleep() to briefly put the thread to sleep when swapping values. This inevitably ended up freezing the EDT. After searching through Stack Overflow, I came across Swing Timer which is recommended when making GUI modifications.
When I used Swing Timer for shuffling the array in shuffleArray(), it worked perfectly fine and I could see each value being swapped with a delay (currently, the portion in shuffleArray() that used Swing Timer is commented because I decided later to not to show the shuffling part with delays). When I implemented the delayedSwap() method in a similar fashion with Swing Timer, the array slightly sorted itself but then suddenly stopped. The array remains unsorted as a whole.
delayedSwap() is called appropriate number of times and the insertion sort algorithm works perfectly fine as well when tested without Swing Timer.
Can someone please tell me why am I having this issue with Swing Timer in delayedSwap()? I have tried using SwingWorker and creating a new thread in delayedSwap() and then putting that to sleep. I kind of think it has something to do with me calling delayedSwap() repeatedly in a loop from another class but I do not understand how else to implement delayedSwap() as that is used in all sorting algorithms (roughly). If this is not fixable, is there any other alternative?
Below is the code for the ArrayVisualizer which contains delayedSwap().
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
public class ArrayVisualization extends JPanel {
private int[] array;
private static final int BAR_WIDTH = 5;
private final static int WIN_WIDTH = 1280;
private final static int WIN_HEIGHT = 720;
private static final int NUM_BARS = WIN_WIDTH / BAR_WIDTH;
//private static final int SWAP_DELAY = 1;
public void arrayScreen() {
JFrame frame = new JFrame("Sorting Visualizer");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
ArrayVisualization panel = new ArrayVisualization();
frame.add(panel);
frame.setSize(WIN_WIDTH, WIN_HEIGHT);
frame.setVisible(true);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
}
public int getArraySize() {
return this.array.length;
}
public int getArrayValue(int x) {
return this.array[x];
}
public ArrayVisualization() {
array = new int[NUM_BARS];
for (int i = 0; i < NUM_BARS; i++) { // populate the array
array[i] = i;
}
shuffleArray(); // shuffle
InsertionSort sort = new InsertionSort();
sort.sort(this); // sort
}
public void shuffleArray() {
Random rand = new Random();
for (int i = 0; i < NUM_BARS; i++) {
int randIdx = rand.nextInt(NUM_BARS - 1); // create random indices to swap with
int temp = array[randIdx];
array[randIdx] = array[i];
array[i] = temp;
}
repaint();
/* Timer timer = new Timer(1, new ActionListener() {
private int counter;
@Override
public void actionPerformed(ActionEvent e) {
int randomNumber = rand.nextInt(NUM_BARS - 1);
int temp = array[counter];
array[counter] = array[randomNumber];
array[randomNumber] = temp;
repaint();
if (counter == NUM_BARS - 1) {
((Timer)e.getSource()).stop();
}
counter++;
}
});
timer.start();*/
}
/* MAIN PROBLEM */
public void delayedSwap(int idx1, int idx2) {
Timer timer = new Timer(1000, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
int temp = array[idx1];
array[idx1] = array[idx2];
array[idx2] = temp;
repaint();
((Timer) e.getSource()).stop(); // so that timer terminates after 1 swap
}
});
timer.start();
}
@Override
public void paintComponent(Graphics g) {
Graphics2D graphics = (Graphics2D) g;
super.paintComponent(graphics);
graphics.setColor(Color.BLACK);
for (int i = 0; i < NUM_BARS; i++) {
int height = array[i] * 2;
int xBegin = i + (BAR_WIDTH - 1) * i;
int yBegin = WIN_HEIGHT - height;
graphics.fillRect(xBegin, yBegin, BAR_WIDTH, height);
}
}
}
Thank you!