Chapter 4

Applet Programming Fundamentals


CONTENTS

In this chapter you learn the fundamentals of Java applet programming. You learn about the four methods that control the life span of an applet. You also learn how to write code to respond to events generated by an applet's graphical user interface. In this chapter you also see how to use applet parameters to control the behavior of a program. Finally, you learn about Uniform Resource Locators (URLs) and how to display simple graphics.

The Applet Class

To create your own applets, you derive a class from Java's Applet class and then add the desired functionality. The Applet class contains methods for actions such as interacting with the browser environment in which it is running, for retrieving images, for playing sound files, and for resizing its host window. In this section you learn about the most frequently used methods in this important class.

The Life and Death of an Applet

On a typical Java-enhanced Web page, Java applets start and stop frequently as the user switches among pages. As pages are loaded into the browser, viewed and then left, applets are started and terminated in response to messages passed to the Applet class. The four most important methods in the life of an applet are init, start, stop, and destroy. They are described in Table 4.1.

Table 4.1. Important methods over the life of an applet.

MethodPurpose
initCalled when the applet is initially loaded.
startCalled each time the user loads the host Web page.
stopCalled each time the user leaves the host Web page.
destroyCalled to release resources allocated by the applet.

The init Method

When an applet is first loaded by either a browser or a stand-alone interpreter such as is provided with Visual J++, the init method is called. This allows the applet to execute any startup code that is necessary. Usually an applet will resize itself at this point. The applet may also acquire and load resources such as images or sound at this point. The init method will be called only once for each time the applet is loaded.

The destroy Method

The destroy method is called when the browser is closing an applet. Ideally this method should be used to release any resources that have been allocated during the life of the applet; however, because Java performs garbage collection, it is not necessary to release resources.

TIP
Although you do not need to explicitly release resources, it is generally a good practice to do so. By explicitly releasing a resource, rather than waiting for Java's garbage detection to notice a resource has been released, your program will be able to reuse the resource sooner

The start and stop Methods

The start method is similar to init except that start is called each time the Web page in which the applet is embedded is loaded. The most frequent use of the start method is to create a new thread. Similarly, the stop method is called whenever the browser moves off the Web page that hosts the applet.

The distinction between a method that gets called when an applet is first loaded and when its host page is first loaded might seem like a fine distinction, but understanding this distinction enables you to write more efficient applets. In Netscape Navigator 3 and Microsoft Internet Explorer 3, when a page containing a Java applet is first loaded, the init and start methods are called. Following a link from the page calls the applet's stop method. Backing up to the page calls the applet's start method, but not its init method.

In Netscape Navigator, reloading a page that contains an applet will stop and then start the applet. Performing the equivalent function in Microsoft Internet Explorer, however, causes the stop, destroy, init, and start methods all to be invoked in that order. For convenience, this information is summarized in Table 4.2.

Table 4.2. Applet method calls under Navigator and Internet Explorer.

WhatNavigator Internet Explorer
Page first loadedinit + start init + start
Forward then backwardstop + start stop + start
Reload/Refreshstop + start stop + destroy + init + start

An Example

The best way to understand how the init, start, stop, and destroy methods interact is to build an applet to demonstrate their use. Listing 4.1 shows a class that does exactly this. The class EX04A includes a private string member named history that is empty initially. As the various methods are called, text is added to this string to indicate the sequence in which the methods were called. Parentheses are placed around the start and stop messages to improve readability.


Listing 4.1. EX04A.java.
import java.applet.*;
import java.awt.*;

public class EX04A extends Applet
{
    private String history = "";


    public EX04A()
    {
    }

    public void init()
    {
        history = history + "init ";
        resize(320, 240);
    }

    public void start()
    {
        history = history + "(start ";
    }
    
    public void stop()
    {
        history = history + "stop) ";
    }

    public void destroy()
    {
        history = history + "destroy ";
    }

    public void paint(Graphics g)
    {
        g.drawString(history, 10, 10);
    }
}

