Sunday, 4 April 2010

Using Thread in Java to Create Animation, Example 1

I liked to write a short guide for threads in java. It is because I could not find the existing materials much helpful. None of them dealt with this in a pedagogically clear way. They confuse the reader with materials such as "monitor" and native operating system or by mixing the thread usage with other pieces of a complicate program that deviate the attention to those pieces. Many of them want only to demonstrate an animated program is possible without explaining the thread by itself. Here I use a thread for moving from one image to another image. It is like a "Clock Pulse" or a "tick-tack" When it ticks we have one image when it tacks it shows another image. When the clock pulse is up it shows one image. When the pulse is down it shows the other image. When you use a thread in a java class you should implement java.lang.Runnable() interface. This interface contains the signature for the run() method that you write  for your class. You also need a start method start()  to initiate a thread. As a counterpart  to tick of run() method we need a reset() method for tack of our clock. We need a method that, in case, takes us out of  the tick-tack into a place that we become in control of doing other tasks. This is normally a boolean flag that tests something we predicted in a corner of the tick or in a corner of the tack. I do it simple by counting the tick-tacks and after certain number of loops I stop the animation, through that counter or through the flag. The quartet of start() -  run() - reset() - flag() is all I need. start(): starts tick-tack; run() and reset(): make the tick-tack runs and runs for ever; flag(): stops the tick-tack to go to other jobs if you like to stop it (it inhibits the clock like the hardware inhibit signal). I cannot change names of the run() and start() but I can change names of the other two. I call my reset() as other() to emphasis its job, to prevent confusing it with inhibit. I call my flag() method as isDone() in fashion of java boolean classes. I do not move anything on the screen to demonstrate animation. I only switch between two still pictures to learn how the thread is working between two states. This facilitate my future progress. I had an icon image, "Bella.gif" I used Windows 7 Microsoft Picture Manager and flipped it horizontally and saved the flipped image as "bellb.gif" Then I switched back and forth between these two images. You can see that, tick and tack are both within a never-ending while loop, as far as the thread is not killed; that is, is not null. We call our flag method isDone() to find a way, or rather to arrange, to terminate that loop, for example, if the bell has done fifty tolls. At that time we put the toll counting back to zero for the next round. Here, I embed my code,

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
package Forward;

/**
 *
 * author Peter Jones
 */
// I do not extend java.lang.Thread, I'd rather to implement java.lang.Runnable to be more straight forward
public class Ex1aThread extends javax.swing.JFrame implements java.lang.Runnable{

    /** Creates new "form" Ex1bThread */
    public Ex1aThread() {
        aPanel = new javax.swing.JPanel();
        aLabel = new javax.swing.JLabel();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        setPreferredSize(new java.awt.Dimension(50, 110));
        add(aPanel);
        aPanel.add(aLabel);
        pack();
        // I start a thread just after packing.
        // I could start it from a button or a mouse click
        // or any other event
        start();
    }


    /** Start when browser is loaded or button pushed. **/
    public final void start() {
        // if thread is not active start it
        if (fThread == null){
            fThread = new java.lang.Thread (this);
            fThread.start();
        }
    } // start

