Check out the new USENIX Web site.
Using javaUSENIX

 

using java

Applets and Animation

rao_prithvi

by Prithvi Rao
<prithvi+@kiwilabs.com>

Prithvi Rao is the founder of Kiwilabs, which specializes in software engineering methodology and Java training. He has worked on the development of the MACH OS and a real-time version of MACH, and he holds two patents resulting from his work on mobile robots.


A popular of use of Java since its inception has been the creation of applets. Applets are the "other" way of running Java programs; they do not have a main method because the browser inside which they run has one instead. Applets are also special in the sense that they are "panels," whereas Java programs that are not applets do not extend java.applet.Applet.

This article focuses on one of the more interesting and popular aspects of writing applets -- animation. This typically means taking an object (text and/or graphics) and moving it on the screen. We will write a Java program that displays a "banner" in a browser. The code will include some aspects of programming with the AWT, and I'll provide pointers on how to write applets. This applet also demonstrates the use of "threads" to do animation.

The AWT and the JDK1.1 Event Model

Let's start with some fundamentals about applets. (This is a vast topic, so I won't treat it very rigorously here.)

The graphics model is one of the key elements of the Abstract Windowing Toolkit (AWT), and applets are essentially panels that are part of the AWT. Applets are often used in interactive applications that run inside browsers, and so they rely on a powerful event model in the JDK to support the interactive capability. The event model is also basic to building GUIs (another potential use of applets).

The event model has changed considerably since JDK1.0. Although I know of no applications currently running under JDK1.0, they may still exist. The JDK1.0 event model was a "containment" model in which the events passed through the entire component hierarchy, and the programmer could control which components handled the event. The JDK1.1 event model is known as a "delegation" model. In this model, event sources and listeners are created, and components register themselves with the various event listeners. The event listeners handle the events generated from registered components. We will not deal with the containment model from JDK1.0 because the subsequent releases from JDK1.1 onward use the delegation model.

Applets

Applets are "panels": The applet window has to be capable of containing other components such as text areas, buttons, and lists. The java.awt.Panel is the simplest class that can do this and be a top-level window.

One useful way to look at an applet is that it is defined by its context, such as a Web browser or appletviewer. Managing an applet means that the user must override methods such as when to start and what to do when another Web page is visited. The user must override these methods because java.applet.Applet defines them with empty bodies. These are the only methods that the user is permitted to override. However, the user is permitted to override those that Panel permits.

Example

This applet is an example of the use of a thread to do animation. The animation consists of moving some text across a background. This will also serve to introduce some new elements of the AWT, which I'll discuss as we come across them.

Let's start with the animation thread:

import java.awt.*;
import java.applet.*;

Import all relevant packages.

public class Animation extends Applet

Animation is a subclass of applet and so is an applet itself.

private Banner b;

Banner is the class that actually does the animation. We'll study that after we have looked at an applet that uses it.

private Thread animationThread;

The thread that does the animation.

public void init()

The init method that all applets must define.

resize(Integer.parseInt(getParameter("width")),
 Integer.parseInt(getParameter("height")));

Read the parameters by the HTML file and set the size of the applet.

b = new Banner("I Love Austin");

Create an instance of the banner class. The argument is an instance of String. This is the string that will move across the screen.

add(b);

This is a new method. We will look at it in more detail later, but the effect of this is to tell the AWT system that b is to be contained within the applet. Remember that the class java.applet.Applet is a subclass of Panel, and panels can contain other AWT components.

public void start()

The start method.

if (animationThread == null)
 {
  animationThread = new Thread(b);
  animationThread.start();
 }

If no thread has been created, create it with an instance of Runnable as target. b is also an AWT component and is runnable.

else if (animationThread.isAlive())
 animationThread.resume();

If it has been created and is runnable, then continue it from where it was, not from the start.

public void stop()

The stop method.

if (animationThread != null && animationThread.isAlive())
 animationThread = null

If the thread is runnable, then set it to null. The Java virtual machine will eventually notice that the thread created has no references to it and will flush it out of the system.

public void paint(Graphics g)
 {
  super.paint(g);
 }

Now let's introduce the Banner class:

class Banner extends Component implements Runnable

Notice that Banner is a subclass of Component (which is an AWT component) because it extends Component, and it is runnable because it implements the interface Runnable. As you will remember, this means that instances of the class Banner can be supplied as targets when threads are created. This is exactly what we did in the applet previously.

Now for the various fields of the class Banner.

private String bannerString;

This is the banner that is dragged across the box.

private int boxw, boxh;

The size of the box across which the banner is dragged.

private Color fgColor;

The color of the font used for drawing the banner.

private Color bgColor;

The background color of the box on which the banner string will be drawn

private Font bannerFont = new Font("Helvetica", Font.PLAIN, 36);

The font used for the banner string. We made it large . . . just like in real life.

private int[] X, Y;

An array of positions that are the starting points for drawing the banner string. The banner is first drawn at the coordinate (X[0], Y[0]), then it is moved by drawing at location (X[1], Y[1]), then at (X[2], Y[2]), and so on.