NOTE
Even though the code in the destroy method of Listing 4.1 will execute, the results of adding this text will not be apparent. Because the history string is displayed only by the paint method and paint is not called after destroy, you will not be able to see the destroy message. You've got two options: Either trust me or run EX04A in the debugger after setting a breakpoint in destroy

The result of a sample run of EX04A is shown in Figure 4.1. In this case, Netscape Navigator was used to run this applet. After the applet was loaded, the Reload button was pressed repeatedly. This had the effect of stopping and starting the applet each time, as you can see in Figure 4.1. Closing Navigator will stop the applet and then destroy it.

Figure 4.1 : Example of reloading an applet in Netscape Navigator.

Unlike Navigator, Microsoft Internet Explorer does not simply stop and start an applet when refreshing a page. Figure 4.2 shows Internet Explorer while running EX04A after the Refresh button was pressed repeatedly. As you can see, only init and start have been used. This is because Internet Explorer completely reloads an applet when refreshing it. This causes the history string to be reset each time the applet is reloaded.

Figure 4.2 : Example of reloading an applet in Microsoft Intenet Explorer.

Event Handling

The Java Virtual Machine works by sending messages to Java applets whenever specific events occur. For example, if the user presses a key, a message named KEY_PRESS is passed to the applet. If a Java applet wants to respond in a particular way to a message, a handler for that message is written. The complete list of Java messages follows:

Java messages

WINDOW_DESTROYMOUSE_DRAG
WINDOW_EXPOSESCROLL_LINE_UP
WINDOW_ICONIFYSCROLL_LINE_DOWN
WINDOW_DEICONIFYSCROLL_PAGE_UP
WINDOW_MOVEDSCROLL_PAGE_UP
KEY_PRESSSCROLL_ABSOLUTE
KEY_RELEASELIST_SELECT
KEY_ACTIONLIST_DESELECT
KEY_ACTION_RELEASEACTION_EVENT
MOUSE_DOWNLOAD_FILE
MOUSE_UPSAVE_FILE
MOUSE_MOVEGOT_FOCUS
MOUSE_ENTERLOST_FOCUS
MOUSE_EXIT 

The Component Class

In Java, events are generated in response to a user's interaction with the graphical user interface (GUI) of a program. As events are generated, they are sent to the component in or over which they occurred. The Component class is an abstract class, so instances of it cannot be created directly. However, it serves as the superclass for almost all parts of a program's user interface. This allows events to be sent to the specific part of the user interface that will be best able to interpret the message.

For example, if the user presses the mouse button down while the mouse pointer is over a button, the MOUSE_DOWN event is sent to the button object. This works because Button is a subclass of Component. If the button object chooses not to handle the event, it can be passed up to the object on which the button is located, usually a Window or Dialog object. That object will then have the option of handling the event, ignoring it, or passing it up to a higher level. Figure 4.3 shows a class hierachy of the subclasses of Component, which is a very active superclass.

Figure 4.3 : The descendants of Component.

The Event Class

When an event occurs, it is passed to the event handling methods of a component as an instance of the Event class. This class is defined in the java.awt package. At the time the event occurs, an instance of Event is created and member variables are used to store information about the event and the state of the system at the time. For example, if a KEY_PRESS event occurs, it may be useful to know whether the Shift key was being held down at the time. Similarly, when the mouse is clicked, it is usually important to know the x and y coordinates of the mouse pointer when the click occurred. All relevant information about an event is stored in the member variables of the Event class, as shown in Table 4.3.

Table 4.3. The member variables of Event.

MemberPurpose
argContains arbitrary, event-specific data.
ClickCountThe number of consecutive mouse clicks. (For example, 2 indicates a double-click.)
evtThe next event.
IdA number representing the type of event.
KeyThe key that was pressed if this is a keyboard event.
ModifiersIndicates the state of the modifier keys (Shift, Ctrl, and so on).
TargetThe target component for the event.
WhenThe time at which the event occurred expressed in seconds since midnight January 1, 1970 (GMT).
XThe x coordinate where the event occurred.
YThe y coordinate where the event occurred.

