I have been making a sorting algorithm visualizer in Java using Java Swing and AWT and coded insertion sort to see if it would be able to work. The algorithm works in the sense that when this program is run you can shuffle and sort the algorithm using insertion short but you don't actually see the algorithm in action. It just happens instantly and have been looking for ways to add some sort of delay but I can't find any sources to help me.
I set it up with 4 java classes, the main which just init's the window, the window class, array visualizer class, and the insertion sort class.
Window.java:
public class Window implements ActionListener {
//Window width
protected static int WINDOW_WIDTH = 1980;
//Window height
protected static int WINDOW_HEIGHT = 1080;
private int delay = 100;
//This will draw all our rectangles
protected static ArrayVisualizer arrayVisualizer;
//Make a new JFrame
JFrame window = new JFrame();
JButton shuffleBut = new JButton("Shuffle");
JButton startSort = new JButton("Start Sorting");
public Window() {
initWindow();
}
private void addButtons() {
//Shuffle Button
shuffleBut.setBounds(100, 50, 100, 100);
shuffleBut.setBackground(Color.white);
shuffleBut.addActionListener(this);
startSort.setBounds(500, 50, 100, 100);;
startSort.setBackground(Color.white);
startSort.addActionListener(taskPerformer);
window.add(shuffleBut);
window.add(startSort);
}
private void initWindow() {
ImageIcon logo = new ImageIcon();
window = new JFrame();
window.setTitle("JAlgorithms");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
window.setLocationRelativeTo(null);
window.setResizable(false);
addButtons();
arrayVisualizer = new ArrayVisualizer();
window.add(arrayVisualizer);
arrayVisualizer.repaint(); //Will call paint component method
window.pack();
window.setVisible(true);
}
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
if(e.getSource() == shuffleBut) {
arrayVisualizer.shuffle(ArrayVisualizer.array);
arrayVisualizer.repaint();
}
}
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent event) {
if(event.getSource() == startSort) {
arrayVisualizer.sort(ArrayVisualizer.array);
arrayVisualizer.repaint();
}
}
};
}
ArrayVisualizer.java:
public class ArrayVisualizer extends JPanel {
protected static int[] array;
private final int REC_WIDTH = 1; //1980 rectangles
private final int NUMBER_OF_RECS = Window.WINDOW_WIDTH / REC_WIDTH;
public ArrayVisualizer() {
array = new int[NUMBER_OF_RECS];
generateRandom(array);
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D graphics = (Graphics2D) g.create();
graphics.setColor(Color.orange);
for(int i = 0; i < NUMBER_OF_RECS; i ) {
int height = array[i] * 4; //Done for scaling
int recX = i (REC_WIDTH - 1) * i; //Read fillRect documentation
int recY = Window.WINDOW_HEIGHT - height; //Read fillRect documentation
graphics.fillRect(recX, recY, REC_WIDTH, height);
}
}
//This will return the Dimension of the actual rectangles. i.e the rectangles will only exist when this exists, almost like a canvas in javascript
@Override
public Dimension getPreferredSize() {
return new Dimension(Window.WINDOW_WIDTH, Window.WINDOW_HEIGHT);
}
//Creates a random unsorted array with numbers 1-200
protected void generateRandom(int[] array) {
Random number = new Random();
for(int i = 0; i < NUMBER_OF_RECS; i ) {
array[i] = number.nextInt(200);
}
}
protected void shuffle(int[] array) {
generateRandom(array);
}
protected void sort(int[] array) {
InsertionSort.insertionSort(array);
}
}
InsertionSort.java:
public class InsertionSort {
public static void insertionSort(int arr[])
{
int n = arr.length;
for (int i = 1; i < n; i) {
int key = arr[i];
int j = i - 1;
/* Move elements of arr[0..i-1], that are
greater than key, to one position ahead
of their current position */
while (j >= 0 && arr[j] > key) {
arr[j 1] = arr[j];
j = j - 1;
}
arr[j 1] = key;
}
}
}
UPDATE (Here is the modified code, I added selection sort as well and heavily modified the suggestion I checkmarked):
Main.java:
public class Main {
public static void main(String[] args) {
//Opens window
Window window = new Window();
}
}
Window.java:
import java.awt.Color;
import java.awt.Image;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.awt.EventQueue;
import javax.swing.ImageIcon;
import java.awt.Graphics2D;
import java.awt.Graphics;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class Window implements ActionListener {
//Window width
protected static int WINDOW_WIDTH = 1440;
//Window height
protected static int WINDOW_HEIGHT = 1080;
//This will draw all our rectangles
protected static ArrayVisualizer arrayVisualizer;
//Make a new JFrame
JFrame window = new JFrame();
JButton shuffleBut = new JButton("Shuffle");
JButton startSort = new JButton("Start Sorting");
public Window() {
initWindow();
}
private void addButtons() {
//Shuffle Button
shuffleBut.setBounds(100, 50, 100, 100);
shuffleBut.setBackground(Color.white);
shuffleBut.addActionListener(this);
startSort.setBounds(500, 50, 100, 100);;
startSort.setBackground(Color.white);
window.add(shuffleBut);
window.add(startSort);
}
private void initWindow() {
ImageIcon logo = new ImageIcon();
window = new JFrame();
window.setTitle("JAlgorithms");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
window.setLocationRelativeTo(null);
window.setResizable(false);
addButtons();
startSort.addActionListener(taskPerformer);
arrayVisualizer = new ArrayVisualizer();
window.add(arrayVisualizer);
arrayVisualizer.repaint(); //Will call paint component method
window.pack();
window.setVisible(true);
}
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
if(e.getSource() == shuffleBut) {
arrayVisualizer.shuffle(ArrayVisualizer.array);
arrayVisualizer.repaint();
}
}
ActionListener taskPerformer = new ActionListener() {
@Override
public void actionPerformed(ActionEvent event) {
if(event.getSource() == startSort) {
if(!timer.isRunning()) { //If timer is not running
timer.setInitialDelay(0); //Set initial delay
timer.start(); //Start the timer
}
}
}
};
ActionListener sortWithDelay = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if(sorted(ArrayVisualizer.array)) { //If it is sorted
timer.stop(); //Stop the timer
return;
} else {
arrayVisualizer.sort(ArrayVisualizer.array); //If it is not sorted continue the sort
arrayVisualizer.repaint(); //Called after each swap
}
}
};
private int delay = 10; //Milliseconds
private Timer timer = new Timer(delay, sortWithDelay);
private boolean sorted(int[] array) {
for(int i = 0; i < array.length - 1; i ) {
if(array[i] > array[i 1]) {
return false;
}
}
return true;
}
}
ArrayVisualizer.java:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.Array;
import javax.swing.*;
import java.util.*;
public class ArrayVisualizer extends JPanel {
private static final long serialVersionUID = 1L;
private InsertionSort insertionSort = new InsertionSort();
private SelectionSort selectionSort = new SelectionSort();
protected static int[] array;
private final int REC_WIDTH = 1; //1980 rectangles
private final int NUMBER_OF_RECS = Window.WINDOW_WIDTH / REC_WIDTH;
private final int[] barColors;
public ArrayVisualizer() {
setBackground(Color.black);
array = new int[NUMBER_OF_RECS];
barColors = new int[NUMBER_OF_RECS];
generateRandom(array);
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D graphics = (Graphics2D) g.create();
graphics.setColor(Color.white);
for(int i = 0; i < NUMBER_OF_RECS; i ) {
int height = array[i] * 4; //Done for scaling
int recX = i (REC_WIDTH - 1) * i; //Read fillRect documentation
int recY = Window.WINDOW_HEIGHT - height; //Read fillRect documentation
graphics.fillRect(recX, recY, REC_WIDTH, height);
}
}
//This will return the Dimension of the actual rectangles. i.e the rectangles will only exist when this exists, almost like a canvas in javascript
@Override
public Dimension getPreferredSize() {
return new Dimension(Window.WINDOW_WIDTH, Window.WINDOW_HEIGHT);
}
//Creates a random unsorted array with numbers 1-200
protected void generateRandom(int[] array) {
Random number = new Random();
for(int i = 0; i < NUMBER_OF_RECS; i ) {
array[i] = number.nextInt(200);
}
}
protected void shuffle(int[] array) {
generateRandom(array);
}
protected void sort(int[] array) {
selectionSort.sortWithDelay(array);
}
}
InsertionSort.java:
public class InsertionSort {
private int i = 1;
private int j = 0;
public void sortWithDelay(int arr[])
{
int n = arr.length;
if(i < n) {
int key = arr[i];
j = i - 1;
/* Move elements of arr[0..i-1], that are
greater than key, to one position ahead
of their current position */
while(j >= 0 && arr[j] > key) {
arr[j 1] = arr[j];
j = j - 1;
}
arr[j 1] = key;
i;
}
}
}
SelectionSort.java:
public class SelectionSort {
private int i = 1;
private int j = 0;
public void sortWithDelay(int arr[])
{
int n = arr.length - 1;
if(i < n) {
int min_index = i;
for(int j = i 1; j < n; j ) {
if(arr[j] < arr[min_index]) {
min_index = j;
}
}
int temp = arr[min_index];
arr[min_index] = arr[i];
arr[i] = temp;
i;
}
}
}
CodePudding user response:
Call an action with a swing timer every second that will return an intermediate array. Then paint this intermediate array. Repeat until the array is sorted.
To obtain an intermediate array, modify the InsertionSort from a static method to a class method that will store the variables i
and j
so that we can resume sorting when called again.
public class Window implements ActionListener {
//Window width
protected static int WINDOW_WIDTH = 1980;
//Window height
protected static int WINDOW_HEIGHT = 1080;
//This will draw all our rectangles
protected static ArrayVisualizer arrayVisualizer;
//Make a new JFrame
JFrame window = new JFrame();
JButton shuffleBut = new JButton("Shuffle");
JButton startSort = new JButton("Start Sorting");
public Window() {
initWindow();
}
private void addButtons() {
//Shuffle Button
shuffleBut.setBounds(100, 50, 100, 100);
shuffleBut.setBackground(Color.white);
shuffleBut.addActionListener(this);
startSort.setBounds(500, 50, 100, 100);;
startSort.setBackground(Color.white);
startSort.addActionListener(taskPerformer);
window.add(shuffleBut);
window.add(startSort);
}
private void initWindow() {
ImageIcon logo = new ImageIcon();
window = new JFrame();
window.setTitle("JAlgorithms");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
window.setLocationRelativeTo(null);
window.setResizable(false);
addButtons();
arrayVisualizer = new ArrayVisualizer();
window.add(arrayVisualizer);
arrayVisualizer.repaint(); //Will call paint component method
window.pack();
window.setVisible(true);
}
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
if(e.getSource() == shuffleBut) {
arrayVisualizer.shuffle(ArrayVisualizer.array);
arrayVisualizer.repaint();
}
}
private int delay = 1000; // delay is 1s
private Timer timer = new Timer(delay, sortWithDelay);
ActionListener taskPerformer = new ActionListener() {
@Override
public void actionPerformed(ActionEvent event) {
if(event.getSource() == startSort) {
// Start the timer that shows a swap every second
if(!timer.isRunning()) {
timer.setInitialDelay(0);
timer.start();
}
}
}
};
ActionListener sortWithDelay = new ActionListener() {
@Override
public void actionPerformed(ActionEvent event) {
if(isSorted(ArrayVisualizer.array)) {
timer.stop();
return;
}
arrayVisualizer.sort(ArrayVisualizer.array);
arrayVisualizer.repaint();
}
};
private boolean isSorted(int[] arr) {
for (int i = 0; i < a.length - 1; i ) {
if (a[i] > a[i 1]) {
return false;
}
}
return true;
}
}
public class ArrayVisualizer extends JPanel {
private InsertionSort insertionSort = new InsertionSort();
protected static int[] array;
private final int REC_WIDTH = 1; //1980 rectangles
private final int NUMBER_OF_RECS = Window.WINDOW_WIDTH / REC_WIDTH;
public ArrayVisualizer() {
array = new int[NUMBER_OF_RECS];
generateRandom(array);
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D graphics = (Graphics2D) g.create();
graphics.setColor(Color.orange);
for(int i = 0; i < NUMBER_OF_RECS; i ) {
int height = array[i] * 4; //Done for scaling
int recX = i (REC_WIDTH - 1) * i; //Read fillRect documentation
int recY = Window.WINDOW_HEIGHT - height; //Read fillRect documentation
graphics.fillRect(recX, recY, REC_WIDTH, height);
}
}
//This will return the Dimension of the actual rectangles. i.e the rectangles will only exist when this exists, almost like a canvas in javascript
@Override
public Dimension getPreferredSize() {
return new Dimension(Window.WINDOW_WIDTH, Window.WINDOW_HEIGHT);
}
//Creates a random unsorted array with numbers 1-200
protected void generateRandom(int[] array) {
Random number = new Random();
for(int i = 0; i < NUMBER_OF_RECS; i ) {
array[i] = number.nextInt(200);
}
}
protected void shuffle(int[] array) {
generateRandom(array);
}
protected void sort(int[] array) {
insertionSort.sortWithDelay(array);
}
}
public class InsertionSort {
private int i = 1;
private int j = 0;
public void sortWithDelay(int arr[])
{
int n = arr.length;
if(i < n) {
int key = arr[i];
j = i - 1;
/* Move elements of arr[0..i-1], that are
greater than key, to one position ahead
of their current position */
if(j >= 0 && arr[j] > key) {
arr[j 1] = arr[j];
j = j - 1;
// return immediately after swap
return;
}
arr[j 1] = key;
i;
}
}
}