1

So I am writing a program that animates the insertion sort algorithm using a line graph type thing. The way it is written now, it will generate a random array of integers and draw according representitive lines a DrawingPanel when the populate button is clicked, and when the pause button is hit, it freezes for like 5 seconds then shows the graph sorted. I want to show each iteration, showing one line at a time moving. Any suggestions. I am really not sure how to work multi-threading in Java, I am pretty new. I would appreciate any suggestions.

import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import javax.swing.*;
import java.util.Random;
import java.util.Arrays;

public class AnimationApplication extends JFrame {

private static final long serialVersionUID = 1L;

AnimationPanel panel1 = new AnimationPanel();
AnimationPanel panel2 = new AnimationPanel();

public static void main(String[] args) {
    AnimationApplication prog = new 
     AnimationApplication("Animation Application");

    prog.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    prog.setSize(450, 300);
    prog.setVisible(true);
}

AnimationApplication(String title) {
    super(title);

    setLayout(new BorderLayout());

    add(panel1, BorderLayout.WEST);
    add(panel2, BorderLayout.EAST);
}
}

class AnimationPanel extends JPanel implements ActionListener, Runnable {

private static final long serialVersionUID = 1L;

private int currentSize;

private JButton populate = new JButton("Populate Array");
private JButton pauseB = new JButton("Pause");
private JButton stopB = new JButton("Stop");
private DrawingPanel drawingCanvas = new DrawingPanel();

private volatile Thread animator = null;
private volatile boolean animationSuspended = false;

ArrayList<Integer> pointList = new ArrayList<Integer>();

private Integer [] rndInts;

AnimationPanel() {
    setLayout(new BorderLayout());

    JPanel buttonP = new JPanel(new GridLayout(1, 3, 5, 5));
    buttonP.add(populate);
    buttonP.add(pauseB);
    buttonP.add(stopB);

    populate.addActionListener(this);
    pauseB.addActionListener(this);
    stopB.addActionListener(this);

    add(drawingCanvas, BorderLayout.CENTER);
    add(buttonP, BorderLayout.SOUTH);
}

public void actionPerformed(ActionEvent e) {

    if (e.getSource() == populate) {

                        rndInts = new Integer[ getSize().width-1];


                        for(int i = 0; i < rndInts.length; i++)
  {
    Random rand = new Random();
    rndInts[i]=rand.nextInt((getSize().height)-1);
  //  System.out.println(rndInts[i]);
  }

  currentSize = rndInts.length;               

       pointList = new ArrayList<Integer>(Arrays.asList(rndInts));                



        //System.out.println("Start button pressed");

        // Check if no animation thread exists
        if (animator == null) {

            // If not, start the animation
            start();


        } else {
            // If animation is paused, resume it
            if (animationSuspended) {
                resume();
            }
        }

    } else if (e.getSource() == pauseB) {
        insertionSort(rndInts , currentSize);
        // Check if animation thread exists
        if (animator != null) {

            // If so, suspend the animation thread
            animationSuspended = true;
        }

    } else if (e.getSource() == stopB) {
        stop();
        clear();
    }

}

public void run() {

    Thread thisThread = Thread.currentThread();

    drawingCanvas.repaint();
    while (animator == thisThread) {
        //System.out.println("Animation thread running");
      drawingCanvas.repaint();
        try {
          //  Thread.sleep(1);
 drawingCanvas.repaint();
            if (animationSuspended) {
                synchronized (this) {
                    while (animationSuspended && animator == thisThread) {
                        drawingCanvas.repaint();
                        wait();
                        drawingCanvas.repaint();
                    }
                }
            }
        } catch (InterruptedException e) {
            break;
        }

        // Repaint the panel
        drawingCanvas.repaint();
    }

}

public void start() {
drawingCanvas.repaint();
    // Create a new animation thread and start it
    animator = new Thread(this);
    animationSuspended = false;
    animator.start();
    animationSuspended = true;
 }




public synchronized void stop() {
    drawingCanvas.repaint();
    animator = null;
    notify();
}

public synchronized void resume() {
    animationSuspended = false;
    notify();
}

public void clear() {
    pointList.clear();
    repaint();
}


void insertionSort(Integer [] arr, int length) 
{
  int i, j, tmp;
  for (i = 1; i < length; i++) 
{
        j = i;
        while (j > 0 && arr[j - 1] > arr[j]) 
{
              tmp = arr[j];
              arr[j] = arr[j - 1];
              arr[j - 1] = tmp;
              j--;
              stop();
              drawingCanvas.repaint();
              start();
              //resume();
        }

  }
}



class DrawingPanel extends JPanel implements Runnable {

    private static final long serialVersionUID = 1L;

    protected void paintComponent(Graphics g) {





        // Call superclass version of method
        super.paintComponent(g);

        this.setBackground(Color.WHITE);

        //clear the background
        g.clearRect(0, 0, getSize().width-1, getSize().height-1);

        g.setColor(Color.RED);



        // Draw points
        for (int i = 0; i < currentSize ; i++) //pointList.size(); i++) 
        {
          g.drawLine(i, getSize().height, i, rndInts[i]);
          repaint();
            //resume(); 
        }
      }
    }

}
TheBlindSpring
  • 631
  • 5
  • 22

2 Answers2

0
void insertionSort(Integer[] arr, int length) {
        int i, j, tmp;
        for (i = 1; i < length; i++) {
            j = i;
            while (j > 0 && arr[j - 1] > arr[j]) {
                tmp = arr[j];
                arr[j] = arr[j - 1];
                arr[j - 1] = tmp;
                j--;
                stop();
                drawingCanvas.repaint();
                start();
                // resume();
            }

        }
    }

I think this code is the problem, in a loop start(); is getting called several times. please debug and find out how you can refactor.

Philip Puthenvila
  • 512
  • 1
  • 8
  • 19
0

Some suggestions:

1.) You don't need (and more particularly, don't want) multithreading (Thread) for this.

2.) All access to Swing methods (other than repaint, I think) must be on the Event Queue. (Actually, from personal experience, Swing works just fine off the EventQueue 99.999% of the time, but that 0.001% is murder!) Even without threads, your main method is not on the event queue, so start something like this:

EventQueue.InvokeLater( new Runnable()  {
    AnimationApplication prog = new AnimationApplication( "Animation Application" );
    prog.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    prog.setSize(450, 300);
    prog.setVisible(true);
} );

3.) Use a Swing timer to let you do each step. Start it with the "populate" button and pause it (if you can, stop it and recreate it if you can't, I haven't used it in a while and my memory's bad) with the "pause" button. The Swing timer, unlike anything else you could use--such as the AWT timer--runs its events on the EventQueue.

4.) Write a method that does one step of the sort. Then call it once in each timer event, so inside each event you do one step of the sort, then update the display.

More generally, you've got to make your display work off UI events--button presses and timer events--not the progress of your current sorting code. Your sort needs to be turned inside out, as it were, to dance to the UI's tune, not blast through to sort as fast as possible. Code these days executes way too fast for one thread to watch what another one is doing.

RalphChapin
  • 3,108
  • 16
  • 18