    /** The thread loops to draw each frame.**/
    public void run() {
        //  Loop through animation frames
        while ( fThread != null){
            //  Sleep 100msecs between frames
            // Change this value for smoothness
            try{
                Thread.sleep (100);
                // I am counting number of loops
                ++bellTolls;
                // in each loop I "refresh" image icon of the label
                aLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("Bella.gif")));
            }
            catch  (InterruptedException e) { }
            //  Now go to other frame
            other();
            //  I check if bell tolls fifty times I kill fThread by making it null
            if (this.isDone())  fThread = null;
        }
    }// run ends
 
    //  Your other frame comes here.
    public void other(){
        //  Sleep 100msecs between frames
        // Change this value for smoothness
        try{
            Thread.sleep (100);
            // in each loop I "refresh" image icon of the label to other image
            aLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("Bellb.gif")));
        }
        catch  (InterruptedException e) { }

     }

    /*  Boolean allows you to terminate this thread, if you like, and go to other tasks.
     *  I used it to provide a flag for counting. Bell stops after fifty tolls.
     *  The true flag kills the thread, returns the counter to zero to be ready
     */
    public boolean isDone() {
        boolean temp=false;
        //COUNTS is assumed fifty times.
        if(bellTolls==COUNTS) {
            temp=true;
            // I reset the toll counting
            bellTolls=0;
        }
        // returning true kills the fThread
        return temp;
    }

    //
    //  Next main
    //
    public static void main(String args[]) {
        new Ex1aThread().setVisible(true);
    }

    //  Variables declaration - do not modify
    //  For simple GUI
    //
    private javax.swing.JLabel aLabel;
    private javax.swing.JPanel aPanel;

    //  Variables declaration - do not modify
    //  For thread animation
    //
    Thread fThread;
    int bellTolls=0; // this is toll counter
    final int COUNTS=50;
    //  End of variables declaration
}
Click here to see the application (please click on Open/Run and look at top-left corner ). Ifyou save the "jar" file in your computer you can use "7z" decompression utility to extract source file and image file.
I have created a Java Swing Ex1Thread.java class to put my animation over it. That Swing comes in the constructor "public Ex1Thread { bloh, bloh, bloh, ...}" up to the line that we see start(). start() method is invoked after packing the Swing frame by pack() method. Up to this point we do not concentrate on given codes. They are already part of our knowledge. From start() the thread task starts. By putting the start() in the constructor we have started our thread from the point that the class becomes created. (That is the reason for modifying start() as a final or as private method. Had we called it somewhere out of the constructor it simply could override the interface. Ignore these details here.) It is easy to start it from other points in the program, for instance, from action of a button. Other tutorials have done it from a button, but it is confusing since we encounter with event dispatching, then. To prove my control over the threads, in the next example I interrupt between tick-tacks with a third thread such that I have a tick-talk-tack. In this fashion I can manage as many threads in my hand. Here, I embed my code,

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
package Forward;

/**
 *
 * author Peter Jones
 */
public class Ex1bThread extends javax.swing.JFrame implements java.lang.Runnable{

    /** Creates new form Ex1bThread */
    public Ex1bThread() {

        aPanel = new javax.swing.JPanel();
        aLabel = new javax.swing.JLabel();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        setPreferredSize(new java.awt.Dimension(50, 110));
        add(aPanel);
        aPanel.add(aLabel);
        pack();
        start();
    }

    /** Start when browser is loaded or button pushed. **/
    public final void start() {
        if (fThread == null){
            fThread = new java.lang.Thread (this);
            fThread.start();
        }
    } // start

    /** The thread loops to draw each frame.**/
    public void run() {
        //  Loop through animation frames
        while ( fThread != null){
            //  Sleep 100msecs between frames
            // Change its value to adjust its smoothness.
            try{
                Thread.sleep (100);
                ++bellTolls;
                aLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("Bella.gif")));
            }
            catch  (InterruptedException e) { }
            //  Now go to other frame
            other();
            //To appreciate that you can invoke many threads as easy as one
            //create a third thread to interrupt between tick and tack
            anOther();
            if (this.isDone())  fThread = null;
        }
    }// run ends
 
    //  Your other frame comes here.
    public void other(){
        //  Sleep 100msecs between frames
        // Change its value to adjust its smoothness.
        try{
            Thread.sleep (100);
            aLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("Bellb.gif")));
        }
        catch  (InterruptedException e) { }

     }

    //  Your yet another frame comes here.
    // It is t he third thread comes interrupting inthe middle of tick tack
    public void anOther(){
        //  Sleep 100msecs between frames
        // Change its value to adjust its smoothness.
        try{
            Thread.sleep (100);
            aLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("Sun.gif")));
        }
        catch  (InterruptedException e) { }

     }

    /*  Boolean allows you to terminate this thread, if you like, and go to other tasks.
     *  I used it to provide a flag for counting. Bell stops after fifty tolls.
     *  The true flag kills the thread, returns the counter to zero to be ready
     */
    public boolean isDone() {
        boolean temp=false;
        if(bellTolls==COUNTS) {
            temp=true;
            bellTolls=0;
        }
        return temp;
    }
    
    //
    //  Next main
    //
    public static void main(String args[]) {
        new Ex1bThread().setVisible(true);
    }

    //  Variables declaration - do not modify
    //  For simple GUI
    //
    private javax.swing.JLabel aLabel;
    private javax.swing.JPanel aPanel;

    //  Variables declaration - do not modify
    //  For thread animation
    //
    Thread fThread;
    int bellTolls=0;
    final int COUNTS=50;
    //  End of variables declaration

}
Click here to see the application (please click on Open/Run and look at top-left corner ). I put a Helios (personified Sun) between bell tolls. It is done by invoking the method anOther()

No comments:

Post a Comment