In addition to the member variables shown in Table 4.3, the Event class includes some public methods you will find useful in handling events. These are shown in Table 4.4. Many of these public variables and methods are described in detail and used in examples in the following sections of this chapter where mouse and keyboard event handling are covered.

Table 4.4. The public, nonconstructor member methods of Event.

MemberPurpose
boolean controlDownReturns true if the Ctrl key was down.
boolean metaDownReturns true if the meta key was down.
boolean shiftDownReturns true if the Shift key was down.
String toStringReturns a formatted string showing information about the event, which can be useful for display while debugging.
void translateTranslates the x and y coordinates of an event relative to a component.

Handling Any Event

Java provides a single method, handleEvent in the java.awt.Component class that can be used to process all events. This method is passed an Event object that contains all of the information necessary to handle the event. As an example, consider the code for EX04B, shown in Listing 4.2.


Listing 4.2. EX04B.java.
import java.applet.*;
import java.awt.*;

public class EX04B extends Applet
{
    private int xPosStart=0, xPosEnd=0;
    private int yPosStart=0, yPosEnd=0;
    private boolean drawing = false;

    public void init()
    {
        resize(320, 240);
    }


    public void paint(Graphics g)
    {
        if (drawing)
            g.drawLine(xPosStart, yPosStart, xPosEnd, yPosEnd);
    }

    public boolean handleEvent(Event event) {
        boolean result;

        switch (event.id) {
        case Event.MOUSE_DOWN:
            drawing = true;
            xPosStart = event.x;
            yPosStart = event.y;
            xPosEnd   = xPosStart;
            yPosEnd   = yPosStart;
            repaint();
            result = true;
            break;
        case Event.MOUSE_UP:
            drawing = false;
            repaint();
            result = true;
            break;
        case Event.MOUSE_DRAG:
            xPosEnd = event.x;
            yPosEnd = event.y;
            repaint();
            result = true;
            break;
        default:
            result = super.handleEvent(event);
            break;
        }
        return result;
    }
}

This example includes a handleEvent method that uses a switch statement to act on the MOUSE_DOWN, MOUSE_UP, and MOUSE_DRAG events. This applet implements a very simple drawing program in which a line is drawn from the location where the mouse button is pressed to the mouse pointer's current location while the mouse is being dragged. When the mouse button is released, the drawing stops.

When the MOUSE_DOWN event occurs, a private member variable, drawing, is set to true to indicate that the user wants to draw a line while the mouse button is held down. The current location of the mouse pointer is retrieved from the x and y members of event and stored in private member variables. These will serve as the starting and ending points for the line that the applet will draw.

The MOUSE_DRAG event is caught and also retrieves values from event.x and event.y. This time, however, these values indicate the end of the line being drawn. After being stored, the repaint method is called to tell the applet to redisplay itself. This causes the paint method to be invoked. The paint method of EX04B is written so that it will draw a line between the stored locations if the value of drawing is true. Because drawing was set to true when the mouse button was pushed down, the line will be drawn and updated as long as the mouse button remains depressed. This can be seen in Figure 4.4. When a MOUSE_UP event is caught, it sets drawing to false to indicate that the user is done drawing the line and then repaints the screen.

Figure 4.4 : The results of running EX04B.

You may have noticed in Listing 4.2 that handleEvent is a boolean method. In order to indicate that the event has been successfully dealt with, handleEvent must return true. If an event is received that handleEvent would prefer not to deal with, but would rather pass up to its parent, false can be returned.

Event Handling for the Mouse

While handleEvent provides a very flexible and powerful way of catching and acting on Java events, it is sometimes tedious to have to look inside the supplied Event object for the necessary values. Because mouse and keyboard events are so common, Java includes a simple set of methods customized for use with these events. Mouse event handling is made simpler by the methods listed in Table 4.5.

Table 4.5. Methods for handling mouse events directly.

MemberPurpose
mouseDownCalled when the mouse button is pressed.
mouseDragCalled when the mouse pointer is dragged while the button is held down.
mouseEnterCalled for a component when the mouse pointer is moved over the component.
mouseExitCalled for a component when the mouse pointer moves off the component.
mouseMoveCalled when the mouse pointer is moved while the button is not held down.
mouseUpCalled when the mouse button is released.