private int bannerx, bannery;

The location at which the banner is currently drawn. This will move one of the members of the array X, Y.

Now that we have the Banner class we need to do a few more things. We must provide a body to the run method. Remember that run is part of the interface Runnable, and any class implementing Runnable must also provide a body for the run method. This is the method that will be called when an instance of the class Banner is passed as the target of the thread:

public void run()

The run method has two parts. The first part does some initialization. The second part does the actual animation. I'll discuss the local variables as we come across them.

 FontMetrics fm = getFontMetrics(bannerFont);

The class FontMetrics contains information about the font family. We need that to properly position the banner within this box.

 Dimension d = getSize();

This is the size of the component: its width and height.

 boxw = d.width;
 boxh = d.height;

boxw and boxh are fields of this class.

 delta = 1;

The amount (in pixels) by which the banner is moved to the left at each step. We choose to move the string by one pixel in each new step. This is a matter of trial and error and experience. A value that is too large will make it jerky. A very small value will make it computationally expensive. This example isn't very expensive, so we choose a small value.

 sw = fm.stringWidth(bannerString);

Compute the width of this string in this font.

 n = sw/delta;

The number of steps it takes to draw the string across the box -- this is just the size of the box divided by the size of each step.

 X = new int[n];
 Y = new int[n];

Create arrays for holding the location of the first character of the banner. Each pair of elements (X[i], Y[i]) specifies a location of the first character of the banner string.

 X[0] = sw + (boxw - sw)/2;
 Y[0] = (boxh + fm.getAscent())/2;

Set the zeroth element.

for (int i = 1; i < n; i++)
 {
  X[i] = X[i - 1] - delta;
   Y[i] = Y[i - 1];
 }

The Y coordinate doesn't change, but the X coordinate is moved over to the left. Remember that we are just initializing things here; no animation is being done. We are, however, inside the thread. It is possible to move this initialization phase outside of run to the time when the banner is first created, but we chose not to do it that way.

 while (true)

Now we start the actual animation. This loop never ends, so we see the banner go round and round for ever. The loop just consists of setting the current location to a new position and then redrawing the screen -- nothing complicated.

  for (int i = 0; i < X.length; i++)

For each element of the array (could be X or Y here; they are both the same length)

  bannerx = X[i];
  bannery = Y[i];

Set the current location.

  repaint();

Repaint this component. repaint is a very important method. It has the effect of clearing the background and redrawing whatever needs to be redrawn. That is, it clears the background and calls the paint method. This is just what we need. When we change the position of the banner string, we want to rub it out at its previous location and draw it at the new location. This is just what repaint does.

 try
  {
   Thread.sleep(100L);
  }
 catch(InterruptedException ex) {}

Just sleep for a while between steps in the animation -- to slow things down a little.

 try
  {
   Thread.sleep(2000L);
  }
 catch(InterruptedException ex) {}

After going through the entire animation, stop for a while before starting again.

Finally the all-important paint method must be provided:

public void paint(Graphics g)

 Color c = g.getColor();
 Font f = getFont();

Save the values of the current font and current color. This is not really necessary, but I have put it in just to show typical programming constructs. If you need to change colors and fonts multiple times, you will have to save old values if you need them later.

 Dimension d = getSize();

The size of the box; this should be the same as boxw and boxh that we set previously. We could use those just as well.

 g.setColor(bgColor);
 g.fillRect(0, 0, d.width, d.height);

Set the color and fill this box with that color. Remember that bgColor is black, so this will give us the black background we need.

 g.setColor(fgColor);
 g.setFont(bannerFont);
 g.drawString(bannerString, bannerx, bannery);

Change the color again for drawing the banner, set the font in which the banner will be drawn, and then draw the banner string at the current location.

 g.setFont(f);
 g.setColor(c);

Strictly unnecessary, but you can reset the old values this way.

Running Applets

In order to view this applet we must now create an HTML file that has the name of the applet. This is how a browser identifies which Java class contains the applet that is to be run. The following is the HTML file for this applet. You can call this file animation.html or anything else with the same extension.

<HTML>
<HEAD>
<TITLE>Animation Applet</TITLE>
</HEAD>
<BODY>
<H2>Animation Applet</H2>
<CENTER>
<APPLET CODEBASE="." CODE="Animation.class" name=animation width=400 height=300>
<PARAM NAME=banner VALUE="I Love Austin"></APPLET>
</CENTER>
<HR>
</BODY>
</HTML>

As you can see, this is a very simple HTML file that will display a banner that says "I Love Austin." (It's supposed to be a nice place.)

Conclusion

I have demonstrated by example the use of applets to do simple animation. In the process, we gained some insight into the power of the AWT and the use of threads. The Java environment is truly a rich one for writing powerful applications, be they console-based or applets. In subsequent articles we will look at inter-applet synchronization.

 

?Need help? Use our Contacts page.
First posted: 14 Apr. 1999 jr
Last changed: 14 Apr. 1999 jr
Java index
Publications index
USENIX home