Create Java Applet to Simulate Any Sorting Technique

This is a java program to create an applet to simulate a sorting technique. This applet demonstrates Bubble Sort.

Here is the source code of the Create Java Applet to Simulate Any Sorting Technique. The Java program is successfully compiled and run on a Windows system. The program output is also shown below.

package com.maixuanviet.combinatorial;
 
import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Canvas;
import java.awt.Choice;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Event;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Panel;
import java.awt.Point;
 
@SuppressWarnings("deprecation")
class ExplainBox extends Canvas
{
    private static final long serialVersionUID = 1L;
    static final int marginX = 6;
    static final int marginY = 3;
    String text = "";
 
    public ExplainBox()
    {
        setFont(new Font("TimesRoman", Font.PLAIN, 12));
    }
 
    public void setText(String text)
    {
        this.text = text;
        invalidate();
    }
 
    public void validate()
    {
        FontMetrics metrics = getFontMetrics(getFont());
        int baseLine = metrics.getAscent();
        int lineHeight = baseLine + metrics.getDescent();
        int width = metrics.stringWidth(text);
        Point corner = location();
        reshape(corner.x, corner.y, width + 2 * marginX, lineHeight + 2
                * marginY);
    }
 
    public void paint(Graphics g)
    {
        g.setColor(Color.black);
        Dimension size = size();
        g.drawRect(0, 0, size.width - 1, size.height - 1);
        FontMetrics metrics = getFontMetrics(getFont());
        g.drawString(text, marginX, marginY + metrics.getAscent());
    }
 
    public boolean mouseExit(Event event, int x, int y)
    {
        return true;
    }
}
 
@SuppressWarnings("deprecation")
class CodePanel extends Panel
{
    private static final long serialVersionUID = 1L;
    static final int marginX = 15;
    static final int marginY = 20;
    static final int offsetX = 1;
    static final int offsetY = 1;
    static final int none = -1;
    String code[]; // Array to hold the source code
    String explainations[]; // Array to hold the explaination of source code
    Font font = new Font("TimesRoman", Font.PLAIN, 16);
    int lineHeight;
    int baseLine;
    int maxWidth = 0;
    int highlightedLine = none;
    ExplainBox explaination = new ExplainBox();
    Applet applet;
 
    public CodePanel(String code[], String explainations[], Applet applet)
    {
        this.code = code;
        this.explainations = explainations;
        this.applet = applet;
        setBackground(Color.white); // Set the background of code panel to be
                                    // white
        explaination.setBackground(Color.lightGray);
        explaination.setForeground(Color.lightGray);
        add(explaination);
        explaination.hide(); // Hide explaination until the code line is clicked
    }
 
    public Dimension preferredSize()
    {
        return new Dimension(280, 300);
    }
 
    public void addNotify()
    {
        super.addNotify();
        setFont(font);
        FontMetrics metrics = getFontMetrics(font);
        baseLine = metrics.getAscent();
        lineHeight = baseLine + metrics.getDescent();
        for (int i = 0; i < code.length; i++)
        {
            maxWidth = Math.max(maxWidth, metrics.stringWidth(code[i]));
        }
    }
 
    public void paint(Graphics g)
    {
        int y = marginY + baseLine;
        for (int i = 0; i < code.length; i++, y += lineHeight)
        {
            setBackground(Color.white);
            g.drawString(code[i], marginX, y);
        }
        highlightLine(highlightedLine);
    }
 
    public void reset()
    {
        if (highlightedLine != none)
        {
            colorLine(highlightedLine, Color.white);
        }
        highlightedLine = none;
    }
 
    public void highlightLine(int line)
    {
        if (highlightedLine != none)
        {
            colorLine(highlightedLine, Color.white);
        }
        highlightedLine = line;
        if (highlightedLine != none)
        {
            colorLine(highlightedLine, Color.pink);
        }
    }
 
    public void colorLine(int line, Color color)
    {
        Graphics g = getGraphics();
        int y = marginY + line * lineHeight;
        g.setColor(color);
        g.fillRect(0, y, size().width - 1, lineHeight);
        g.setColor(Color.black);
        g.drawString(code[line], marginX, y + baseLine);
    }
 
