Java Animation Basics and Java Threads


Introduction

This lecture covers:


I. Sample Program

In the current directory is the Java source code of a GUI application that animates the various sorting algorithms discussed in the lectures. To see how the application behaves, compile and run SortControl. Play around with this program to see how it behaves.  The program is designed according to the MVC pattern as shown in the UML diagram below.

MVC.png (33895 bytes)

In the above diagram, the model is an array of OCInteger objects that is to be sorted according to a concrete ACompareSorter selected at runtime.   SortGUI is the view.  It has a GraphCanvas where the data array is plotted and animated.  The design of GraphCanvas is identical to that of BodyPartsCanvas in the hangman project, except that it has an ILambda object to draw on its graphics context instead of an IDrawable object.   The IDrawable object in this case is an inner object of  SortCtrl, the controller: SortCntrl.GraphBarsCmnd.    It makes uses of ArrayMapCar to plot each element in the data array on the GraphCanvasSortCtrl also has a concrete ILambda to print the data array on the JTextArea of SortGUIILambda has one method called Object apply (Object arg).  It represents the abstraction of a command that is capable of performing a task given an input and returning an output object.  GraphCanvas delegates the task of drawing to its ILambda object.  Similarly, SortCtrl delegates the task for updating the text area to print the data array to another ILambda inner object called _appendCmd.  SortCntrl.GraphBarsCmnd and _appendCmd define what to display on the view SortGUI.  But they only appear to SortCtrl as ILambda objects.   SortCtrl asks these ILambda objects to carry out their tasks (by calling apply) without knowing what the tasks are.   These are simple examples of what is called the Command Pattern.

SortCtrl maintains a Timer object that runs in a separate Thread and updates the views at regular time slices.  The Timer object dictates when to repaint.  This is a basic technique in Java animation.

II. Basic Java Animation and Threads

When the sort button is clicked,  the selected sorting algorithm is executed in a separate Thread.  The key method for the Thread object is run ().   To carry out a task on a Thread, all we have to do is to instantiate a Thread object, override the Thread.run () method to perform the desired task, and start the Thread's execution by calling its start() method.  SortControl.gSortBtn_actionPerformed illustrates how sorting is done in a separate Thread.

private final void gSortBtn_actionPerformed(ActionEvent e)
{
    setEnabledBtns (false); // all GUI's buttons are disabled.
    Thread sortThread = new Thread()
    {
        public void run()
        {
            _aCSorter.init ();

            new GraphicSorter (_aCSorter).sort (_gcDataArray,0,_gcDataArray.length-1);
            setEnabledBtns (true); // all GUI's buttons are enabled.
           
_timer.stop ();
        }
    };
    _timer.start ();
    sortThread.start();
}

The Timer object has its own ActionListeners that run in separate threads.  At regular time slices, the Timer object fires an ActionEvent to its listeners, which respond by executing their own actionPerformed method.   Here's the code for the Timer object in SortControl.

private Timer _timer = new Timer (TimeSlice, new ActionListener()
    {
        public void actionPerformed(ActionEvent e)
        {
            updateViews ();
        }
    }
);

At each time slice, the views of the data array are updated.  Since the data array is being sorted in a different thread, its views will have changed, giving the illusion of animation.  How do we display the data array?

III. Decorator Pattern

The abstract sorting algorithm, ACompareSorter, and its concrete variants have no notion of displaying the data array.  To add new displaying capablity without modifying any existing code, we apply what is called the decorator pattern to ACompareSorter.  Below is a UML diagram illustrating the design.

Sorter.png (20408 bytes)

In the above diagram, GraphicSorter is called a decorator for ACompareSorter.  It wraps a concrete ACompareSorter, the "decoree", intercepts all requests to the decoree, performs additional works (decoration) before and/or after delegating the requests to the decoree.  This provides additional functionalities to the decoree without changing any of its code.  Here is the code for GaphicSorter.split.

public int split(IOrdered[] A, int lo, int hi)
{
    int s = _aCSorter.split (A,lo, hi); // delegates to decoree

    SorterColor color = (SorterColor) ((IColored)A[s]).getColor ();
    Color splitColor = color.getLoSplit ();
    for(int i = lo; i < s; i++)
    {
        ((IColored) A[i]).setColor (splitColor);
    }

    splitColor = color.getHiSplit ();
    for(int i=s;i<=hi;i++)
    {
        ((IColored) A[i]).setColor (splitColor);
    }
    try
    {
        System.out.println ("Split at " + s);
        Thread.sleep(NapDuration);
    }
    catch(Exception e){}
    return s;
}

In the above,  when a GraphicSorter splits, it first calls on its decoree to split the data array as usual, then it changes the colors of the splitted arrays.  It also slows down the sorting  to allow time for the view update by going to sleep a little.  SorterColor is a subclass of Color that implements a very application specific coloring scheme.  The data array contains objects that are both IOrdered and IColored.  IOrdered is needed for comparison in sorting.  IColored is needed for graphically drawing the data objects in different colors.

Exercises:

1. Experiment with different time slices for the Timer and GraphicSorter.

2. Add a radio button for heap sort to the above system.


dxnguyen@cs.rice.edu

revised 11/13/00