Writing Applets
- Overview
- Taking Advantage of the Applet API
- Finishing an Applet
- Before You Ship That Applet,
- Common Problems (and Their Solutions)
Overview
Every applet is implemented by creating a subclass of the Applet class.
Below is the source code for an applet called Simple. The Simple applet displays a descriptive string whenever it encounters a major milestone in its life, such as when the user first visits the page the applet's on. The pages that follow use the Simple applet and build upon it to illustrate concepts that are common to many applets.
/* * 1.0 code. */ import java.applet.Applet; import java.awt.Graphics; public class Simple extends Applet { StringBuffer buffer; public void init() { buffer = new StringBuffer(); addItem("initializing... "); } public void start() { addItem("starting... "); } public void stop() { addItem("stopping... "); } public void destroy() { addItem("preparing for unloading..."); } void addItem(String newWord) { System.out.println(newWord); buffer.append(newWord); repaint(); } public void paint Graphics(g) { //Draw a Rectangle around the applet's display area. g.drawRect(0, 0, size().width - 1, size().height - 1); //Draw the current string inside the rectangle. g.drawString(buffer.toString(), 5, 15); } }
HelloWorld Applet
Here is the HelloWorld applet:
import java.applet.Applet; import java.awt.Graphics; public class HelloWorld extends Applet { public void paint Graphics(g) { g.drawString("Hello world!", 50, 25); } }The extends keyword indicates that HelloWorld is a subclass of Applet. From the Applet class, applets inherit the ability to respond to browser requests.
Every applet must also implement an init, start, or paint method:
import java.applet.Applet; import java.awt.Graphics; public class HelloWorld extends Applet { public void paint Graphics(g) { g.drawString("Hello world!", 50, 25); } }Applets can also implement the stop or destroy methods when the browser leaves the applet's page.
The Life Cycle of an Applet
Below is the Simple applet.
Because some old browsers don't support 1.1, the above applet is a 1.0 version (here is the 1.0 code; here's the 1.1 code). To run the 1.1 version of the applet, go to example-1dot1/Simple.html.
Loading the Applet
You should see "initializing... starting..." above, as the result of the applet being loaded. When an applet is loaded, here's what happens:
- An instance of the applet's controlling class (an Applet subclass) is created.
- The applet initializes itself.
- The applet starts running.
Leaving and Returning to the Applet's Page
When the user leaves the page, for example, to go to another page, applet has the option of stopping itself. When the user returns to the page, the applet can start itself again. The same sequence occurs when the user iconifies and then reopens the window that contains the applet. (Other terms used instead of iconify are minaturize, minimize, and close.)
Leave and then return to this page. You'll see "stopping..." added to the applet output above, as the applet is given the chance to stop itself. You'll also see "starting...", when the applet is told to start itself again. Next, iconify this window, and then open it again. Many window systems provide a button in the title bar that lets you iconify the window. You should see "stopping...." and then "starting...." added to the applet output.
Some browsers reload the applet when you return to its page. In at least one browser, a bug exists where an applet can initialize itself more than once without being reloaded.
Reloading the Applet
Some browsers let the user reload applets, which consists of unloading the applet and then loading it again. Before an applet is unloaded, it's given the chance to stop itself and then to perform a final cleanup, so that the applet can release any resources it holds. After that, the applet is unloaded and then loaded againIf your browser or other applet viewer lets you easily reload applets, reload the applet. Look at the standard output to see what happens when you reload the applet.
You should see "stopping..." and "preparing for unloading..." when the applet is unloaded. You can't see this in the applet GUI because the applet is unloaded before the text can be displayed. When the applet is reloaded, you should see "initializing..." and "starting...", just like when you loaded the applet for the first time.
Quitting the Browser
When the user quits the browser (or whatever application is displaying the applet), the applet has the chance to stop itself and do final cleanup before the browser exits.
Summary
An applet can react to major events in the following ways:
- It can initialize itself.
- It can start running.
- It can stop running.
- It can perform a final cleanup, in preparation for being unloaded.
Methods for Milestones
The Simple applet, like every other applet, features a subclass of the Applet class. The Simple class overrides four Applet methods so that it can respond to major events:public class Simple extends Applet { . . . public void init() { . . . } public void start() { . . . } public void stop() { . . . } public void destroy() { . . . } . . . }
- init
- To initialize the applet each time it's loaded (or reloaded).
- start
- To start the applet's execution, such as when the applet's loaded or when the user revisits a page that contains the applet.
- stop
- To stop the applet's execution, such as when the user leaves the applet's page or quits the browser.
- destroy
- To perform a final cleanup in preparation for unloading.
Not every applet needs to override every one of these methods. Some very simple applets override none of them. The "Hello World" applet just displays a string once, using its paint method. Most applets, however, do more.
The init method is useful for one-time initialization that doesn't take very long. In general, the init method should contain the code that you would normally put into a constructor. The reason applets shouldn't usually have constructors is that an applet isn't guaranteed to have a full environment until its init method is called. For example, the Applet image loading methods simply don't work inside of a applet constructor. The init method, on the other hand, is a great place to call the image loading methods, since the methods return quickly.
Some browsers sometimes call the init method more than once after the applet has been loaded.
Every applet that does something after initialization (except in direct response to user actions) must override the start method. The start method either performs the applet's work or (more likely) starts up one or more threads to perform the work.
Most applets that override start should also override the stop method. The stop method should suspend the applet's execution, so that it doesn't take up system resources when the user isn't viewing the applet's page. For example, an applet that displays animation should stop trying to draw the animation when the user isn't looking at it.
Many applets don't need to override the destroy method, since their stop method (which is called before destroy) does everything necessary to shut down the applet's execution. However, destroy is available for applets that need to release additional resources.
Methods for Drawing and Event Handling
The Simple applet defines its onscreen appearance by overriding the paint method:class Simple extends Applet { . . . public void paint Graphics(g) { . . . } . . . }The paint method is one of two display methods an applet can override:
- paint
- The basic display method. Many applets implement the paint method to draw the applet's representation within a browser page.
- update
- A method you can use along with paint to improve drawing performance.
Applets inherit their paint and update methods from the Applet class, which inherits them from the Abstract Window Toolkit (AWT) Component class. For an overview of the Component class, and the AWT in general, see the Overview of the Java UI trail. Within the overview, the architecture of the AWT drawing system is discussed on the Drawing page.
Applets inherit a group of event-handling methods from the Component class. (The architecture of the AWT event system is discussed on the Events The Component class defines several methods, such as action and mouseDown, for handling particular types of events, and then one catch-all method called handleEvent.
To react to an event, an applet must override either the appropriate event-specific method or the handleEvent method. For example, adding the following code to the Simple applet makes it respond to mouse clicks.
import java.awt.Event; . . . public boolean mouseDown Event(event, int x, int y) { addItem("click!... "); return true; }Below is the resulting applet. When you click within its rectangle, it displays the word "click!...".
Because some old browsers don't support 1.1, the above applet is a 1.0 version (here is the 1.0 code; here's the 1.1 code). To run the 1.1 version of the applet, go to example-1dot1/SimpleClick.html.
Adding UI Components
Buttons java.awt.Button Checkboxes java.awt.Checkbox Single-line text fields java.awt.TextField Larger text display and editing areas java.awt.TextArea Labels java.awt.Label Lists java.awt.List Pop-up lists of choices java.awt.Choice Sliders and scrollbars java.awt.Scrollbar Drawing areas java.awt.Canvas Menus java.awt.Menu
java.awt.MenuItem
java.awt.CheckboxMenuItemContainers java.awt.Panel
java.awt.Window
Methods for Using UI Components in Applets
Because the Applet class inherits from the AWT Container class, it's easy to add components to applets and to use layout managers to control the components' onscreen positions. Here are some of the Container methods an applet can use:
- add
- Adds the specified Component.
- remove
- Removes the specified Component.
- setLayout
- Sets the layout manager.
Adding a Non-Editable Text Field to the Simple Applet
To make the Simple applet use a scrolling, non-editable text field, we can use the TextField class. Here is the revised source code. The changes are shown below.//Importing java.awt.Graphics is no longer necessary //since this applet no longer implements the paint method. . . . import java.awt.TextField; public class ScrollingSimple extends Applet { //Instead of using a StringBuffer, use a TextField: TextField field; public void init() { //Create the text field and make it uneditable. field = new TextField(); field.setEditable(false); //Set the layout manager so that the text field will be //as wide as possible. setLayout(new java.awt.GridLayout(1,0)); //Add the text field to the applet. add(field); validate(); addItem("initializing... "); } . . . void addItem(String newWord) { //This used to append the string to the StringBuffer; //now it appends it to the TextField. String t = field.getText(); System.out.println(newWord); field.setText(t + newWord); repaint(); } //The paint method is no longer necessary, //since the TextField repaints itself automatically.The revised init method creates an uneditable text field (a TextField instance). It sets the applet's layout manager to one that makes the text field as wide as possible
After all this, the init method calls the validate method (which Applet inherits from Component). Invoking validate once after adding one or more Components to an applet is a bit of voodoo that ensures that the Components draw themselves onscreen.
Below is the resulting applet.
Security Restrictions
Every browser implements security policies to keep applets from compromising system security. This section describes the security policies that current browsers adhere to. However, the implementation of the security policies differs from browser to browser. Also, security policies are subject to change. For example, if a browser is developed for use only in trusted environments, then its security policies will likely be much more lax than those described here.Current browsers impose the following restrictions on any applet that is loaded over the network:
Each browser has a SecurityManager object that implements its security policies. When a SecurityManager detects a violation, it throws a SecurityException. Your applet can catch this SecurityException and react appropriately.
- An applet cannot load libraries or define native methods.
- It cannot ordinarily read or write files on the host that's executing it.
- It cannot make network connections except to the host that it came from.
- It cannot start any program on the host that's executing it.
- It cannot read certain system properties.
- Windows that an applet brings up look different than windows that an application brings up.
Applet Capabilities
The java.applet package provides an API that gives applets some capabilities that applications don't have. For example, applets can play sounds, which other programs can't do yet.Here are some other things that current browers and other applet viewers let applets do:
- Applets can usually make network connections to the host they came from.
- Applets running within a Web browser can easily cause HTML documents to be displayed.
- Applets can invoke public methods of other applets on the same page.
- Applets that are loaded from the local file system (from a directory in the user's CLASSPATH) have none of the restrictions that applets loaded over the network do.
- Although most applets stop running once you leave their page, they don't have to.
Test Driving an Applet
Once you've written some code for your applet, you'll want to run your applet to test it. To run an applet, you first need to add the applet to an HTML page, using the <APPLET> tag. You then specify the URL of the HTML page to your Java-enabled browser.
Because you can't always rely on browsers to reload your applet's classes, you might want to use a quick-starting tool like the JDK Applet Viewer for most of your applet testing. Every time you change your applet, you can restart the Applet Viewer to make sure it loads all of the latest classes.
Here's the simplest form of the <APPLET> tag:
<APPLET CODE=AppletSubclass.class m>anInt HEIGHT=anInt> </APPLET>This tag tells the browser to load the applet whose Applet subclass is named AppletSubclass. The following figure shows where the applet class file must be, relative to the HTML document that contains the <APPLET> tag. As the figure shows, unless the applet is declared to be in a package, its class file should be in the same directory as the HTML file that has the <APPLET> tag.
When a Java-enabled browser encounters an <APPLET> tag, it reserves a display area of the specified width and height for the applet, loads the bytecodes for the specified Applet subclass, creates an instance of the subclass, and then calls the instance's init and start methods.
The <APPLET> tag has many options that you can use to customize your applet's execution. For example, you can put your applet's files into an archive. You can also specify parameters to be passed to the applet.
Summary
First you learned that to write an applet, you must create a subclass of the java.applet Applet class. In your Applet subclass, you must implement at least one of the following methods: init, start, and paint. The init and start methods, along with stop and destroy, are called when major events (milestones) occur in the applet's life cycle. The paint method is called when the applet needs to draw itself to the screen.
The Applet class extends the AWT Panel class, which extends the AWT Container class, which extends the AWT Component class. From Component, an applet inherits the ability to draw and handle events. From Container, an applet inherits the ability to include other components and to have a layout manager control the size and position of those components. From Applet, an applet inherits several capabilities, including the ability to respond to major milestones, such as loading and unloading. You'll learn more about what the Applet class provides as you continue along this trail.
You include applets in HTML pages using the <APPLET> tag. When a browser user visits a page that contains an applet, here's what happens:
- The browser finds the class file for the applet's Applet subclass. The location of the class file (which contains Java bytecodes) is specified with the CODE and CODEBASE attributes of the <APPLET> tag.
- The browser brings the bytecodes over the network to the user's computer.
- The browser creates an instance of the Applet subclass. When we refer to an applet, we're generally referring to this instance.
- The browser calls the applet's init method. This method performs any one-time initialization that is required.
- The browser calls the applet's start method. This method often starts a thread to perform the applet's duties.
An applet's Applet subclass is its main, controlling class, but applets can use other classes, as well. These other classes can be either local to the browser, provided as part of the Java environment, or custom classes that you supply. When the applet tries to use a class for the first time, the browser tries to find the class on the host that's running the browser. If the browser can't find the class there, it looks for the class in the same place that the applet's Applet subclass came from. When the browser finds the class, it loads its bytecodes (over the network, if necessary) and continues executing the applet.
Loading executable code over the network is a classic security risk. For Java applets, some of this risk is reduced because the Java language is designed to be safe, example, it doesn't allow pointers to random memory. In addition, Java-compatible browsers improve security by imposing restrictions. These restrictions include disallowing applets from loading code written in any non-Java language, and disallowing applets from reading or writing files on the browser's host.
Applet API
The applet API lets you take advantage of the close relationship that applets have with Web browsers. The API is provided by the java.applet package -- mainly by the Applet class and the AppletContext interface. Thanks to the applet API, applets can do the following:
- Be notified by the browser of milestones.
- Load data files specified relative to the URL of the applet or the page in which it is running.
- Display short status strings.
- Make the browser display a document.
- Find other applets running in the same page.
- Play sounds.
- Get parameters specified by the user in the <applet> tag.
This lesson discusses each of these topics in turn, except for the milestone methods (init, start, and so on), which are explained in Methods for Milestones.
Finding and Loading Data Files
Whenever an applet needs to load some data from a file that's specified with a relative URL (a URL that doesn't completely specify the file's location), the applet usually uses either the code base or the document base to form the complete URL. The code base, returned by the Applet getCodeBase method, is a URL that specifies the directory from which the applet's classes were loaded. The document base, returned by the Applet getDocumentBase method, specifies the directory of the HTML page that contains the applet.
Unless the <applet> tag specifies a code base, both the code base and document base refer to the same directory on the same server.
Data that the applet always needs, or needs to rely on as a backup, is usually specified relative to the code base. Data that the applet user specifies, often by using parameters, is usually specified relative to the document base.
For security reasons, browsers limit the URLs from which untrusted applets can read. For example, most browsers don't allow untrusted applets to use ".." to get to directories above the code base or document base. Also, since untrusted applets can't read files except those on the applet's originating host, the document base isn't generally useful if the document and the untrusted applet are on different servers.
The Applet class defines convenient forms of image-loading and sound-loading methods that let you specify images and sounds relative to a base URL. For example, assume an applet is set up with one of the directory structures shown in the following figure.
To create an Image object using the a.gif image file under imgDir, the applet can use the following code:
Image image = getImage(getCodeBase(), "imgDir/a.gif");
Displaying Short Status Strings
All applet viewers -- from the Applet Viewer to Java-compatible browsers -- allow applets to display a short status string. In current implementations, this string appears on the status line at the bottom of the applet viewer window. In browsers, all applets on the page, as well as the browser itself, generally share the same status line.You should never put crucial information in the status line. If many users might need the information, it should instead be displayed within the applet area. If only a few, sophisticated users might need the information, consider displaying the information on the standard output.
The status line is not usually very prominent, and it can be overwritten by other applets or by the browser. For these reasons, it's best used for incidental, transitory information. For example, an applet that loads several image files might display the name of the image file it's currently loading.
Applets display status lines with the showStatus method. Here's an example of its use:
showStatus("MyApplet: Loading image file " + file);Please don't put scrolling text in the status line. Browser users find such status line abuse highly annoying!
Displaying Documents in the Browser
Have you ever wanted an applet to display formatted HTML text? Here's the easy way to do it: Ask the browser to display the text for you.With the AppletContext showDocument methods, an applet can tell the browser which URL to show and in which browser window. (By the way, the JDK Applet Viewer ignores these methods, since it can't display documents.) Here are the two forms of showDocument:
The one-argument form of showDocument simply tells the browser to display the document at the specified URL, without specifying the window to display the document in.public void showDocument(java.net.URL url) public void showDocument(java.net.URL url, String targetWindow)In this discussion, frame refers not to an AWT Frame but to an HTML frame within a browser window.
The two-argument form of showDocument lets you specify which window or HTML frame to display the document in. The second argument can have the values listed below.
- "_blank"
- Display the document in a new, nameless window.
- "windowName"
- Display the document in a window named windowName. This window is created if necessary.
- "_self"
- Display the document in the window and frame that contain the applet.
- "_parent"
- Display the document in the applet's window but in the parent frame of the applet's frame. If the applet frame has no parent frame, this acts the same as "_self".
- "_top"
- Display the document in the applet's window but in the top-level frame. If the applet's frame is the top-level frame, this acts the same as "_self".
The following applet lets you try every option of both forms of showDocument. The applet brings up a window that lets you type in a URL and choose any of the showDocument options. When you press Return or click the Show document button, the applet calls showDocument.
Because some old browsers don't support 1.1, the above applet is a 1.0 version (here is the 1.0 code; here's the 1.1 code). To run the 1.1 version of the applet, go to example-1dot1/ShowDocument.html.
Following is the applet code that calls showDocument. (Here's the whole program.)
...//In an Applet subclass: urlWindow = new URLWindow(getAppletContext()); . . . class URLWindow extends Frame { . . . public URLWindow AppletContext(appletContext) { . . . this.appletContext = appletContext; . . . } . . . public boolean action Event(event, Object o) { . . . String urlString = /* user-entered string */; URL url = null; try { url = new URL(urlString); } catch MalformedURLException(e) { ...//Inform the user and return... } if (url != null) { if (/* user doesn't want to specify the window */) { appletContext.showDocument(url); } else { appletContext.showDocument(url, /* user-specified window */); } } . . .
Sending Messages to Other Applets
Applets can find other applets and send messages to them, with the following security restrictions:
- Many browsers require that the applets originate from the same server.
- Many browsers further require that the applets originate from the same directory on the server (the same code base).
- The Java API requires that the applets be running on the same page, in the same browser window.
Some browsers let applets invoke methods on other applets -- even applets on different pages in the same browser -- as long as all of the applets come from the same code base. This method of interapplet communication isn't supported by the Java API, so it's possible that it will not be supported by all browsers.
An applet can find another applet either by looking it up by name (using the AppletContext getApplet method) or by finding all the applets on the page (using the AppletContext getApplets method). Both methods, if successful, give the caller one or more Applet objects. Once the caller finds an Applet object, the caller can invoke methods on the object.
Finding an Applet by Name: The getApplet Method
The getApplet method looks through all of the applets on the current page to see if one of them has the specified name. If so, getApplet returns the applet's Applet object.
By default, an applet has no name. For an applet to have a name, one must be specified in the HTML code that adds the applet to a page. You can specify an applet's name in two ways:
- By specifying a NAME attribute within the applet's <applet> tag. For example:
<applet code.gBASE=example/ CODE=Sender.class width=450 height=200 NAME="buddy"> . . . </applet>- By specifying a NAME parameter with a <PARAM> tag. For example:
<applet code.gBASE=example/ CODE=Receiver.class width=450 height=35> <PARAM NAME="name" value="old pal"> . . . </applet>Browser Note: Although at least one Java-enabled browser conducts a case-sensitive search, the expected behavior is for the getApplet method to perform a case-insensitive search. For example, getApplet("old pal") and getApplet("OLD PAL") should both find an applet named "Old Pal".
Below are two applets that illustrate lookup by name. The first, the Sender, looks up the second, the Receiver. When the Sender finds the Receiver, the Sender sends a message to the Receiver by invoking one of the Receiver's methods (passing the Sender's name as an argument). The Receiver reacts to this method call by changing its leftmost text string to "Received message from sender-name!".
Because some old browsers don't support 1.1, the above applets are 1.0 versions. Here are links to the 1.0 code for the Sender and Receiver classes. To run the 1.1 versions of the applets, go to example-1dot1/iac.html.
Click the Send message button of the top applet (the Sender). Some status information will appear in the Sender's window, and the Receiver will confirm (with its own status string) that it received a message, After you've read the Receiver status string, press the Receiver's Clear button to reset the Receiver. In the Sender's text field labeled "Receiver name:," type in buddy and press Return. Since "buddy" is the Sender's own name, the Sender will find an applet named buddy but won't send it a message, since it isn't a Receiver instance.
Here's the whole Sender program The code it uses to look up and communicate with the Receiver is listed below. Code that you can use without change in your own applet is in bold font.
The Sender goes on to make sure that the Receiver was found and that it's an instance of the correct class (Receiver). If all goes well, the Sender sends a message to the Receiver. (Here's the Receiver program)Applet receiver = null; String receiverName = nameField.getText(); //Get name to search for. receiver = getAppletContext().getApplet(receiverName);if (receiver != null) { //Use the instanceof operator to make sure the applet //we found is a Receiver object. if (!(receiver instanceof Receiver)) { status.appendText("Found applet named " + receiverName + ", " + "but it's not a Receiver object.\n"); } else { status.appendText("Found applet named " + receiverName + ".\n" + " Sending message to it.\n"); //Cast the receiver to be a Receiver object //(instead of just an Applet object) so that the //compiler will let us call a Receiver method. ((Receiver)receiver).processRequestFrom(myName); } } . . .From an applet's point of view, its name is stored in a parameter named NAME. It can get the value of the parameter using the Applet getParameter method. For example, Sender gets its own name with the following code:
myName = getParameter("NAME");The example applets in this page perform one-way communication -- from the Sender to the Receiver. If you want your receiver to be able to send messages to the sender, then you just need to have the sender give a reference to itself (this) to the receiver. For example:
((Receiver)receiver).startCommunicating(this);
Finding All the Applets on a Page: The getApplets Method
The getApplets method returns a list (an Enumeration, to be precise) of all the applets on the page. For security reasons, many browsers and applet viewers implement getApplets so that it returns only those applets that originated from the same host as the applet calling getApplets. Here's an applet that simply lists all the applets it can find on this page:
Because some old browsers don't support 1.1, the above applet is a 1.0 version (here is the 1.0 code; here's the 1.1 code). To run the 1.1 version of the applet, go to example-1dot1/iac.html.
Below are the relevant parts of the method that calls getApplets. (Here's the whole program
public void printApplets() { //Enumeration will contain all applets on this page (including //this one) that we can send messages to. Enumeration e = getAppletContext().getApplets(); . . . while (e.hasMoreElements()) { Applet applet = (Applet)e.nextElement(); String info = ((Applet)applet).getAppletInfo(); if (info != null) { textArea.appendText("- " + info + "\n"); } else { textArea.appendText("- " + applet.getClass().getName() + "\n"); } } . . . }
Playing Sounds
In the Java Applet package (java.applet), the Applet class and AudioClip interface provide basic support for playing sounds. Currently, the Java API supports only one sound format: 8 bit, µlaw, 8000 Hz, one-channel, Sun ".au" files. You can create these on a Sun workstation using the audiotool application. You can convert files from other sound formats using an audio format conversion program.
Sound-Related Methods
Below are the sound-related Applet methods. The two-argument form of each method takes a base URL, which is usually returned by either getDocumentBase or getCodeBase, and the location of the sound file relative to the base URL. You should use the code base for sounds that are integral to the applet. The document base is used for sounds specified by the applet user, such as through applet parameters.
- getAudioClip(URL), getAudioClip(URL, String)
- Return an object that implements the AudioClip interface.
- play(URL), play(URL, String)
- Play the AudioClip corresponding to the specified URL.
The AudioClip interface defines the following methods:
- loop
- Starts playing the clip repeatedly.
- play
- Plays the clip once.
- stop
- Stops the clip. Works with both looping and one-time sounds.
An Example
Here is an applet called SoundExample that illustrates a few things about sound. Note that, for instructional purposes, the applet adds up to 10 seconds to the load time for each sound. If the sounds were larger or the user's connection slower than ours, these delays might be realistic.
Because some old browsers don't support 1.1, the above applet is a 1.0 version (here is the 1.0 code; here's the 1.1 code). To run the 1.1 version of the applet, go to example-1dot1/SoundExample.html.
The SoundExample applet provides an architecture for loading and playing multiple sounds in an applet. For this reason, it is more complex than necessary. Essentially, the sound loading and playing code boils down to this:
AudioClip onceClip, loopClip; onceClip = applet.getAudioClip(getCodeBase(), "bark.au"); loopClip = applet.getAudioClip(getCodeBase(), "train.au"); onceClip.play(); //Play it once. loopClip.loop(); //Start the sound loop. loopClip.stop(); //Stop the sound loop.Since there's nothing more annoying than an applet that continues to make noise after you've left its page, the SoundExample applet stops playing the continuously looping sound when the user leaves the page, and resumes playing it when the user comes back. It does this by implementing its stop and start methods as follows:
public void stop() { //If one-time sound were long, we'd stop it here, too. //looping is a boolean instance variable that's initially //false. It's set to true when the "Start sound loop" button //is clicked and to false when the "Stop sound loop" or "Reload //sounds" button is clicked. if (looping) { loopClip.stop(); //Stop the sound loop. } } public void start() { if (looping) { loopClip.loop(); //Restart the sound loop. } }The SoundExample applet features three classes:
- An Applet subclass, SoundExample, that controls the applet's execution.
- A Hashtable subclass, SoundList, that holds AudioClips. This is overkill for this applet, but if you were to write an applet that used lots of sound files, a class like this would be useful.
- A Thread subclass, SoundLoader, each instance of which loads an AudioClip in the background. During the applet's initialization, the applet preloads each sound by creating a SoundLoader for it.
Preloading the sounds in a background thread (with SoundLoader) improves the perceived performance by reducing the amount of time the user has to wait to be able to interact with the applet. It does this by reducing the amount of time spent in the init method. If you simply called getAudioClip in the applet's init method, it could take quite a while before getAudioClip returned, meaning that the applet couldn't perform the other statements in its init method, and that the applet's start wouldn't get called. (For this SoundExample applet, a delay in calling the start method doesn't matter.)
Another advantage of loading the sounds in a background thread is that it enables the applet to respond appropriately (and immediately) to user input that would normally cause a sound to play, even if that sound hasn't been loaded yet. If you simply use the Applet play methods, for example, then the first time the user does something to make the applet play a particular sound, the applet's drawing and event handling are frozen while the sound is loaded. Instead, this applet detects that the sound hasn't been loaded yet and responds appropriately.
Defining and Using Applet Parameters
Parameters are to applets what command-line arguments are to applications. They allow the user to customize the applet's operation. By defining parameters, you can increase your applet's flexibility, making your applet work in multiple situations without recoding and recompiling it.
Deciding Which Parameters to Support
When implementing parameters, you must answer four questions:
- What should the applet let the user configure?
- What should the parameters be named?
- What kind of value should each parameter take?
- What should the default value of each parameter be?
Writing the Code to Support Parameters
Applets get the user-defined values of parameters by calling the Applet getParameter method.
Giving Information about Parameters
By implementing the getParameterInfo method, applets provide information that browsers can use to help the user set parameter values.
Using the applet Tag
This section tells you most of what you need to know to use the <applet> tag. It starts by showing you the tag's simplest form. It then discusses some of the most common additions to that simple form: the <PARAM> tag, alternate HTML code and text, the code.gBASE attribute, and the ARCHIVE attribute. For a detailed description of the <applet> tag, refer to The <applet> Tag.You should already have seen the simplest form of the <applet> tag:
<applet code.g=AppletSubclass.class width=anInt height=anInt> </applet>This tag tells the browser to load the applet whose Applet subclass is named AppletSubclass, displaying it in an area of the specified width and height.
Specifying Parameters
Some applets let the user customize the applet's configuration with parameters, as described in Defining and Using Applet Parameters. For example, AppletButton (an applet used throughout this tutorial to provide a button that brings up a window) allows the user to set the button's text by specifying the value of a parameter named BUTTONTEXT.The user specifies the value of a parameter using a <PARAM> tag. The <PARAM> tags should appear just after the <applet> tag for the applet they affect:
<applet code.g=AppletSubclass.class width=anInt height=anInt> <PARAM NAME=parameter1Name VALUE=aValue> <PARAM NAME=parameter2Name VALUE=anotherValue> </applet>Here's an example of the <PARAM> tag in use.
<applet code.g="Animator.class" width=460 height=160> <PARAM NAME="imageSource" VALUE="images/Beans"> <PARAM NAME="backgroundColor" VALUE="0xc0c0c0"> <PARAM NAME="endImage" VALUE=10> <PARAM NAME="soundSource" VALUE="audio"> <PARAM NAME="soundtrack" VALUE="spacemusic.au"> <PARAM NAME="sounds" VALUE="1.au|2.au|3.au|4.au|5.au|6.au|7.au|8au|9.au|0.au"> <PARAM NAME="pause" VALUE=200> . . . </applet>
Specifying Alternate HTML Code and Text
Note the ellipsis points (". . .") in the previous HTML example. What did the example leave out? It omitted alternate HTML code -- HTML code interpreted only by browsers that don't understand the <applet> tag. Alternate HTML code is any text that appears between the <applet> and </applet> tags, after any <PARAM> tags. Java-enabled browsers ignore alternate HTML code.To specify alternate text to Java-enabled browsers and other browsers that understand the <applet> tag, use the ALT attribute. If the browser can't display an applet for some reason, it can display the applet's ALT text.
We use alternate HTML code throughout the online version of this tutorial to tell readers about the applets they're missing. Often, the alternate HTML code includes one or more pictures of the applet. Here's the complete HTML code for the Animator example shown previously:
An applet that doesn't understand the <applet> tag ignores everything in the previous HTML code except the line that starts with "Your". A browser that does understand the <applet> tag ignores everything on that line. If the applet-savvy browser can't run the applet, it might display the ALT text.<applet code.g="Animator.class" width=460 height=160 ALT="If you could run this applet, you'd see some animation"> <PARAM NAME="imageSource" VALUE="images/Beans"> <PARAM NAME="backgroundColor" VALUE="0xc0c0c0"> <PARAM NAME="endImage" VALUE=10> <PARAM NAME="soundSource" VALUE="audio"> <PARAM NAME="soundtrack" VALUE="spacemusic.au"> <PARAM NAME="sounds" VALUE="1.au|2.au|3.au|4.au|5.au|6.au|7.au|8au|9.au|0.au"> <PARAM NAME="pause" VALUE=200> Your browser is completely ignoring the <applet> tag! </applet>
Specifying the Applet Directory
By default, a browser looks for an applet's class and archive files in the same directory as the HTML file that has the <applet> tag. (If the applet's class is in a package, then the browser uses the package name to construct a directory path underneath the HTML file's directory.) Sometimes, however, it's useful to put the applet's files somewhere else. You can use the code.gBASE attribute to tell the browser in which directory the applet's files are located:If aURL is a relative URL, then it's interpreted relative to the HTML document's location. By making aURL an absolute URL, you can load an applet from just about anywhere -- even from another HTTP server.<applet code.g=AppletSubclass.class CODEBASE=aURL width=anInt height=anInt> </applet>This tutorial uses code.gBASE="someDirectory/" frequently, since we group the examples for each lesson in subdirectories. For example, here's the <applet> tag that includes the Simple applet in The Life Cycle of an Applet
The following figure shows the location of the class file, relative to the HTML file, when code.gBASE is set to "example/".<applet code.g=Simple.class CODEBASE="example/" width=500 height=20> </applet>The next figure shows where the applet class can be if you specify an absolute URL for the value of code.gBASE.
Combining an Applet's Files into a Single File
If your applet has more than one file, you should consider providing an archive file that bundles the applet's files into a single file. Whether archive files make sense for your applet depends on several factors, including your applet's size, performance considerations, and the environment you expect your users to have.Archive files reduce your applet's total download time. Much of the time saved comes from reducing the number of HTTP connections that the browser must make. Each HTTP connection can take several seconds to start. This means that for a multifile applet, connection time can dwarf transfer time. You can further reduce transfer time by compressing the files in your archive file.
If you specify one or more archive files, then the browser looks for the archive files in the same directory that it would search for the applet class file. The browser then looks for the applet's class files in the archive files. If a file isn't in the archive, then the browser generally tries to load it just as it would if the archive file weren't present.
The standard Java archive format, called JAR, was introduced in JDK 1.1 and is based on the ZIP file format. You specify JAR files using the ARCHIVE attribute of the <applet> tag. You can specify multiple archive files by separating them with commas:
Unfortunately, not all browsers understand the same archive format or use the same HTML code to specify the applet archive. Watch this page for the latest information about browser support for archives. To learn how to create a JAR file, see Platform-specific Details: Creating a JAR File.<applet code.g="AppletSubclass.class" ARCHIVE="file1, file2" width=anInt height=anInt> </applet>
Other <applet> Tag Attributes
This section didn't discuss every attribute of the <applet> tag. Other attributes -- which might seem familiar, since the <IMG> HTML tag uses them -- include ALIGN, vspace, and hspace. The <applet> tag also allows you to load a serialized (saved) applet by specifying the OBJECT attribute instead of specifying a class file with code.g. Finally, you can name an applet using the NAME attribute. For a detailed description of the <applet> tag, see The <applet> Tag.
Security Restrictions
This section talks about design-level security. For more general information on applet security, go to the FAQ
Each applet viewer has a SecurityManager object that creates and throws a SecurityException object if a violation is detected.
Generally, the SecurityException constructor prints a warning message to the standard output. An applet can catch SecurityExceptions and react appropriately, such as by reassuring the user and by resorting to a "safer" (but less ideal) way of accomplishing the task.
Some applet viewers swallow some SecurityExceptions, so that the applet never gets the SecurityException. For example, the JDK Applet Viewer's implementation of the AppletContext getApplet and getApplets methods simply catches and ignores any SecurityExceptions. The user can see an error message in the standard output, but at least the applet gets a valid result from the methods. This makes some sense, since getApplets should be able to return any valid applets it finds, even if it encounters invalid ones. (The Applet Viewer considers an applet valid if it's loaded from the same host as the applet that's calling getApplets.)
To learn about security managers and the kinds of security violations they can check for, see Introducing the Security Manager
As the applet overview lesson mentioned, existing applet viewers (including Web browsers) impose the following restrictions:
- Applets cannot load libraries or define native methods.
Applets can use only their own Java code and the Java API the applet viewer provides. At a minimum, each applet viewer must provide access to the API defined in the java.* packages.
- An applet cannot ordinarily read or write files on the host that is executing it.
The JDK Applet Viewer actually permits some user-specified exceptions to this rule, but Netscape Navigator 2.0, for example, does not. Applets in any applet viewer can read files specified with full URLs, instead of by a filename. A workaround for not being to write files is to have the applet forward data to an application on the host the applet came from. This application can write the data files on its own host. See Working with a Server-Side Application for more examples.
- An applet cannot make network connections except to the host that it came from.
The workaround for this restriction is to have the applet work with an application on the host it came from. The application can make its own connections anywhere on the network. See Using a Server to Work Around Security Restrictions for an example.
- An applet cannot start any program on the host that is executing it.
Again, an applet can work with a server-side application instead.
- An applet cannot read certain system properties.
See Reading System Properties for more information.
- Windows that an applet brings up look different than windows that an application brings up.
Applet windows have some warning text and either a colored bar or an image. This helps the user distinguish applet windows from those of trusted applications.
The following figures show a window brought up by a program that can run either as an applet or as an application. The first figure shows what the window looks like when the program is run as an application on the Solaris platform. The second figure shows the window when the program runs as an applet within the Solaris Netscape Navigator 2.0 browser.
![]()
![]()
As you can see, the applet window has a warning.
Creating a User Interface
Most applets have a graphical user interface (GUI). This is a natural consequence of the fact that each applet appears within a browser window. Because the Applet class is a subclass of the AWT Panel class and thus participates in the AWT event and drawing model, creating an applet's GUI is just as easy as creating an application's GUI -- easier, actually, since the applet's window (the browser window) already exists.In addition to its graphical UI, an applet can use several other UI types, depending on the kind of information it needs to give or get. Some applets play sounds, either to give the user feedback or to provide ambiance. Applets can get configuration information from the user through parameters that the applet defines. To give text information to the user, an applet can use its GUI, display a short status string (for text that's not crucial), or display to the standard output or standard error stream (for debugging purposes).
For information about sound, parameters, and status strings, see Taking Advantage of the Applet API The rest of this section discusses the following topics, as they pertain to applets:
Getting System Properties
To find out about the current working environment, applets can read system properties. System properties are key/value pairs that contain information such as the operating system that the applet is running under. System properties are covered in detail in the System Properties page.Applets can read some, but not all, system properties. This page lists the system properties that Netscape Navigator 2.0 and the Applet Viewer allow applets to read, followed by a list of properties that applets can't read.
System Properties that Applets Can Read
Applets can read the following system properties:
Key Meaning file.separator File separator (for example, "/") java.class.version Java class version number java.vendor Java vendor-specific string java.vendor.url Java vendor URL java.version Java version number line.separator Line separator os.arch Operating system architecture os.name Operating system name path.separator Path separator (for example, ":") To read a system property from within an applet, the applet uses the System class method getProperty. For example:
The following applet reads all of the properties that are available to all applets:String newline = System.getProperty("line.separator");You can find the source code (which is the same in both 1.0 and 1.1) in GetOpenProperties.java
Forbidden System Properties
For security reasons, no existing browsers or applet viewers let applets read the following system properties.
Key Meaning java.class.path Java classpath java.home Java installation directory user.dir User's current working directory user.home User home directory user.name User account name
Threads in Applets
Every applet can run in multiple threads. Applet drawing methods (paint and update) are always called from the AWT drawing and event handling thread. The threads that the major milestone methods -- init, start, stop, and destroy -- are called from depends on the application that's running the applet. But no application ever calls them from the AWT drawing and event handling thread.
Many browsers allocate a thread for each applet on a page, using that thread for all calls to the applet's major milestone methods. Some browsers allocate a thread group for each applet, so that it's easy to kill all the threads that belong to a particular applet. In any case, you're guaranteed that every thread that any of an applet's major milestone methods creates belongs to the same thread group.
Below are two PrintThread applets. PrintThread is a modified version of SimpleApplet that prints the thread and thread group that its init, start, stop, destroy, and update methods are called from. (Actually, due to a Netscape Navigator 2.0 for Windows 95/NT bug, the following applets don't implement update. If you aren't using a PC that's running Netscape Navigator 2.0, you should be able to run the real example.) Here's the code for the hobbled example, and for the more interesting example. As usual, to see the output for the methods such as destroy that are called during unloading, you need to look at the standard output. See Displaying Diagnostics to the Standard Output and Error Streams for information about the standard output stream.
Because some old browsers don't support 1.1, the above applet is a 1.0 version (here is the 1.0 code; here's the 1.1 code). To run the 1.1 version of the applet, go to example-1dot1/PrintThread.html. So why would an applet need to create and use its own threads? Imagine an applet that performs some time-consuming initialization -- loading images, for example -- in its init method. The thread that invokes init can not do anything else until init returns. In some browsers, this might mean that the browser can't display the applet or anything after it until the applet has finished initializing itself. So if the applet is at the top of the page, for example, then nothing would appear on the page until the applet has finished initializing itself.
Even in browsers that create a separate thread for each applet, it makes sense to put any time-consuming tasks into an applet-created thread, so that the applet can perform other tasks while it waits for the time-consuming ones to be completed.
If an applet performs a time-consuming task, it should create and use its own thread to perform that task.
Applets typically perform two kinds of time-consuming tasks: tasks that they perform once, and tasks that they perform repeatedly. The next page gives an example of both.
Working with a Server-Side Application
Applets, like other Java programs, can use the API defined in the java.net package to communicate across the network. The only difference is that, for security reasons, the only host an applet can communicate with is the host it was delivered from.Depending on the networking environment an applet is loaded into, and depending on the browser that runs the applet, an applet might not be able to communicate with its originating host. For example, browsers running on hosts inside firewalls often cannot get much information about the world outside the firewall. As a result, some browsers might not allow applet communication to hosts outside the firewall.
It's easy to find out which host an applet came from. Just use the Applet getCodeBase method and the java.net.URL getHost method, like this:
String host = getCodeBase().getHost();Not all browsers support all networking code flawlessly. For example, one widely used Java-compatible browser doesn't support posting to a URL.
Before You Ship
Before you let the whole world know about your applet, make sure the answer to all of the following questions is yes.
- Have you removed or disabled debugging output?
Debugging output (generally created with System.out.println), while useful to you, is generally confusing or annoying to users. If you need to give textual feedback to the user, try to do it inside the applet's display area or in the status area at the bottom of the window. Information on using the status area is in Displaying Short Status Strings.
- Does the applet stop running when it's offscreen?
Most applets should not use CPU resources when the browser is iconified or is displaying a page that doesn't contain the applet. If your applet code doesn't launch any threads explicitly, then you're OK.
If your applet code launches any threads, then unless you have a really good excuse not to, you should implement the stop method so that it stops and destroys (by setting to null) the threads you launched.
- If the applet does something that might get annoying -- play sounds or animation, for example -- does it give the user a way of stopping the annoying behavior?
Be kind to your users. Give them a way to stop the applet in its tracks, without leaving the page. In an applet that otherwise doesn't respond to mouse clicks, you can do this by implementing the mouseDown method so that a mouse click suspends or resumes the annoying thread. For example:
boolean frozen = false; //an instance variable public boolean mouseDown Event(e, int x, int y) { if (frozen) { frozen = false; start(); } else { frozen = true; stop(); } return true; }
The Perfectly Finished Applet
- Make your applet as flexible as possible.
- You can often define parameters that let your applet be used in a variety of situations without any rewriting.
- Implement the getParameterInfo method.
- Implementing this method now might make your applet easier to customize in the future. Currently, no browsers use this method. Soon, however, we expect browsers to use this method to help generate a GUI that allows the user to interactively set parameter values.
- Implement the getAppletInfo method.
- This method returns a short, informative string describing an applet. Although no browsers currently use this method, we expect them to in the future. Here's an example of implementing getAppletInfo:
public String getAppletInfo() { return "GetApplets by Kathy Walrath"; }
Common Applet Problems
Problem: Applet Viewer says there's no <APPLET> tag on my HTML page, but it really is there.
Problem: I recompiled my applet, but my applet viewing application won't show the new version, even though I told it to reload it.
- Check whether you have a closing applet tag: </APPLET>.
Problem: The light gray background of my applet causes the applet to flicker when it's drawn on a page of a different color.
- In many applet viewers (including browsers), reloading isn't reliable. This is why we recommend that you simply use the JDK Applet Viewer, invoking it anew every time you change the applet.
- If you get an old version of the applet, no matter what you do, make sure that you don't have an old copy of the applet in a directory in your CLASSPATH. See Managing Source and Class Files for information about the CLASSPATH environment variable.
Problem: The Applet getImage method doesn't work.
- You need to set the background color of the applet so that it works well with the page color.
Problem: Now that I've copied my applet's class file onto my HTTP server, the applet doesn't work.
- Make sure you're calling getImage from the init method or a method that's called after init. The getImage method does not work when it's called from a constructor.
Problem: I can't get my applet to run. The browser displays a ClassCastException.
- Does you applet define more than one class? If so, make sure that the class file (ClassName.class) for each class is on the HTTP server. Even if all the classes are defined in one source file, the compiler produces one class file per class.
- Did you copy all the data files for your applet -- image and sound files, for example -- to the server?
- Make sure all the applet's class and data files can be read by everyone.
- Make sure the applet's class and data files weren't garbled during the transfer. One common source of trouble is using the ASCII mode of FTP (rather than the BINARY mode) to transfer files.
- If your applet has multiple classes, did you specify the right one (an Applet subclass) in the applet tag's CODE attribute?
![]()