    public boolean mouseExit(Event event, int x, int y)
    {
        explaination.hide();
        validate();
        return true;
    }
 
    public boolean mouseUp(Event event, int x, int y)
    {
        int line = (y - marginY) / lineHeight;
        if ((line <= explainations.length) || (explainations[line].equals("")))
        {
            explaination.setText(explainations[line]);
            explaination.setBackground(Color.lightGray);
            explaination.validate();
            explaination.show();
        }
        else
        {
            explaination.hide();
        }
        validate();
        explaination.move(marginX + offsetX, marginY + offsetY + (line + 1)
                * lineHeight);
        return true;
    }
}
 
@SuppressWarnings("deprecation")
class Algorithm extends Thread
{
    CodePanel codeDisplay; // Code Panel
    static int granularity; // Granularity Level
    SortingApplet applet; // Bubble Sort Applet
    Animation animation; // Animation Canvas
    public static int indexi = 0; // Loop Index
    public static int indexj = 0; // Loop Index
    public static int flag = -1;
 
    public Algorithm(CodePanel codeDisplay, int granularity, SortingApplet applet,
            Animation animation)
    {
        this.codeDisplay = codeDisplay;
        this.applet = applet;
        Algorithm.granularity = granularity;
        this.animation = animation;
    }
 
    void setGranularity(int granularity)
    {
        Algorithm.granularity = granularity;
    }
 
    public void run()
    {
        int line = 0; // Line Number
        visualize(line, 2); // Visualize current line
        indexi = SortingApplet.SourceData.length - 1; // Set loop index value
        Algorithm.flag = 1; // Set execution status
        animation.repaint(); // Refresh animation canvas
        int forLoopLine1 = line; // Mark the line # of first for loop
        while (true)
        {
            if (!(indexi >= 1))
                break;
            visualize(++line, 2);
            indexj = 0;
            animation.repaint();
            int forLoopLine2 = line; // Mark the line # of second for loop
            while (true)
            {
                if (!(indexj <= (indexi - 1)))
                    break;
                visualize(++line, 2);
                animation.repaint();
                if (SortingApplet.SourceData[indexj] > SortingApplet.SourceData[indexj + 1])
                {
                    // switch the two array elements
                    visualize(++line, 2);
                    int temp = SortingApplet.SourceData[indexj];
                    animation.repaint();
                    visualize(++line, 2);
                    SortingApplet.SourceData[indexj] = SortingApplet.SourceData[indexj + 1];
                    animation.repaint();
                    visualize(++line, 2);
                    SortingApplet.SourceData[indexj + 1] = temp;
                    animation.repaint();
                }
                line = forLoopLine2; // Set line # to be the second for loop
                visualize(line, 1);
                animation.repaint();
                indexj++;
            }
            line = forLoopLine1; // Set line # to be the first for loop
            visualize(line, 1);
            indexi--;
            animation.repaint();
        }
        Algorithm.flag = -1; // After execution finished, set flag back to -1
        animation.repaint();
        try
        {
            sleep(1000);
        }
        catch (Exception e)
        {
        }
        applet.sortButton.setLabel("  Sort  ");
        applet.sortButton.disable();
        applet.stopButton.disable();
        applet.resetButton.enable();
        visualize(0, 0); // After execution finished, highlight the first line
        applet.finished();
    }
 
    void visualize(int line, int level)
    {
        codeDisplay.highlightLine(line); // Highlight the current line
        codeDisplay.repaint();
        if (level > granularity)
        {
            try
            {
                sleep(300);
            }
            catch (Exception e)
            {
            }
            ;
        }
        else
        {
            suspend();
        }
    }
}
 
@SuppressWarnings("deprecation")
class Animation extends Panel
{
    private static final long serialVersionUID = 1L;
    int dX = 30; // starting position for x coordinate
    int dBar = 15; // width of bar
    int dUnit = 15; // unit height
    int dDis = 20; // distance between bars
    Image offImage; // Offscreen Image
    Graphics offG; // Offscreen Graphics
    Font font = new Font("TimesRoman", Font.PLAIN, 14);
 
    public Animation()
    {
        repaint();
    }
 
    public Dimension preferredSize()
    {
        return new Dimension(320, 300);
    }
 
