Chapter 15
Advanced Applet Code

by Joe Weber

Now that you have learned how to write a Java Applet, it's time to dig in a bit deeper. Applets inherit a number of abilities which come from the applet class. In this chapter you learn how to make the most out of all these features.

Using the <PARAM> Tag

The most utilized java.applet. Applet feature is the ability to get information from the HTML file. This information can be very useful because it enables you to use the HTML file almost as a batch file, containing the runtime parameters for a particular applet. This also enables you to write an applet once, which can be customized by people unfamiliar with Java coding. This information is placed in what are known as <PARAM> tags.

In Chapter 14, "The <PARAM> Tag" section, you learned that <PARAM> tags are part of the <APPLET> tag included in HTML files. In addition, you learned that the syntax for a <PARAM> tag is:

<PARAM NAME="parameter_name" VALUE=value_of_parameter>

where the items in italics are replaced by specific information for your case. In this chapter you learn how to use this information within an applet.

See "Writing an Applet," Chapter 14

To access the parameter data, java.applet.Applet has a method called getParameter(). The method prototype for this method looks like this:

public String getParameter(String name)

As you can see from the prototype, getParameter() requires a parameter--a name. That name corresponds directly to the NAME value in the <PARAM> tag, so if you had a tag that looked like:

<PARAM NAME="Stars" VALUE=50>

You could retrieve the result with a line of code similar to this:

String starCount = getParameter("Stars");


NOTE: Normally, you will actually develop the program, and then the HTML file, so this example will probably be backward for most of your development.


If what you had wanted to get from the parameter was a string value, the previous code might be enough to satisfy your needs. However, odds are that what you really wanted was an integer with a value of 50. Since getParameter() returns a string, how can you obtain the int value 50? The answer lies in the Wrapper class for int called java.lang.Integer. Integer can take a string which represents a number and "parse" through it to get the number value. Using Integer, you can retrieve the value into an int by using Integer's parseInt() method, as shown here:

int starCountInt = Integer.parseInt(starCount);

Putting this whole thing together in a complete applet which paints the stars in random places on the screen is shown in Listing 15.1.

Listing 15.1StarPainter Reads in a Value for the Number of Stars and Paints Them to the Screen

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

/*
 *
 * StarPainter
 *
 */
public class StarPainter extends Applet{
     int starCount;
     public void init(){
          starCount = Integer.parseInt(getParameter("Stars"));
     }

     public void paint(Graphics g){
          g.setColor(Color.black);
          for (int count=0;count<starCount;count++){
               int xValue = (int)(getSize().width*Math.random());
                int yValue = (int)(getSize().height*Math.random());               
               g.drawLine(xValue,yValue,xValue,yValue);
          }
     }
}

