Tutorial 8: Java Animation Basics and Java Threads


Introduction

This tutorial covers:


I. Sample Program

Create a local directory comp212/tutorials/08 for this lab and copy the files ~/comp212/tutorials/08/*.java and ~/comp212/tutorials/08/*.class.  These are the Java source code and byte code for a GUI application that animates the various sorting algorithms discussed in the lectures. To see how the application behaves, run the command: java 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.

SortGUI.png (30310 bytes)

In the above diagram, the model is an array of IOrdered 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 lab 04: it has an IDrawable object to draw on its graphics context.   The IDrawable object in this case is an inner object of  SortControl, the controller: SortControl.GraphCommand.  It is both an IDrawable and and ACommand.   It makes uses of ArrayMapper to plot each element in the data array on the GraphCanvasSortControl also has a concrete ACommand to print the data array on the JTextArea of SortGUISortControl maintains a Timer object that runs in a separate Thread and updates the views at regular time slices.  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()
        {
            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(TimeSlice);
    }
    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 03/20/00