    public Dimension minimumSize()
    {
        return preferredSize();
    }
 
    public void update(Graphics g)
    {
        paint(g);
    }
 
    public void paint(Graphics g)
    {
        Dimension d = size();
        if (offImage == null)
        {
            offImage = createImage(d.width, d.height);
            offG = offImage.getGraphics();
            offG.setFont(font);
        }
        offG.setColor(Color.yellow); // Set background of Animation Canvas to be
        // yellow
        offG.fillRect(0, 0, d.width, d.height); // Draw background
        offG.setColor(Color.blue); // Set color for bars to be blue
        int x = 40; // x coordinate of the bar position
        for (int i = 0; i < SortingApplet.SourceData.length; i++, x = x + dDis
                + dBar)
        {
            if (((i == Algorithm.indexj) || (i == Algorithm.indexj + 1))
                    && (Algorithm.flag == 1))
            {
                offG.setColor(Color.green); // Use green color to indicate the
                // bars being compared currently
            }
            else if (((i > Algorithm.indexi) && (Algorithm.flag == 1))
                    || ((Algorithm.indexi == 0) && (Algorithm.indexj == 1) && (Algorithm.flag == -1)))
            {
                offG.setColor(Color.black); // Use black color to indicate bars
                // that are already sorted
            }
            offG.fillRect(x, 180 - SortingApplet.SourceData[i] * dUnit, dBar,
                    SortingApplet.SourceData[i] * dUnit); // fill bars
            offG.setColor(Color.blue); // Reset color to be blue
            offG.drawString("" + i, x + 7, 25); // Draw the current index value
            // of i
            offG.drawString("" + SortingApplet.SourceData[i], x + 7, 40);
        }
        offG.drawString("Index:", 5, 25);
        offG.drawString("Value:", 5, 40);
        offG.drawString("I:", 5, 205);
        offG.drawString("J:", 5, 230);
        offG.drawString("J+1:", 5, 255);
        if (Algorithm.indexi != 0)
            offG.drawString("i", 40 + 9 + Algorithm.indexi * (dDis + dBar), 205);
        if (Algorithm.indexj < Algorithm.indexi)
        {
            offG.drawString("j", 40 + 9 + Algorithm.indexj * (dDis + dBar), 230);
            offG.drawString("j+1", 40 + 7 + (Algorithm.indexj + 1)
                    * (dDis + dBar), 255); // Mark the current j+1 position
        }
        g.drawImage(offImage, 0, 0, this);
    }
}
 