When you compile StarPainter you need to also create an HTML file for it. In Listing 15.2, you see one possible version of this HTML file. Figure 15.1 shows you what StarPainter looks like with those parameter values. Try changing the number of stars to see what happens (you might want to increase it by a large number, since it's difficult to see small changes in this applet).

FIG. 15.1
StarPainter paints stars at random places on the screen.

Listing 15.2An HTML File for the StarPainter Applet

<hr>
<applet code="StarPainter.class" width=100 height=100>
<param name=Stars value=500>
</applet>
<hr>

Understanding the StarPainter Source Code

Since you're still fairly new to applet programming, take a look at Listing 15.1 and walk through how the StarPainter applet works.

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

The first thing to notice is, like all Java classes, the StarPainter program needs to import several classes. This is really an important step. When you're just starting to program in Java, you may get frustrated by an error that looks like:

StarPainter.java:14 Class Graphics not found in type declaration.
     public void paint(Graphics g){
                 ^

This error is caused because you failed to import the Graphics class.

public void init(){
     starCount = Integer.parseInt(getParameter("Stars"));
}

The init() method of StarPainter should look just like you thought it would, except for one minor change. You have combined the two lines of code you saw earlier into one. Notice that this demonstrates the fact that it is perfectly legitimate to use a method (getParameter()) as a parameter to a second method (parseInt()) when the proper value is being returned.

     public void paint(Graphics g){
          g.setColor(Color.black);
          for (int count=0;count<starCount;count++){
               int xValue = (int)(getSize().width*Math.random());
                int yValue = (int)(getSize().height*Math.random());               
               g.drawLine(xValue,yValue,xValue,yValue);
          }
     }
}

The paint() method of StarPainter is not too involved, but does contain some methods you haven't seen until now. The first thing that the paint() method does is set the paint color to black. This is a very standard practice, and you explore the entire graphics library in greater depth in Chapter 27.

See "java.awt--Graphics," Chapter 27

Using the getSize() Method

Now concentrate on the xValue= and the yValue= lines.

int xValue = (int)(getSize().width*Math.random());

To help you understand this line, break it up into several lines of equivalent code:

int width = getSize().width;
double randomLoc = Math.random();
double location = width * randomLoc;
int xValue = (int) location;

Go through the code on your own and verify that it does get you the same result as the xValue= line in StarPainter.

The first line of code uses a method you haven't seen before-- getSize(). getSize() is a method which an applet inherits from the java.awt. Component class. getSize() can be a very useful method for applets because it allows you to find out how much room you have to work with. To understand how the applet obtained the getSize() method, take a look at the API for applet at:

http://www.javasoft.com/products/jdk/1.1/docs/api/packages.html

When you visit the Web site, you see a structure at the top of the applet, called an inheritance tree, which looks like this:

Class java.applet.Applet 

java.lang.Object
   |
   +----java.awt.Component
           |
           +----java.awt.Container
                   |
                   +----java.awt.Panel
                           |
                           +----java.applet.Applet

An inheritance tree helps you to see all of the classes Applet inherits from. You see that, just like when you create your applets by extending the java.applet.Applet class (and in so doing you obtain all the methods of applet), when Applet extends Panel it obtains all of Panel's methods. So, even though you aren't extending Component, since Container does, and since Panel extends Container, and Applet extends Panel, and PaintStars extends Applet, you have effectively inherited all of those classes and can use the methods present in all of them.

If you look at the top of the tree you will see Component. Component is a very rich class with a lot of methods, and so you will want to get to know Component very well. However, the point of all of this is that Component has a method called getSize(), which is the very method you were looking for.

Going back to your equivalent code, the next line after the width = getSize().width; is a line that says:

double randomLoc = Math.random();

Math is a class in the java.lang package (i.e., java.lang.Math). Math has a number of valuable methods, one of which is Random. Random returns a random number from 0.0-1.0. This can be very useful because, as you used it here, you can use that number to generate any random number you need. The rest of the code should be easy to follow once you understand random() and getSize().


NOTE: A quick note about random(): Notice that when you call random() you are doing this on the class Math, and not on an actual instance of Math. In other words, what you are NOT doing is:

Math myMathVar = new Math();
double randomLoc = myMathVar.random();

How can you do this? Ordinarily you cannot call methods just using their class name. However, if a method is defined to be static, the method can be invoked without having to create an instance object of the class first. It just so happens that all of Math's methods are static, so you can use them without having to actually invoke Math. If you're following along using JavaSoft's API, you may have noticed that random() is preceded by a green dot instead of a red one. This is to indicate that random() is a static method.


See Chapter 8, "Methods," for more information.

Adding Images to an Applet

Another common task when building an applet is displaying an image. As you saw in the StarPainter Applet, you can create images on your own using the Graphics class, but you can also load images stored in .gif or .jpg formats. getImage() is the method which has been added to java.applet.Applet for the purpose of loading such images.

public Image getImage(URL url)

getImage is a very easy method to use. To use getImage() all you need to know is the URL where the image can be found. So, to get the image called banner.gif from the Web site www.magnastar.com, all you would need to do is use a line similar to this:

Image testImage = getImage (new URL("http://www.magnastar.com/banner.gif");

To put this in an applet, look at Listing 15.3:

Listing 15.3PaintBanner Loads an Image and Displays It

import java.applet.Applet;
import java.awt.*;
import java.net.URL;

/*
 *
 * PaintBanner
 *
 */
public class PaintBanner extends Applet{
     Image testImage;
     public void init(){
          testImage = getImage("http://www.magnastar.com/banner.gif");
     }

     public void paint(Graphics g){
          g.drawImage(testImage,0,0,this);
     }
}

PaintBanner is a very effective applet if what you want to do is paint one image: banner.gif. However, it's unlikely that you will have too many requirements for banner.gif. Because of the URL restrictions imposed on applets, you would not even be able to load the banner.gif image from www.magnastar.com unless the applet actually resides on the www.magnastar.com computer.

You can get away from this requirement by using the getParameter() method you learned about in the previous section, embedding a parameter that would be used for the URL. For limited cases this might actually work. However, what if you want to load the banner.gif graphic, and you want to always load it off the current computer? In other words, what if you create an applet that relies on a number of graphics, but when somebody from www.jars. com loads the applet they need to get the image from www.jars.com, not from www. magnastar.com.

java.applet.Applet just so happens to have a number of methods that can help you in this pursuit. It has the ability to tell you the relative URL of either the location where the class files for the applet were retrieved, or where the HTML file the applet was contained in are from. These two methods are getDocumentBase() and getCodeBase().

public URL getDocumentBase()
public URL getCodeBase()

The getDocumentBase() will return the relative URL where the applet is contained. getCodeBase() returns the relative URL where the applet's class files are located. Now, the key here is the term relative. You see the two methods return only the relative location for the file. For instance, the relative URL for the banner.gif file talked about before would be http://www.magnastar.com/. Had it been located in a subdirectory called Images, the URL would be http://www.magnastar.com/Images/. To get to the whole URL you need to create an URL from both this URL and the name of the actual file you're looking for. How do you do this? The answer is twofold; first you could use the two-parameter constructor for an URL, which would look like new URL(getDocumentBase(),"banner.gif"). It just so happens that getImage() itself has been overloaded to provide this same functionality as well. Listing 15.4 shows Listing 15.3 again using the getDocumentBase() method.

Listing 15.4Loading an Image from the Current Directory

import java.applet.Applet;
import java.awt.*;
import java.net.URL;

/*
 *
 * PaintBanner
 *
 */
public class PaintBanner extends Applet{
     Image testImage;
     public void init(){
          testImage = getImage(getDocumentBase(),"banner.gif");
     }

     public void paint(Graphics g){
          g.drawImage(testImage,0,0,this);
     }
}

Figure 15.2 shows the result of adding the getDocumentBase() method.

FIG. 15.2
getDocumentBase() method will return the relative URL where the Applet is contained.

Now when you run paintBanner, the browser will look for the graphic banner.gif in the same directory where it found the HTML file. When you move paintBanner to another system or directory, there is no need to change either the HTML or the source code.


One interesting characteristic of getImage() is that it returns immediately. In other words, your program starts to process the next file right away. getImage() does not wait until after the image has been dragged across the Net; in fact, the image isn't actually even retrieved until it is first used. Be aware of this fact, because you'll likely see images paint slowly at times. You learn more about this in Chapter 27, "java.awt--Graphics."


Adding Sound to an Applet

Another useful feature of applets is their ability to load and use sounds. At the present time this ability is actually quite limited--you can only load sounds in the .au format. However, in coming months you should see a new set of class files which will allow you to utilize a much greater variety of sounds.

Audio is abstracted in Java in a class called java.applet.AudioClip. At present Applet provides you with one method to load the .au files, and this method is getAudioClip().

public AudioClip getAudioClip(URL url)
public AudioClip getAudioClip(URL url, String name)

getAudioClip() works very similarly to getImage(). In fact, just as with getImage(), getAudioClip() has two possibilities, one with just the URL, and one with a relative URL and a name. To actually use the AudioClip, you will need to use one of AudioClip's methods: play(), loop(), or stop(). Each of these methods works exactly as you'd think it would. play() plays the clip once, while loop() plays it over and over (and over and over) again. Please use some courtesy when using loop(). There is nothing worse than hearing the same clip over and over again, so don't arbitrarily loop an audioclip endlessly. Put these together in a small applet, shown in Listing 15.5.

Listing 15.5Play Audio Clip--When You Click This Applet It Plays a Sound

import java.applet.Applet;
import java.applet.AudioClip;
import java.awt.Event;

/*
 *
 * PlayAudio
 *
 */
public class PlayAudio extends java.applet.Applet{
     AudioClip audio;

     public void init(){
          audio = getAudioClip(getDocumentBase(),"welcome.au");
     }
     
     public booleanmouseDown(Event evt, int x, int y){
          audio.play();
          returns true;
     }
}

One major difference between getAudioClip() and getImage() is the fact that getAudioClip() will go out to the Net and return the actual AudioClip. This is not what getImage() does and, when you get an AudioClip, the rest of your program will have to wait until that audio file has been downloaded. There is also another method in applet called play(). play() is overridden the same way that getAudioClip() and getImage() are. The difference between play() and getAudioClip() is that play() grabs the audio clip and plays it right away. However, it doesn't save the AudioClip so, if you need it again, it will have to be re-downloaded from the Net.

Using the Applet to Control the Browser

Another thing you can use an applet to do is to provide control over the browser. This is very important because it allows the applets that you write to extend the capabilities of a standard browser, actually changing the experience of a user to fit your new needs.

One difference with the methods used to control the browser, as opposed to the rest of the methods discussed in this chapter, is that java.applet.Applet doesn't have the ability to change the Web page itself. Instead, a class called AppletContext, which is basically a link to the browser itself, actually controls the browser environment in which the applet lives.

To retrieve the AppletContext for the browser you need to use the method:

public AppletContext getAppletContext()

Once you have the AppletContext for the applet you can begin to manipulate the browser.

Changing the Status Message

An applet can cause the browser to change Web pages or display a different message. The first method for doing this is showStatus(). ShowStatus() causes the message to be displayed in the status window, normally at the bottom of the page, as seen in Figure 15.3.

FIG. 15.3
When you click the applet, the status line changes.

public void showStatus(String msg)

Using showStatus(), you can change the value of this output to be any string you want. Listing 15.6 shows an example program that changes the status to indicate the number of times you've clicked the applet.

Listing 15.6The Status Window of This Browser Is Changed by the Applet

import java.applet.Applet;
import java.awt.Event;

/*
 *
 * ShowClickCount
 *
 */
public class ShowClickCount extends Applet
{

     int count=0;

     public boolean mouseDown(Event evt, int x, int y){
          getAppletContext().showStatus("You've clicked "+(count++)+" times");
          return true;
     }
}

When you run the ShowClickCount applet you will notice the status message changes each time you click the applet. Changing the status message at the bottom of the page can be an extremely useful way to give feedback to your users. Notice how the browser uses the status area to tell you about where a link goes, or the status of a download.

Changing the Page the Browser Displays

Another thing you can do with the browser is change the Web page it is displaying. This can be extremely useful because it means you can now add navigation capabilities to your applet. AppletContext's method for doing this comes in two varieties:

showDocument(URL) 
showDocument(URL, String) 

If you're jumping ahead, you're thinking to yourself, "Ahh huh, showDocument() has the same relative URL and final document options that getImage() and getAudioClip() did." If that's what you're thinking--well, there's no easy way to break this to you--you're wrong. The two versions of showDocument DO NOT work the same way as getImage() and getAudioClip(), so read on.

First, showDocument(URL) does change the browser window to the URL you've pointed it to, just as you might have guessed. So, if you wanted to create a very simple applet that just changed to the Web page, you could put something together like Listing 15.7.

Listing 15.7Show Document Displays a Different Web Page in the Browser

import java.applet.Applet;
import java.awt.Event;
import java.net.*;

/*
 *
 * ShowDocument
 *
 */
public class ShowDocument extends Applet {
     public boolean mouseDown(Event evt, int x, int y){
          try{
          getAppletContext().showDocument(new URL("http://www.magnastar.com"));
          } catch (MalformedURLException urlException){
               System.out.println("Sorry but there was an error creating the URL:"+urlException);
          }
          return true;
     }
}

When you run the ShowDocument applet and then click it, your browser changes to the www.magnastar.com Web page. Notice the try-catch sequence in the example above. Do you realize why you need it? It's required because the constructor for URL throws an exception if the URL isn't valid. For instance, if you point to htpt://www.magnastar.com this would not be a valid URL since URL doesn't know what to do with htpt.

So what, then, is the difference between the two showDocument() methods? Well, the first method takes just the URL you want to show, as just covered. The second takes the URL you want to point to and the name of the target frame to display the document in. You can use the actual name of the frame you want to display in (if you are using frames on the Web page) or the values "_self", "_parent", and "_blank" to refer to either the current frame (default), the parent frame, or a new window, respectively.

Putting It All Together

Now, try to construct a more complete example using each of the methods you learned about in this chapter. For this complete example, first display a graphic. Then, each time the mouse enters the applet, play a sound. When the mouse button is pressed, display a message, and when the button is released, change pages. Listing 15.8 shows you just how to create this application; see if you can work through the source code on your own.

Listing 15.8ActiveBanner Displays an Image and Plays a Sound When the Mouse Enters the Area. It Switches Web Pages When Its Clicked

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

/*
 *
 * ActiveBanner
 *
 */
public class ActiveBanner extends Applet{
     Image banner;
     AudioClip welcome;

     public void init(){
          banner = getImage(getDocumentBase(),"banner.gif");
          welcome = getAudioClip(getDocumentBase(),"welcome.au");
     }

     public void paint(Graphics g){
          g.drawImage(banner,0,0,this);
     }

     public void update (Graphics g){
          paint(g);
     }

     public boolean mouseEnter(Event e, int x, int y){
          welcome.play();
          return true;
     }

     public boolean mouseDown(Event e, int x, int y){
          getAppletContext().showStatus("Release the mouse button to go to 			        MagnaStar");
          return true;
     }

     public boolean mouseUp(Event e, int x, int y){
          try{
               getAppletContext().showDocument(new URL("http://	                                  www.magnastar.com"));
          } catch (MalformedURLException urlException){
               System.out.println("Sorry but there was an error creating the 	                                  URL:"+urlException);
          }
          return true;
     }
}