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.
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.
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.
| Method | Purpose |
| init | Called when the applet is initially loaded. |
| start | Called each time the user loads the host Web page. |
| stop | Called each time the user leaves the host Web page. |
| destroy | Called to release resources allocated by the applet. |
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 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 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.
| What | Navigator | Internet Explorer |
| Page first loaded | init + start | init + start |
| Forward then backward | stop + start | stop + start |
| Reload/Refresh | stop + start | stop + destroy + init + start |
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.
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:
| WINDOW_DESTROY | MOUSE_DRAG |
| WINDOW_EXPOSE | SCROLL_LINE_UP |
| WINDOW_ICONIFY | SCROLL_LINE_DOWN |
| WINDOW_DEICONIFY | SCROLL_PAGE_UP |
| WINDOW_MOVED | SCROLL_PAGE_UP |
| KEY_PRESS | SCROLL_ABSOLUTE |
| KEY_RELEASE | LIST_SELECT |
| KEY_ACTION | LIST_DESELECT |
| KEY_ACTION_RELEASE | ACTION_EVENT |
| MOUSE_DOWN | LOAD_FILE |
| MOUSE_UP | SAVE_FILE |
| MOUSE_MOVE | GOT_FOCUS |
| MOUSE_ENTER | LOST_FOCUS |
| MOUSE_EXIT |
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.
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.
| Member | Purpose |
| arg | Contains arbitrary, event-specific data. |
| ClickCount | The number of consecutive mouse clicks. (For example, 2 indicates a double-click.) |
| evt | The next event. |
| Id | A number representing the type of event. |
| Key | The key that was pressed if this is a keyboard event. |
| Modifiers | Indicates the state of the modifier keys (Shift, Ctrl, and so on). |
| Target | The target component for the event. |
| When | The time at which the event occurred expressed in seconds since midnight January 1, 1970 (GMT). |
| X | The x coordinate where the event occurred. |
| Y | The 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.
| Member | Purpose |
| boolean controlDown | Returns true if the Ctrl key was down. |
| boolean metaDown | Returns true if the meta key was down. |
| boolean shiftDown | Returns true if the Shift key was down. |
| String toString | Returns a formatted string showing information about the event, which can be useful for display while debugging. |
| void translate | Translates the x and y coordinates of an event relative to a component. |
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.
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.
| Member | Purpose |
| mouseDown | Called when the mouse button is pressed. |
| mouseDrag | Called when the mouse pointer is dragged while the button is held down. |
| mouseEnter | Called for a component when the mouse pointer is moved over the component. |
| mouseExit | Called for a component when the mouse pointer moves off the component. |
| mouseMove | Called when the mouse pointer is moved while the button is not held down. |
| mouseUp | Called 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;
}
}
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)
| Member | Purpose |
| keyDown | Called when a key is pressed down. |
| keyUp | Called 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:
| HOME | ||
| END | ||
| PGUP | ||
| PGDN | ||
| UP | ||
| DOWN | ||
| LEFT |
Each of these values can be accessed through the event class. For example, Event.LEFT represents the left arrow key on the keyboard.
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.
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.
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.
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>
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 |
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)
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
}
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.
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.