@SuppressWarnings("deprecation")
public class SortingApplet extends Applet
{
    private static final long serialVersionUID = 1L;
    // Source code for Bubble Sort Algorithm
    String code[] = { "  for ( int i = n - 1; i >= 1; i-- )        ",
            "      for ( int j = 0; j <= i - 1; j++ )    ",
            "          if ( data [j] > data[j+1] ) {     ",
            "             int temp = data [j];           ",
            "             data [j] = data [j+1];         ",
            "             data [j+1] = temp;             ",
            "          }                                 " };
    // Explaination for each line of code
    String pseudoCode[] = {
            "go through elements of 'data' from last to 1 index",
            "go through elements of 'data' from 0 to i index",
            "to compare data [j] and data [j+1]",
            "before swap, remember data [j]", "assign data [j] = data [j+1]",
            "assign data [j+1] the original value of data [j]",
            "end of if statement" };
    public static int SourceData[] = { 7, 4, 5, 1, 8, 3, 6, 2 };
    public static int normalData[] = { 7, 4, 5, 1, 8, 3, 6, 2 };
    public static int bestData[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
    public static int worstData[] = { 8, 7, 6, 5, 4, 3, 2, 1 };
    Button sortButton = new Button("   Sort   "); // sort Button
    Button stopButton = new Button("   Stop   "); // stop Button
    Button resetButton = new Button("   Reset  "); // reset Button
    int choice = 0; // choice index
    Choice dataChoice = new Choice(); // choice of different data sets
    String dataLabels[] = { "normal case", "best case", "worst case" };
    int granularity = 0; // granularity index
    Choice granularityChoice = new Choice(); // choice of different granularity
    String granularityLabels[] = { "entire sort", "next swap", "next line" }; // granularity
                                                                              // labels
    private Panel controlPanel = new Panel();
    CodePanel codeDisplay = new CodePanel(code, pseudoCode, this);
    Algorithm algorithm = null;
    Animation animation = new Animation();
 
    public void init()
    {
        setLayout(new BorderLayout()); // Set the panle to be border layout
        add("West", codeDisplay);
        add("East", animation);
        add("South", controlPanel);
        controlPanel.setLayout(new FlowLayout(FlowLayout.CENTER)); // Set
                                                                   // codepanel
                                                                   // to be
                                                                   // flowlayout
        controlPanel.add(sortButton); // Add sort button
        controlPanel.add(stopButton); // Add stop button
        stopButton.disable(); // At the beginning, stop button is disabled
        controlPanel.add(resetButton); // Add reset button
        resetButton.disable(); // At the beginning, resuet button is disabled
        controlPanel.add(dataChoice); // Add data choice menu
        for (int i = 0; i < dataLabels.length; i++)
        {
            dataChoice.addItem(dataLabels[i]); // Set label for each menu items
        }
        controlPanel.add(granularityChoice); // Add granularity choice menu
        for (int i = 0; i < granularityLabels.length; i++)
        {
            granularityChoice.addItem(granularityLabels[i]); // Set label for
                                                             // each menu items
        }
    }
 
    public void finished()
    {
        algorithm = null;
    }
 
    public boolean action(Event event, Object what)
    {
        if (event.target == sortButton)
        {
            if (granularity == 0)
                sortButton.disable();
            else
                sortButton.setLabel("Continue");
            resetButton.disable(); // Once sorting begins, reset Button is
            // disabled
            stopButton.enable(); // stop Button is enabled
            if (algorithm == null)
            {
                algorithm = new Algorithm(codeDisplay, granularity, this,
                        animation);
                algorithm.start(); // Start the Bubble Sort Algorithm
            }
            else
            {
                algorithm.resume(); // Continue the Bubble Sort Algorithm
            }
        }
        else if (event.target == stopButton)
        { // stop Button is clicked
            algorithm.stop(); // Stop the Bubble Sort Algorithm
            sortButton.disable(); // Disable the sort Button
            stopButton.disable(); // Disable the stop Button
            resetButton.enable(); // Enable the reset Button
            finished(); // Applet finished
        }
        else if (event.target == resetButton)
        { // reset Button is clicked
            finished(); // Applet finished
            sortButton.setLabel("  Sort  "); // Set sort Button label
            sortButton.enable();
            stopButton.disable();
            resetDataArray(); // Recover the data array to its initial value
            // based on the dataChoice menu
            Algorithm.flag = -1; // Reset flag to initial value
            animation.repaint(); // Refresch the animation canvas
        }
        else if (event.target == dataChoice)
        { // If dataChoice menu is changed
            choice = dataChoice.getSelectedIndex();
        }
        else if (event.target == granularityChoice)
        { // If granularityChoice menu is changed
            granularity = granularityChoice.getSelectedIndex();
            if (algorithm != null)
            {
                algorithm.setGranularity(granularity); // Set the granularity to
                // be the new value in
                // the menu
            }
        }
        else
        {
            return false;
        }
        return true;
    }
 
    public void resetDataArray()
    {
        // Reset loop index to its initial value
        Algorithm.indexi = 0;
        Algorithm.indexj = 0;
        if (choice == 0)
        { // "Normal Case" is selected
          // Reset the source data to be the normal case
            for (int i = 0; i < normalData.length; i++)
            {
                SourceData[i] = normalData[i];
            }
        }
        else if (choice == 1)
        { // "Best Case" is selected
          // Reset the source data to be the best case
            for (int i = 0; i < bestData.length; i++)
            {
                SourceData[i] = bestData[i];
            }
        }
        else if (choice == 2)
        { // "Worst Case" is selected
          // Reset the source data to be the worst case
            for (int i = 0; i < worstData.length; i++)
            {
                SourceData[i] = worstData[i];
            }
        }
    }
}

Output:

$ javac SortingApplet.java
$ java SortingApplet
 
Run this applet to see the output