An applet, as the name implies, is a kind of mini-application, designed to be downloaded over a network from a possibly untrusted source and run in a web browser or in the context of some other applet viewer application. Because of the ubiquity of web browsers, applets are a useful and powerful way of delivering Java programs to end users. In fact, it was the power of applets that popularized Java in the first place. Applets differ from regular applications in several important ways:
An applet doesn't have a main() method like a standalone Java application does. Writing an applet is a lot more like subclassing an AWT or Swing component than writing a standalone application.
An applet is not invoked using the command line, as a Java application is. Instead, an applet is embedded within an HTML file with an <APPLET> tag. And, instead of reading command-line arguments as an application does, an applet gets its arguments from <PARAM> tags in the HTML file.
An applet is usually subject to a number of strict security restrictions that prevent untrusted, and possibly malicious, applet code from damaging the host system.
This chapter briefly explains how applets are written and how they are embedded in HTML pages. It also explains the security restrictions to which applets are subject.
From a programmer's standpoint, one of the biggest differences between an applet and an application is that an applet does not have a main() method or any other single entry point from which the program starts running. Instead, to write an applet, you subclass the java.applet.Applet class (which is itself a subclass of java.awt.Panel and thus a descendant of java.awt.Component) and override a number of standard methods. At appropriate times, under well-defined circumstances, the web browser or applet viewer invokes the methods you have defined. The applet is not in control of the thread of execution; it simply responds when the browser or viewer tells it to. For this reason, the methods you write must take the necessary action and return promptly--they are not allowed to enter time-consuming (or infinite) loops. In order to perform a time-consuming or repetitive task, such as animation, an applet may create its own Thread, over which it does have complete control.
The task of writing an applet, then, comes down to defining the appropriate methods. A number of these methods are defined by the Applet class:
Called when the applet is first loaded into the browser or viewer. It is typically used to perform applet initialization, in preference to a constructor method. (If you define a constructor for your Applet, it must be a no-argument constructor, as that is what the web browser expects.) If your applet displays GUI components, they are typically created here. (Remember that the applet itself is a java.awt.Panel, so you can create components and add() them directly to the applet.)
Called when the applet is about to be unloaded from the browser or viewer. The method should free any resources, other than memory, that the applet has allocated. The destroy() method is much less commonly used than init().
Called when the applet becomes visible and should start doing whatever it is that it does. An applet that performs animation or does some other action only when it is visible needs to implement this method.
Called when the applet becomes temporarily invisible (e.g., when the user has scrolled it off the screen). Tells the applet to stop performing an animation or other task.
Called to get information about the applet (e.g., its name and author). This method should return a string suitable for display in a dialog box.
Called to obtain information about the parameters to which the applet responds. Returns a String[ ][ ] that describes the parameters.
In addition to these Applet methods, there are a variety of Component methods that an applet may want to override. The most obvious of these methods is paint(), which the browser or viewer invokes to ask the applet to draw itself on the screen.
Applets handle events in the same way that AWT and Swing applications and components do. However, for maximum portability to old web browsers such as Netscape Navigator 3 and early versions of Navigator 4, many applets use the deprecated Java 1.0 event model and override methods such as mouseDown(), mouseDrag(), keyDown(), and action().
In addition to all these methods that you override when writing an applet, the Applet class also defines some methods that you may find useful to invoke from your applet:
Loads an image file from the network and returns an Image object.
Loads a sound clip from the network and returns an AudioClip object.
Looks up and returns the value of a named parameter, specified with a <PARAM> tag in the HTML file that contains the applet.
Returns the base URL from which the applet class file was loaded.
Returns the base URL of the HTML file that refers to the applet.
Displays a message in the status line of the browser or applet viewer.
Returns the AppletContext object for the applet. AppletContext defines the useful showDocument() method that asks the browser to load and display a new web page.
Example 7-1 is a simple applet. The applet has a simple init() method but consists primarily of the paint() method that produces the applet display shown in Figure 7-1. The example also demonstrates the use of the getParameter() method to obtain the string of text that it displays.
This applet can be placed within an HTML file using the following HTML tags:
<APPLET code="MessageApplet.class" width=350 height=125> <PARAM name="message" value="Hello World"> </APPLET>
To run and display the applet, simply load the HTML file into a Java-enabled web browser. Alternatively, you can use the appletviewer program included with Sun's Java implementation to view the applet:
% appletviewer MessageApplet.html
When invoking appletviewer, you must specify the name of the HTML file that includes the applet, not the Java class file that implements the applet. We'll discuss how applets are embedded in HTML files in full detail later in this chapter.
import java.applet.*; import java.awt.*; public class MessageApplet extends Applet { protected String message; // The text to display protected Font font; // The font to display it in // One-time initialization for the applet public void init() { message = this.getParameter("message"); font = new Font("Helvetica", Font.BOLD, 48); } // Draw the applet whenever necessary public void paint(Graphics g) { // The pink oval g.setColor(Color.pink); g.fillOval(10, 10, 330, 100); // The red outline. The browser may not support Java 2D, so we // try to simulate a four-pixel-wide line by drawing four ovals. g.setColor(Color.red); g.drawOval(10,10, 330, 100); g.drawOval(9, 9, 332, 102); g.drawOval(8, 8, 334, 104); g.drawOval(7, 7, 336, 106); // The text g.setColor(Color.black); g.setFont(font); g.drawString(message, 40, 75); } }
The AWT event model changed dramatically between Java 1.0 and Java 1.1. Chapter 2, "Swing and AWTArchitecture", described the Java 1.1 event-handling model exclusively, since the Java 1.0 event model is now deprecated. However, because there is still a large installed base of web browsers that support only the Java 1.0 event model, applets are sometimes still written using this model.
In Java 1.0, all events are represented by the Event class. This class has a number of instance variables that describe the event. One of these variables, id, specifies the type of the event. Event defines a number of constants that are the possible values for the id field. The target field specifies the object (typically a Component) that generated the event or on which the event occurred (i.e., the source of the event). The other fields may or may not be used, depending on the type of the event. For example, the x and y fields are defined when id specifies a BUTTON_EVENT but not when it specifies an ACTION_EVENT. The arg field can provide additional type-dependent data.
A Java 1.0 event is dispatched first to the handleEvent() method of the Component on which it occurred. The default implementation of this method checks the id field of the Event object and dispatches the most commonly used types of events to various type-specific methods, listed in Table 7-1.
action() | keyUp() | mouseDrag() | mouseMove() |
gotFocus() | lostFocus() | mouseEnter() | mouseUp() |
keyDown() | mouseDown() | mouseExit() |
The methods listed in Table 7-1 are defined by the Component class. One of the primary characteristics of the Java 1.0 event model is that you must override these methods in order to process events. This means that you must create a subclass to define custom event-handling behavior, which is exactly what we do when we write an applet, for example. However, not all of the event types are dispatched by handleEvent() to more specific methods. If you are interested in LIST_SELECT or WINDOW_ICONIFY events, for example, you have to override handleEvent() itself, rather than one of the more specific methods. If you do this, you usually want to invoke super.handleEvent() to continue dispatching events of other types in the default way.
handleEvent() and all of the type-specific methods return boolean values. If an event-handling method returns false, as they all do by default, it means that the event was not handled, so it should be passed to the container of the current component to see if that container is interested in processing it. If a method returns true, on the other hand, it is a signal that the event has been handled and no further processing is needed.
The fact that unhandled events are passed up the containment hierarchy is important. It means that we can override the action() method in an applet in order to handle ACTION_EVENT events that are generated by the buttons within the applet. If they were not propagated up as they are, we would have to create a custom subclass of Button for every button we wanted to add to an interface!
In the Java 1.0 model, there is no de facto way to know what types of events are generated by what GUI components nor to know what fields of the Event object are filled in for what types of events. You simply have to look this information up in the documentation of individual AWT components.
Many event types use the modifiers field of the Event object to report which keyboard modifier keys were pressed when the event occurred. This field contains a bitmask of the SHIFT_MASK, CTRL_MASK, META_MASK, and ALT_MASK constants defined by the Event class. The shiftDown(), controlDown(), and metaDown() methods can be used to test for the various modifiers.
The Event class does not have a special field to indicate which mouse button was pressed when a mouse event occurs. Instead, Event uses the keyboard modifier constants for this purpose, which allows systems that use a one-button mouse to simulate other mouse buttons by using keyboard modifiers. If the left mouse button is in use, no keyboard modifiers are reported. If the right button is used, the META_MASK bit is set in the modifiers field. And if the middle button is down, the ALT_MASK bit is set.
When a keyboard event occurs, you should check the id field of the Event object to determine what kind of key was pressed. If the event type is KEY_PRESS or KEY_RELEASE, the keyboard key has an ASCII or Unicode representation, and the key fields of the event object contain the encoding of the key. On the other hand, if id is KEY_ACTION or KEY_ACTION_RELEASE, the key is a function key of some sort, and the key field contains one of the keyboard constants defined by the Event class, such as Event.F1 or Event.LEFT.
Example 7-2 shows a simple applet that allows the user to produce drawings by scribbling with the mouse. It also allows the user to erase those drawings by clicking on a button or pressing the E key. The applet overrides methods to handle mouse events, keyboard events, and action events generated by the Button component. Unlike the applet in Example 7-1, this applet does not define a paint() method. For simplicity, it does its drawing directly in response to the events it receives and does not store the coordinates. This means that it cannot regenerate the user's drawing if it is scrolled off the screen and then scrolled back on.
import java.applet.*; import java.awt.*; /** A simple applet using the Java 1.0 event-handling model */ public class Scribble extends Applet { private int lastx, lasty; // Remember last mouse coordinates Button erase_button; // The Erase button Graphics g; // A Graphics object for drawing /** Initialize the button and the Graphics object */ public void init() { erase_button = new Button("Erase"); this.add(erase_button); g = this.getGraphics(); this.requestFocus(); // Ask for keyboard focus so we get key events } /** Respond to mouse clicks */ public boolean mouseDown(Event e, int x, int y) { lastx = x; lasty = y; // Remember where the click was return true; } /** Respond to mouse drags */ public boolean mouseDrag(Event e, int x, int y) { g.setColor(Color.black); g.drawLine(lastx, lasty, x, y); // Draw from last position to here lastx = x; lasty = y; // And remember new last position return true; } /** Respond to key presses: erase drawing when user types 'e' */ public boolean keyDown(Event e, int key) { if ((e.id = = Event.KEY_PRESS) && (key = = 'e')) { g.setColor(this.getBackground()); g.fillRect(0, 0, bounds().width, bounds().height); return true; } else return false; } /** Respond to button clicks: erase drawing when user clicks button */ public boolean action(Event e, Object arg) { if (e.target = = erase_button) { g.setColor(this.getBackground()); g.fillRect(0, 0, bounds().width, bounds().height); return true; } else return false; } }
Copyright © 2001 O'Reilly & Associates. All rights reserved.