The signature for each of these methods is the same. For example, the signature for mouseDrag is as follows:

public boolean mouseDrag(Event evt, int x, int y)

In handling a mouse event, the first thing a method usually looks at is the location of the mouse pointer (as given by its x and y coordinates) when the event occurred. Because these values are so frequently used, they are passed directly to the mouse event-handling methods. There is an additional advantage to using the event-specific methods instead of the generic handleEvent. By using these functions, you can reduce the clutter that is caused by involving many case statements inside handleEvent.

As a simple example of how to use one of the mouse event methods, consider the code for class EX04C in Listing 4.3. EX04C is similar to EX04B in allowing the user to draw a line on the screen. However, EX04C differs in a few small ways:


Listing 4.3. EX04C.java.
import java.applet.*;
import java.awt.*;

public class EX04C extends Applet
{
    private int xPos=0, yPos=0;

    public EX04C()
    {
    }

    public void init()
    {
        resize(320, 240);
    }

    public void paint(Graphics g)
    {
        g.drawLine(0, 0, xPos, yPos);
    }

    public boolean mouseDrag(Event evt, int x, int y)
    {
        xPos = x;
        yPos = y;
        repaint();
        return true;
    }
}

Because of the simplifications to the applet, EX04C requires only the use of the mouseDrag method. Similar to the MOUSE_DRAG case of handleEvent, mouseDrag stores the location of the mouse pointer and then repaints the applet. Of course, because x and y have been provided as parameters they are used directly instead of evt.x and evt.y.

The simplifications of EX04C are removed in EX04D, which is shown in Listing 4.4. In this case, mouseDown, mouseUp, and mouseDrag are all used. The applet will respond by drawing a line from the location where the mouse button was pushed down, to its current location while the mouse is dragged, and then remove the line once the mouse button is released.


Listing 4.4. EX04D.java.
import java.applet.*;
import java.awt.*;

public class EX04D extends Applet
{
    private int xPosStart=0, xPosEnd=0;
    private int yPosStart=0, yPosEnd=0;
    private boolean drawing = false;

    public EX04D()
    {
    }

    public void init()
    {
        resize(320, 240);
    }

    public void paint(Graphics g)
    {
        if (drawing)
            g.drawLine(xPosStart, yPosStart, xPosEnd, yPosEnd);
    }

    public boolean mouseDown(Event evt, int x, int y)
    {
        drawing = true;
        xPosStart = x;
        yPosStart = y;
        xPosEnd   = xPosStart;
        yPosEnd   = yPosStart;
        return true;
    }

    public boolean mouseUp(Event evt, int x, int y)
    {
        drawing = false;
        repaint();
        return true;
    }

    public boolean mouseDrag(Event evt, int x, int y)
    {
        xPosEnd = x;
        yPosEnd = y;
        repaint();

        return true;
    }
}

Keyboard Event Handling

Directly handling keyboard events is similar to handling mouse events. Two methods, keyDown and keyUp, are provided. These methods are summarized in Table 4.6. The signature for each method is the same and is as follows:

public boolean keyDown(Event evt, int key)

Table 4.6. Methods for directly handling keyboard events.

MemberPurpose
keyDownCalled when a key is pressed down.
keyUpCalled when a key is released.

In addition to the keys that generate displayable characters, Java supports the usual set of navigational and function keys. The Event class defines values for the following special keys:

Values for Java keys

HOME
RIGHT
F7
END
F1
F8
PGUP
F2
F9
PGDN
F3
F10
UP
F4
F11
DOWN
F5
F12
LEFT
F6
 

Each of these values can be accessed through the event class. For example, Event.LEFT represents the left arrow key on the keyboard.

The Shift, Control, and Meta Modifiers

Sometimes a key is augmented by the use of shift, control, or other modifiers. In Java you can distinguish between an unmodified key and one combined with the Shift or Ctrl key.

Earlier in this chapter you learned that the Event class contains a member named modifiers. When an event is generated, modifiers holds the state of the Shift, Ctrl, and meta keys. To discern the state of these keys, you can either look directly at modifiers or you can use the provided utility methods controlDown, shiftDown, and metaDown.

An Example of Keyboard Event Handling

As an example of keyboard event handling, consider class EX04E in Listing 4.5. This example uses the keyDown method to trap for the up, down, left arrow, and the alphabetic (upper- and lowercase) keys.


Listing 4.5. EX04E.java.
import java.applet.*;
import java.awt.*;

public class EX04E extends Applet
{
    int    yRow = 1;

    public void init()
    {
        resize(320, 240);
    }

    public void paint(Graphics g)
    {
    }

    public boolean keyDown(Event event, int key) {
        boolean result = false;

        Graphics g = getGraphics();

        switch(key) {
        case Event.UP:
            g.drawString("the up key", 10, yRow++ * 10);
            result = true;
            break;
        case Event.DOWN:
            g.drawString("the down key", 10, yRow++ * 10);
            result = true;
            break;
        case Event.LEFT:
            StringBuffer str = new StringBuffer("you pressed: ");
            if (event.controlDown())
                str.append("control + ");
            if (event.shiftDown())
                str.append("shift + ");

            str.append("left");
            
            g.drawString(str.toString(), 10, yRow++ * 10);
            result = true;
            break;
        default:
            if((key >= 65 && key <= 90) ||          // upper case
                    (key >= 97 && key <= 122)) {    // lower case
                Character ch = new Character((char)key);
                g.drawString(ch.toString(), 10, yRow++ * 10);
                result = true;
            }
            break;
        }
        return result;
    }
}

In this example, the applet will write a message to the display describing the key that is pressed. Class EX04E starts by defining a member variable, yRow, that will be used to keep track of the number of rows written so that each call to g.drawString can write at a higher y coordinate, so the messages appear to move down the applet's window. This can be seen in Figure 4.5, which was created after several keys had been pressed. Before the applet window will receive the keypress messages, the browser window needs to have focus. Click the mouse while the pointer is over the applet area.

Figure 4.5 : The results of running EX04E.

In the keyDown method of EX04E, a switch statement is used to distinguish between the keys. If the up or down arrow is pressed, a simple message is displayed on the screen. However, if the left arrow is pressed, the applet uses the controlDown and shiftDown methods to determine which keys were down when the left arrow key was pressed. A string is created to display the modifier information and then the string is displayed.

In the default case, the value of key is checked. If the key is an upper- or lowercase letter, the key is converted from an integer and displayed.

Using Applet Parameters

In the traditional, non-Java programming world, it is common to write a program that uses command-line parameters to modify its behavior. For example, the grep program searches for string patterns in files. To search for java.awt in all files with a Java extension, you would use the following command line:

grep java.awt *.java

Without command-line parameters, the grep program would be useless because it wouldn't know either the pattern to look for or the files to search. Because Java applets are not run from a command line, as is grep, an applet cannot be passed a parameter in this fashion. However, a Java applet is embedded in a host HTML file, and parameters to the applet can be embedded in the HTML file.

Embedding Parameters in HTML

To embed a parameter in a host HTML document you use the <param name> tag. For each parameter you create with this tag, you specify a name and a value. For example, Listing 4.6 is the host HTML file for EX04F. It describes three parameters: message, xPos, and yPos. The message parameter will be displayed in the browser window by the applet and is set to "Hello, World". The xPos and yPos parameters indicate the coordinates at which the message will be displayed.


Listing 4.6. EX04F.html.
<html>
<head>
<title>EX04F</title>
</head>
<body>
<hr>
<applet
    code=EX04F.class
    id=EX04F
    width=320
    height=240 >
    <param name=message value="Hello, World">
    <param name=xPos value=30>
    <param name=yPos value=40>
</applet>
<hr>
<a href="EX04F.java">The source.</a>
</body>
</html>

Reading Applet Parameters

An applet can read parameters from its host HTML file by using the getParameter method of the Applet class. The signature of getParameter is as follows:

public String getParameter(String name)

The getParameter method is passed the name of the parameter to read, and it returns the value of that parameter as a string. Although all parameters are read as string values, they can easily be converted to integers or any other more appropriate data type. This is illustrated in Listing 4.7, which shows the class EX04F. This applet reads the message, xPos, and yPos parameters that were embedded in the HTML file of Listing 4.6. An example of running this applet is shown in Figure 4.6.

Figure 4.6 : EX04F displays a parameter from its host HTML file.


Listing 4.7. EX04F.java.
import java.applet.*;
import java.awt.*;

public class EX04F extends Applet
{
    private String message = "";
    private int xPos = 10;
    private int yPos = 10;

    public void init()
    {
        String param;

        param = getParameter("message");
        if (param != null)
            message = param;

        param = getParameter("xPos");
        if (param != null)
            xPos = Integer.parseInt(param);

        param = getParameter("yPos");
        if (param != null)
            yPos = Integer.parseInt(param);

        resize(320, 240);
    }

    public void paint(Graphics g)
    {
        g.drawString(message, xPos, yPos);
    }
}

NOTE
You can use the Applet Wizard to simplify the use of parameters. The fourth step of the Applet Wizard lets you enter parameter names, types, and default values. When the wizard generates the applet, it will generate class member variables to hold the parameter values and will place code in the init method to retrieve the values

Working with URLs and Graphics

One of the most common things for a Web page to do is display a graphic. Because of this, the Applet class includes a method for retrieving an image from a URL (a Uniform Resource Locator, the way in which files are addressed on the Internet). The signature for getImage is as follows:

public Image getImage(URL url)

Accessing a URL

Because getImage loads an image from a URL, you must first create an instance of a URL. This can be done by using the following URL constructor:

public URL(String spec) throws MalformedURLException

This constructor is simply passed to the URL as a string, as in the following example:

myURL = new URL("http://mtngoat/java/test.jpg");

However, because the constructor can throw a MalformedURLException exception, the constructor must be enclosed in a try...catch block that catches the exception. This could be done as follows:

try {
    myURL = new URL("http://mtngoat/java/test.jpg");
}
catch (MalformedURLException e) {
    // handle error
}

An Example of Displaying an Image

The getImage method retrieves an image from a URL but does not display it. To display the retrieved image, use the Graphics.drawImage method in the paint method of the applet. This can be seen in EX04G, which is shown in Listing 4.8.


Listing 4.8. EX04G.java.
import java.applet.*;
import java.awt.*;
import java.net.*;


public class EX04G extends Applet
{
    private Image m_image;
    private URL m_URL;
    private String error = "";

    public void init()
    {
        resize(600, 440);

        try {
          m_URL = new 
            URL("http://spider.innercite.com/~lcohn/savannah.jpg");
          m_image = getImage(m_URL);        
        }
        catch (MalformedURLException e) {
          error = "Image is unavailable.";
        }
    }

    public void paint(Graphics g)
    {
        g.drawString("Here's a cute baby:", 10,10);

        if (error.length() == 0)
            g.drawImage(m_image, 10, 30, this);
        else
            g.drawString(error, 20, 30);
    }
}

This example creates a URL object and then uses that object as a parameter to getImage. If an exception occurs, the image is not loaded but an error message is formatted. The paint method displays a string above the image and then displays either the image or the error message. The results of running this applet can be seen in Figure 4.7.

Figure 4.7 : Displaying a graphic loaded from a URL.

Summary

This chapter covered a lot of ground. You learned how an applet's init, start, stop, and destroy methods are executed over the life of an applet. Because understanding event handling is critical to applet development, this chapter presented numerous examples of how to handle events. You learned about generic event handling with the handleEvent method as well as how to handle events with mouse- and keyboard-specific methods. This chapter also demonstrated how to customize the behavior of an applet by using applet parameters embedded in the host HTML file. Finally, you got a quick introduction into loading a graphics resource from a URL and displaying it in an applet. In the next chapter, you will turn your attention to enhancing applets by using windows and dialogs.