Chapter 14

Creating a Java Applet


CONTENTS


Java is a powerful language that is just now coming into its own. If you've browsed the Web lately, you have probably seen applets in action. Stop by Sun Microsystems's home page, the Gamelan Web site, or thousands of other sites, and you will see applets come to life right before your eyes. Although applets using Java-based animation are great for their novelty and their capability to call attention to something, they do not fully demonstrate Java's power as a programming tool.

Beyond these beginning applets is the intermediate level of programming, which has multiple connotations. Some believe it begins when a programmer can write a program from scratch, while others contend that it begins with the ability to understand code and modify it to fit the circumstance.

For our purposes, the intermediate level begins when the programmer can allow interaction with the reader. This interaction is the key to distributed languages and the reason Java is getting so much attention. Formerly, the only way to allow for any degree of interaction across the Internet involved using CGI scripts written in languages native to the computer that stored them. Java is helping to change this while offering more power to a wider audience.

To create a CGI script, you must be able to write code in a language that the host computer can run. You also have to get permission to place the program on the host computer. Many Internet service providers (ISPs) have stopped giving this permission due to the computer resources these scripts require and security concerns. Java circumnavigates this issue by running its applets on the client computer instead of on the host, which reduces demands on the ISP's resources.

In this chapter you will construct two intermediate applets. These applets display features that can be found in larger applets without being overly lengthy or complex. The first applet, called QuizMaker, provides for a three-minute timer. Each step in building and testing the applet is described in detail. The second applet converts a color entered as three integers into a single number displayed in hexadecimal. The applet called RGB2Hex lets you preview the associated color. The end of this chapter gives some tips for debugging and provides a comparison of the two applets.

Conceptualization and Design of the QuizMaker Applet

The first step in designing an applet in Java or any other language is to have a good overall understanding of the tasks the applet will perform and for what purpose the applet will be used. Your goal is to create a detailed description of every object you will need to build the applet. This detailed description should specify the task or tasks the applet must perform without detailing how those tasks are to be accomplished.

When you complete the specification, it is easier to visualize how the applet will be presented to the user, what the applet will be used for, and what the user will be required to do to have the applet perform key tasks. Your specification may include a specific screen layout. Making a pencil drawing can help in determining all the pieces of information that need to be presented and deciding on an attractive layout.

After sketching the layout of the applet, describe each object in the applet in terms of its function. Many of these objects appear on the screen and can be defined from the screen layout. Other objects perform background tasks and are used to support the objects that appear in front of the user. These objects can be defined in terms of the tasks they perform. Don't worry if you do not recognize all the objects required while designing the applet. One of the advantages of an object-oriented language is the simplicity with which new objects can be added to provide functionality that was not considered during initial design.

The first applet you will build is called QuizMaker. The initial specification for QuizMaker follows:

The QuizMaker applet implements a simple timer to notify the user when three minutes are up. The user will press a button to start the timer. After the user starts the timer, the applet will provide a text display and a sound bite to indicate that the user should start the quiz. A different text and another sound bite will indicate that the user should stop. A picture will be included to enhance the visual appeal of the applet. The applet is simple to create and yet gives you experience working with the existing Java classes.

You can use the QuizMaker applet for the following:

Having described the tasks the applet will perform, you should now describe the layout of the applet. The layout doesn't have to be extravagant-a simple one drawn by hand is usually just fine. To lay out the QuizMaker applet, draw the key objects the user would see on a piece of paper:

Figure 14.1 shows the initial layout for the applet. The picture of the hourglass is represented by the large rectangle on the right side of the figure. The start button is represented by the small rectangle in the lower left. Finally, the informational text is placed just above the start button.

Figure 14.1 : Layout of the QuizMaker applet.

The next step is to describe the applet in terms of objects. For this example you will implement the applet using classes as they exist in the Java API. This will keep the code short and easy to follow. You implement the picture by creating an Image class object. The audio is provided using the play() method and supplying an appropriate audio file. The Java API also includes Button and Label classes, which are used for the button and the display, respectively.

Tip
Finding the appropriate class for a given function can be a matter of searching the API, your memory, and larger projects' libraries of objects created by others. Which class is appropriate for which function becomes more apparent as you work with the API and existing classes.

Defining the Applet Structure

Defining a class for each object is only part of determining the structure of the applet. Defining the applet structure also includes determining what objects are present when the applet starts, when new objects can be created, and how objects will communicate with each other. The Object superclass can be used to create new classes; however, for many programs there is a subclass already defined in Java that provides some or all of the functionality required.

The easiest way to create an applet is to extend the Applet class, which, as defined in the Java API, includes all the methods necessary for a working applet. The QuizMaker applet extends the Applet class to add the features described in the design. When the applet is started, it creates the objects such as the button, label, and picture. Because these objects are already defined by the Java API, you will not have to reinvent the wheel and can completely code the applet in only a few steps.

You still must define the communication between the objects. All communication is between these objects and the QuizMaker object. The event handler in the Applet class will be modified in the QuizMaker class to start tracking time when the button is pressed. Two new methods will be added to the Applet class: One will start the timer, and the other will stop it. When the timer expires, the QuizMaker object will direct the label to change its text.

The design of the QuizMaker applet is kept simple to provide experience in working with the Applet class. Chapter 16, "Applet Reuse," covers the redesign of the applet to take advantage of multiple threads.

Building the Applet

This section describes each step for building the QuizMaker applet. The comments before and after each section of code describe what the code does and important aspects of the syntax.

Step 1: Create an HTML Document to Test the Applet

The HTML document used to test the applet does not need to be extensive. However, it should include all the required HTML structure tags and display your applet prominently. Listing 14.1 is an example of an HTML document for the QuizMaker applet.


Listing 14.1. A sample HTML document.
<HTML>
<HEAD>
<TITLE> Quiz Maker</TITLE>
</HEAD>
<BODY>
<CENTER>
<H2> The QuizMaker Applet </H2>
<H3> Written with JAVA <H3>
<HR>
<APPLET CODE="QuizMaker" WIDTH=400 HEIGHT=300>
</APPLET>
</CENTER>
</BODY>
</HTML>

With this document available for testing, you can begin to define the classes in the QuizMaker applet. (See Chapter 15, "Creating Java-Powered Web Presentations with Applets," for complete details on creating HTML documents that use the <APPLET> tag.)

Step 2: Create a File Containing Included Classes

Java source files must be named with the .java extension and in a source file named for its class. For this reason, you should name the source code file for the new class QuizMaker.java.

Note
The Java compiler expects the source code to be in a file named with the .java extension. When the source file contains multiple class declarations, the source file must be named after the primary class declaration. For applications, the primary class is the class that contains the main() method. For applets, the primary class is the class that contains the init() and run() methods.

Because the QuizMaker applet uses existing Java classes, you must let the Java runtime environment know it must include these classes. This is done with the import statement. In all, the QuizMaker applet makes use of four packages: java.applet, java.util, java.net, and java.awt. The code to include these four packages follows:

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

Technical Note
Although you could be more specific and include only the classes you will actually be referencing, most applets make extensive use of the packages they import. For this reason, most programmers make the entire class available for importing on demand to prevent an extensive listing of classes. It is important to remember that the asterisk indicates that all classes in the package are to be made available and can be imported on demand. If you don't use the asterisk, the runtime environment will return an error indicating that the class to import could not be found. It is likewise important to include the semicolon at the end of each statement, or the compiler will generate an error.

Step 3: Declaring the QuizMaker Class

Now that all the existing classes you need are available, you can begin to create new classes. The following line of code creates the new class QuizMaker as an extension of the Applet class. The Applet class is public; the QuizMaker class will be as well. This means that other classes can create an instance of the QuizMaker class. It also allows the runtime environment to create an instance of the class. The code is as follows:

public class QuizMaker extends Applet {

The brace at the end of the line is significant. All the extensions to the Applet class must fall between the brace at the end of this line and its corresponding closing brace. In this case, the closing brace will be at the end of the applet code. In fact, you could put a brace on the following line, compile this code, and test it in your HTML file. It will appear as an empty box in the HTML document.

Step 4: Adding Class Variables

After declaring a new class, add code to the class so that it has some functionality beyond displaying an empty box. The applet should specify instance variables for each object you are adding to the class. Although instance variables must be declared outside the methods of the class and are usually placed at the beginning of the class, they can be placed anywhere before the method where they are used. The instance variable declaration lines for QuizMaker look like the following:

Image HglassImage; // Displays a picture of an hour glass
Button  RunButton; // Lets the user start the timer
Label   StatusLabel; // Displays the status to the user
URL HglassURL;  // URL of the applet

The first line declares an Image object to hold the picture to be displayed to the user. The second line declares a Button object, which enables the user to start the timer. The third declaration provides a read-only text area to display messages to the user. The final declaration provides a location for storing the URL of the applet.

The code can now be recompiled to test the syntax of these declarations. If you run the code again, note that there is no apparent change to the display. In the next step you will create methods that will modify the display.

Step 5: Define the Methods

All methods for a class must be included in the file prior to the closing brace that ends the class. This section details each method and recommends an order for coding and testing the methods used in the QuizMaker class. Several of the existing Applet class methods are overridden in the QuizMaker class. Two new methods, runTimer and stopTimer, are also added.

Step 5a: Define the init() Method

When the runtime environment loads the applet, it will run the init() method before executing the applet. This method is used to set up the screen size and create objects that are needed throughout the life of the applet. The init() method must be coded so that the other methods have objects with which to work. After the init() method is created, you can recompile and see the resulting changes when you run the applet. The code for the init() method is shown in Listing 14.2.


Listing 14.2. The QuizMaker class init() method.
public void init() {
 HglassURL = getCodeBase();   // Gets the URL for the applet

   // Get the picture to add to the screen
HglassImage = getImage(HglassURL,"Hglass.gif");

 // Add a label to display text which can not be altered by the user
add(StatusLabel = new Label("Press Run to start timer"));

 // Add a button to start the timer
      add(RunButton = new Button("Run"));

  resize(400,300);   // Resizes the applet
 paint(getGraphics());   // Display applet with the objects on the screen

 play(HglassURL,"intro.au");  // Play an intro
 play(HglassURL,"startTimer.au");  // Play the start message
 play(HglassURL,"endTimer.au");  // Play the end message
    }

This init() method overrides the init() method that was originally defined for the Applet class and is public, so it can be called by other objects. Creating a public method is necessary so that the runtime environment can call it. void indicates that the method does not return a value.

The first action in this method is to get the base URL, or location on the file system, for the applet. The URL is stored because it is a required value for many of the methods used in init() and the other methods in this class. Using the URL, the getImage() method is invoked to create an Image object from the picture stored in the file Hglass.gif. The identifier for this Image object is HglassImage, which was declared as part of the class because the identifier will be needed when the class is drawn on the screen.

The next two lines of code use the add() method to add objects to the applet. This method is part of the API for the Applet class and makes it easy to add a new object to the applet. The first use of add() inserts a label object and sets the initial display to the string "Press Run to start timer". The second use of add() inserts the button with the title Run. These objects are added at initialization so that they are presented to the user when the applet first appears. The objects will remain in existence for the life of the applet.

Because QuizMaker is an extension of the Applet class, the resize method of the Applet class is used in the next line to set the size of the applet to 400¥300. This will have an effect only if the size is not set by the browser. The screen is then drawn using the paint() method. The paint() method will be overridden to draw the objects and images associated with the QuizMaker class, but it still must be passed the graphic on which to draw them. This is done by invoking the getGraphic() method. Notice that the methods can be combined.

The last three lines play an introductory audio clip and the two audio clips that will be used at the beginning and end of the timer. The play() method is available as part of the Applet class. It requires a URL and a filename. It looks for the file specified in the directory obtained from the URL. Playing all three audio clips is not really necessary, but the first time the audio clips are played there is a time delay that is inappropriate for use with the timer. Therefore, if you play them once in the introduction, they will sound appropriate when they are played later in the applet.

Step 5b: Define the paint Method

Like the init() method, the paint() method from the Applet class is overridden to provide different functionality for the QuizMaker class. The paint() method that you are creating is called in place of the one originally defined for the Applet class. Specifically, the paint() method is called when the program starts so that it can draw all the objects added during the initialization phase. In the QuizMaker class the paint method draws the HglassImage on the screen, as well as the button and the label. The code for this method is shown in Listing 14.3.


Listing 14.3. The QuizMaker class paint() method.
public void paint(Graphics g) {
 g.drawImage(HglassImage,250,10,this); // Draw the hour glass

 StatusLabel.resize(150,20);  // Resizes the label
 StatusLabel.move(10,10);  // Moves the label

 RunButton.resize(100,20);  // Resizes the button
 RunButton.move(20,40);   // Moves the button

    }

The methods used to draw the image and manipulate the button and label are all part of the Java API. Using the drawImage() method makes it easy to place the GIF image exactly where you want it on the applet. The other objects can be resized and moved to precise locations as well. So now you have completed the methods that affect the screen layout, but you need to create methods to run the timer.

Step 5c: Define the runTimer() Method

The timer itself is run from the runTimer() method. The runTimer() method is invoked when the user presses the button on the screen. When the button is pressed, a message indicating that the user should get ready is displayed and an audio clip telling the user to get ready and to start is played. When the audio clip stops, the displayed message is changed to indicate that the user should start.

The runTimer() method is responsible for storing the start time, which is created as a date object. The method converts the hours, minutes, and seconds of the start time to seconds. The value in seconds of the start time is stored in a local variable. This value is passed to the method that checks for the timer being expired. For more robustness, the day could be included in this value. The code for these activities is displayed in Listing 14.4.


Listing 14.4. The QuizMaker class runTimer() method.
/* Lets the user know to start,
 saves the start time and checks for time up */
    protected void runTimer() {
 Date  StartTime;    // Holds the time the timer started
 int  startSec;    // Start time in seconds

 // Let the user know to get ready
 StatusLabel.setText("Get the hour glass ready.");
 play(HglassURL,"startTimer.au");  // Play the start message
 StartTime = new Date();        // Get the starting time

 // Let the user know to start
 StatusLabel.setText("Time is slipping away.");

 // Calculate the start time in seconds
// Get the number of seconds
 startSec = StartTime.getSeconds();
// Convert minutes to seconds and add
 startSec += (StartTime.getMinutes() * 60);
// Convert hours to seconds and add
startSec += (StartTime.getHours() * 60 * 60);

 while (!stopTimer(startSec)) {}// Loop looking for the time up

 // Inform the user time is up
 StatusLabel.setText("The hour glass is empty!");
 play(HglassURL,"endTimer.au");
    }

The first line of the runTimer() method is protected so that it cannot be run by an arbitrary object; only the QuizMaker class and its subclasses have access to the runTimer() method. Currently, there are no other classes in the applet that use this method. However, if the applet is included as part of a larger project, creating the method as protected maintains the encapsulation expected in object-oriented programming. void following protected indicates that the method does not return any values. The next word, runTimer, is the name of the method.

The next two lines declare the instance variables StartTime and startSec. StartTime is a local instance of the Date object. It is declared locally because none of the other methods need to access these values, so there is no reason to share them. It is an object because that is what is returned by the Date() constructor. The variable startSec is declared as an integer value. This variable stores the time value of the StartTime object converted to seconds. This variable is created locally and then passed to the EndTimer method. The advantage of passing the variable as opposed to making it available to the entire class is that it prevents accidental manipulation of this important value.

The next line displays new text to the user using the StatusLabel object. The text of the label can be changed while the program is running using the setText() method of the Label class so that it can be used for displaying the computed value. To call this method for the correct object, the applet must have a name to reference the object.

The audio clip is played in the same manner as it was in the init() method. The URL object is defined at the class level, so it is available in this method. The audio clip instructs the user to get ready for the timer to start and then says Go.

The constructor Date() is used to create a new Date object. Used without parameters as it is here, constructor returns a Date object containing the current time and date. This object is then designated as StartTime.

Next, the text Time is slipping away. is displayed to the user on the Label object. The label displayed to the user is modified by the same means in several places. The text is modified using the SetText(text) method of the Label class. This method takes the new text as a parameter and causes the StatusLabel object to display it. Note that this does not create a new object, nor does it modify the text directly. SetText(text) instructs the Label object, in this case, StatusLabel, to change its own text.

The starting time in seconds is then calculated. First, the getSeconds() method of the Date class is used to get the seconds value in the starting time. This value is stored in the startSec variable. Second, the getMinutes() method returns the minutes value from the starting time. The number of minutes is multiplied by 60 to get the number of seconds, which is added to the value in startSec using the += operator. This operator is used again to add the number of seconds to the starting time.

The method then loops, calling the stopTimer(int) method. This method returns false when the current time is less than three minutes after the time passed to it. It returns true if the current time is more than three minutes after the time passed to it. The loop continues until the stopTimer(int) method returns true. In Chapter 16 you will modify the QuizMaker applet so that it will pause and wait for time to pass, but this loop will suffice for the present example.

When the stopTimer(int) method returns true, the remainder of the runTimer() method is executed. It changes the label to indicate to the user that the hourglass is empty. It also plays an audio clip to the user to indicate that the timer has expired.

Step 5d: Define the stopTimer() Method

As described previously, the stopTimer() method checks to see if the current time is more than 180 seconds after the time passed in as a parameter. If this condition is true, the method returns true; otherwise, it returns false. The code for the stopTimer() method is shown in Listing 14.5.


Listing 14.5. The QuizMaker class stopTimer() method.
/* Checks the current system time to determine if 180 seconds has
 elapsed since start */
    protected boolean stopTimer(int startSec) {
 int stopSec;

 Date StopTime = new Date();      // Get the new time
 stopSec = StopTime.getSeconds(); // Get the number of seconds
// Convert minutes to seconds and add
 stopSec += (StopTime.getMinutes() * 60);
// Convert hours to seconds and add
 stopSec += (StopTime.getHours() * 60 * 60);
 if ((stopSec - startSec) > 180) {
  return true;   // True means time has elapsed
 } else {
  return false;   // False means time has not elapsed
 }
    }

The stopTimer() method is protected because it would not make sense for another object to find out that the timer had expired. Only this object knows the start time, so only this object can do a valid comparison. The method returns a boolean value, so boolean is placed between protected and the method name.

After the method name, the type of the input variable is listed in parentheses. The integer input is expected to be the time, in seconds, when the timer was started. This could have been made a class variable of the QuizMaker class. However, that would have made it available to change by any method in the class, and only runTimer() really needs to change the value. Because only stopTimer() needs to read it, the value is passed in as a parameter.

In the lines after the declaration, stopTimer() gets the current time and converts it to seconds in the same manner as runTimer(). It then uses an if statement to determine when the difference in the number of seconds is greater than 180, meaning that more than three minutes have elapsed. Depending on the results of the if statement, the boolean value true or false is returned. Note that each must be stated explicitly and must follow the word return.

You have now finished all the methods that control the screen display and the timer. You still need to create a method that calls the runTimer() method. Keep in mind that the timer is started when the button is pressed. Pressing the button is a user event, so the next method you will define is the event handler.

Step 5e: Define the handleEvent() Method

The handleEvent() method is triggered by the runtime environment when a user, or other outside force, triggers an event. Events include activities such as a button being pressed or a window being resized. Events that are not handled by the method defined here will be handled by the handleEvent() method in one of the superclasses, such as the Applet class. In this sense the handleEvent() method is being extended, not overridden. The code for the method is shown in Listing 14.6.


Listing 14.6. The QuizMaker class handleEvent() method.
/* Event handler to detect when the button on the window is pressed */
    public boolean handleEvent(Event e) {
// If the window is closed end the program
 if (e.id == Event.WINDOW_DESTROY) {
     System.exit(0);
 }
// If the button is pressed start timer
 if (e.target instanceof Button) {
  runTimer();    // Start the timer
  return true;   // Return true so super does not act on event
 }
 return false;    // Return false so super can act on event
    }
  //The final brace ends the QuizMaker class
}

The handleEvent() method is public because this method will be invoked from the runtime environment. The method will return true if it successfully handles the event and false otherwise; therefore, a boolean return value is specified. The name handleEvent is followed by the input declaration. The event is passed an Event object named e.

In the first if statement, the event handler checks to see if e is caused by the window being closed by checking the id property of the Event object. If the window is being closed, this property will be equal to WINDOW_DESTROY, and the class exits using the System.exit(0) method. Otherwise, the handleEvent() method checks for the button being pressed.

The handleEvent() method determines that a button is being pressed by checking the target property of the Event object. If this property is a button, it means a button is being pressed. There is only one button in the QuizMaker applet, so the runTimer() method is triggered to run the timer. When it can handle the event, the handleEvent() method returns true. If an event other than the two events handled here should occur, the method will return false and allow the handleEvent() method in a superclass to respond to the event.

Step 6: Compile the Applet

Now that all the methods have been created, you can compile the completed applet. But before doing so, be sure that your path includes the directory containing the Java compiler, as specified in Chapter 2, "Getting Started with the JDK." When you compile the QuizMaker.java file, the Java compiler will create the QuizMaker.class file, which the runtime environment can load. When your applet has successfully compiled, you can view it using your World Wide Web browser or the Java applet viewer.

To compile QuizMaker using a graphical compiler, follow these steps:

  1. Drop the QuizMaker.java file onto the compiler or select Open from the compiler's File menu.
  2. Place the compiled output file called QuizMaker.class in the same directory as the source.

To compile QuizMaker using a command-line compiler, follow these steps:

  1. Change to the directory containing the source code and type the following at the command prompt:
    javac QuizMaker.java
  2. Place the compiled output file, called QuizMaker.class, in the same directory as the source.

Note
The javac command invokes the Java compiler. Note that you must pass the compiler the entire filename, including the .java extension. Also note that the name is case sensitive. If you do not pass the full filename with the correct extension in the correct case, the compiler will return an error saying it could not find your file.

The Finished Applet

Figure 14.2 shows the finished applet. Although this applet is a somewhat contrived example that extends only one class, it should give you practice in creating an applet and using some of the Java classes. The next applet example is more complex and will give you experience working with multiple objects in an applet.

Figure 14.2 : The QuizMaker applet.

The full text of the completed applet is shown in Listing 14.7. After successfully compiling and running the QuizMaker applet, as shown earlier, try modifying some of the parameters to see the results. For example, lengthen or shorten the wait time, change the sizes of the objects, and move the objects to other locations. You might also try adding pictures, text, or buttons. This will give you practice in working with objects in Java before you move on to the next applet.


Listing 14.7. The QuizMaker applet.
import java.awt.*;
import java.applet.*;
import java.util.*;
import java.net.*;

/**
 * Peter Norton's  Guide to Programming Java * The QuizMaker Applet
 * Acts as a three minute timer. Plays an audio message to start and
 * displays a start message. Plays an audio message at the end with
 * another display message.
 */

public class QuizMaker extends Applet {
Image  HglassImage; // Displays a picture of an hour glass
Button  RunButton; // Lets the user start the timer
Label   StatusLabel; // Displays the status to the user
URL  HglassURL; // URL of the applet

    public void init() {
   // Get the picture to add to the screen
 HglassImage = getImage(getCodeBase(),"Hglass.gif");

 // Add a label to display text which can not be altered by the user
 add(StatusLabel = new Label("Press Run to start timer"));

 // Add a button to start the timer
      add(RunButton = new Button("Run"));

  resize(400,300);    // Resizes the applet
 paint(getGraphics());   // Display applet with the objects on the screen

 HglassURL = getCodeBase();   // Gets the URL for the applet
 play(HglassURL,"intro.au");  // Play an intro
 play(HglassURL,"startTimer.au");  // Play the start message
 play(HglassURL,"endTimer.au");  // Play the end message
    }

    public void paint(Graphics g) {
 g.drawImage(HglassImage,250,10,this); // Draw the hour glass

 StatusLabel.resize(150,20);  // Resizes the label
 StatusLabel.move(10,10);  // Moves the label

 RunButton.resize(100,20);  // Resizes the button
 RunButton.move(20,40);   // Moves the button

    }

    /* Lets the user know to start, saves the start time
       and checks for time up */
    protected void runTimer() {
 Date  StartTime;    // Holds the time the timer started
 int  startSec;    // Start time in seconds

 // Let the user know to get ready
 StatusLabel.setText("Get the hour glass ready.");
 play(HglassURL,"startTimer.au");  // Play the start message
 StartTime = new Date();   // Get the starting time

 // Let the user know to start
 StatusLabel.setText("Time is slipping away.");

 // Calculate the start time in seconds
 startSec = StartTime.getSeconds(); // Get the number of seconds
 startSec += (StartTime.getMinutes() * 60); // Add # of minutes times 60

 while (!stopTimer(startSec)) {} // Loop looking for the time up

 // Inform the user the hour glass is empty
 StatusLabel.setText("The hour glass is empty!");
 play(HglassURL,"endTimer.au");
    }

    /* Checks the current system time to determine if 180 seconds
       has elapsed since start */
    protected boolean stopTimer(int startSec) {
 int stopSec;

 Date StopTime = new Date();  // Get the new time
 stopSec = StopTime.getSeconds(); // Get the number of seconds
 stopSec += (StopTime.getMinutes() * 60); // Add # of minutes times 60
 if ((stopSec - startSec) > 180) {
  return true;   // True means time has elapsed
 } else {
  return false;   // False means time has not elapsed
 }
    }

    /* Event handler to detect when the button on the window is pressed */
    public boolean handleEvent(Event e) {
 int myint;
// If the window is closed end the program
 if (e.id == Event.WINDOW_DESTROY) {
     System.exit(0);
 }
// If the button is pressed start timer
 if (e.target instanceof Button) {
  runTimer();    // Start the timer
  return true;   // Return true so super does not act on event
 }
 return false;    // Return false so super can act on event
    }
}

Creating a Second Applet

The second applet you create in this chapter is actually a new version of a CGI script that has been used on the Internet for some time. It converts a set of red, green, and blue (RGB) integer values into a single hex number. The conversion of RGB values to hex numbers is important on the World Wide Web because solid-color backgrounds are entered into HTML documents in hex. An added twist here is enabling readers to see the color displayed as a result of the RGB values they enter; this shows just some of what is possible with Java.

This applet, RGB2Hex, introduces several complexities not found in the QuizMaker applet. RGB2Hex shows how multiple classes can be extended in the same Java file and how multiple objects in the same applet can communicate with one another. RGB2Hex also shows how some of the objects you used in the previous example can be used in different ways. As you go along, feel free to add to or modify the RGB2Hex applet to suit your taste.

Conceptualization and Design of the Applet

As with the first applet, this section describes how to progress from an initial description of the applet to a complete design. The specification for the RGB2Hex applet is rather simple:

The applet allows the user to enter values for the red, green, and blue components of a color. When the user finishes entering these values, the applet displays the corresponding color and the hexadecimal value for the color.

By expanding this definition, you will see that the applet has three fields for entering numbers, each with an appropriate label. The applet needs a place to display the hexadecimal result, and a portion of the screen must be available to display the color. The user must have a means to indicate that new numbers have been entered and that the applet should display the new color and hexadecimal value by using a button labeled Display. Given this information, you can construct a screen layout.

Figure 14.3 shows the initial layout for the applet. To keep the applet short, the screen layout is a simple rectangle with the top used for data entry and the bottom used to display the color. There is a button to indicate that the user has finished entering data in the middle with the display field for the hexadecimal value to the right of it.

Figure 14.3 : Screen layout for the RGB2Hex applet.

The layout shown here could be divided into objects in many ways. In fact, you could create the entire applet as an instance of one object again. However, the code is easier to understand if you group the objects on the screen into an object containing controls and an object for the color display.

The field to display the results could be considered a separate object, but for simplicity it is created as part of the controls. This object also contains the labels, text entry fields, and display button, all of which are themselves objects. This completes the design of the applet, and you can move on to define the structure.

Defining the Applet Structure

As with the previous example, you must define which objects are present when the applet starts, when new objects are created, and how objects will communicate with each other. For the RGB2Hex applet, multiple existing Java classes are extended to provide the classes needed. Unlike the previous example, the RGB2Hex applet extends multiple classes, and the objects created must interface with one another.

The existing Canvas class is extended and used to display the color desired. Canvas supplies a constructor to create the object and a paint method to paint the background with the default background color. Canvas is generic and can be subclassed to provide a place to display the color the user has entered. It is extended so that the values entered by the user are stored as part of the object.

The paint method from the Canvas class is overridden. The new paint() method colors the object using the three internal values. A redraw method is added to update the internal values and call the paint method. The redraw method also returns the hexadecimal value for the color displayed.

The object for the controls is created by extending the Panel class, a generic container that can be used to hold other objects and display them in various ways on the screen. For the purpose of this applet, the object must hold three labels, three text entry fields, one button, and one display field. Each of these items is an object that will be created using existing classes. The objects are displayed in a standard grid layout. (The GridLayout is also an object defined in Java.)

Now that each object has been described, you must determine how they are created. The RGB2Hex applet is an extension of the Applet class. This class includes an init() method, which is called when the applet is created, as well as the canvas and the panel, which are created as part of the init() method for the applet. There is no need to create more than one instance of these objects as part of this applet.

The interactions between the objects are straightforward. When the button is pushed, the new color is displayed and the new hexadecimal value appears. To do this, the values entered in the text entry fields are passed to the canvas object. Either the canvas object or the control object could calculate the hexadecimal value; in this case, it is the canvas object. This value must be returned to the controls for display.

Building the Applet

Now that you have completed the structure of the applet, you can begin to actually build it. Although the construction of the code is not broken into separate steps as the first example, this section does provide a detailed description of each portion of the code. The RGB2Hex applet extends the Applet class and creates several accompanying classes. The code for each class is presented and a brief description of how the class works is given.

Creating the RGB2Hex Class

The Applet class is extended to create the RGB2Hex class, as shown in Listing 14.8. This class is responsible for creating additional objects and enabling the controls. The overall layout is the Java standard BorderLayout. This allows for placement of objects in North, South, East, West, and Center locations. The two objects you are creating for this applet will be in the North and Center locations. As part of initialization, the add() method is used to add the canvas and the controls to the frame. When the applet starts, it goes through initialization and then enables the controls. Then it adds itself to the frame and resizes the frame to 300¥300.


Listing 14.8. The RGB2Hex class.
public class RGB2Hex extends Applet {
    RGBcontrols controls;

    public void init() {
 setLayout(new BorderLayout());
 RGBcanvas c = new RGBcanvas();
 add("Center", c);
 add("North", controls = new RGBcontrols(c));
    }

    public void doColor() {
 controls.enable();
    }

    public void stop() {
 controls.disable();
    }

    public boolean handleEvent(Event e) {
 if (e.id == Event.WINDOW_DESTROY) {
     System.exit(0);
 }
 return false;
    }
}

This completes the RGB2Hex class. However, this applet has been designed to use multiple classes. These classes can all be created in the same .java file. The remainder of this section describes the other classes.

Creating the RGBcanvas Class

The second class to create is the RGBcanvas class, as shown in Listing 14.9. This class is called in the second line of the init() method in the RGB2Hex class to create the object c. This object displays the color on the basis of the values entered by the user. The class is created by extending the Canvas class, which is part of the Java API.

The RGBcanvas class stores the three values the color is created from and the color value. The three RGB values are stored as integers. The color is stored as a Color object that is returned by the Java method Color(int, int, int) in the Color class, which encapsulates the RGB colors.

Three Color constructors can be used to create a Color object. The constructor used here takes the red, green, and blue values as separate integer parameters. The other constructors allow the red, green, and blue values to be specified as portions of a single integer or a floating-point value.

Two methods of the original Canvas are replaced. A new paint() method overrides the paint() method defined in the Canvas class. A new redraw() method replaces the existing Canvas class redraw() method.

The new paint() method colors the canvas using the three values, which are internal to the RGBcanvas class. It uses the bounds method for the Rectangle class to determine the size of the rectangle to color. The method creates a new color using the three values stored internally and then stores this value in the internal variable createColor. Then paint() sets the default color for the RGBcanvas to the newly created color and paints a rectangle the size of the RGBcanvas.

The redraw() method is created to load the numbers it receives as inputs into the internal values of the object. It then calls the repaint() method to color the object. repaint() is defined in the Component class and inherited by the Canvas class. It calls paint to repaint the Canvas. After calling the repaint() method, redraw() creates a hexadecimal value based on the values entered by the user and returns it to the calling method.


Listing 14.9. The RGBcanvas class first draft.
class RGBcanvas extends Canvas {
    int  RedValue = 12;
    int  GreenValue = 156;
    int   blueValue = 88;
    Color  createColor;
    String  HexString;
    String  HexFinal;

    public void paint(Graphics g) {
 Rectangle r = bounds();

 createColor = new Color(RedValue, GreenValue, blueValue);
 g.setColor(createColor);
 g.fillRect(0,0,r.width,r.height);
    }

    public String redraw(int red, int green, int blue) {
 String HexString;

 this.RedValue = red;
 this.GreenValue = green;
 this.blueValue = blue;
 repaint();
 HexString = Integer.toString(red,16);
 while (HexString.length() < 2)
     HexString = "0" + HexString;
 HexFinal = HexString.toUpperCase();

 HexString = Integer.toString(green,16);
 while (HexString.length() < 2)
     HexString = "0" + HexString;
 HexFinal = HexFinal + HexString.toUpperCase();

 HexString = Integer.toString(blue,16);
 while (HexString.length() < 2)
     HexString = "0" + HexString;
 HexFinal = HexFinal + HexString.toUpperCase();

 return HexFinal;
    }
}

This code will work but is difficult to read because of the complicated conversion used to create the hexadecimal string. To simplify this code, the redraw method needs an easy way to convert from an integer in base 10 to hex. You could use the toString method of the Integer class to do the conversion, but this does not give the exact format desired. The redraw method must be sure the string returned has two characters and that the letters are uppercase.

Creating the HexInt Class

The simplest way to provide the conversion needed is to create a new class called HexInt, as shown in Listing 14.10. This class stores an integer and returns its value as a hexadecimal. The method toHexString(int) will return a string with the number of characters specified in the input parameter. The method uses the while statement to check that the string has fewer characters than the input.


Listing 14.10. The HexInt class.
class HexInt {
    int HInt;

    public HexInt(int AnInteger){
 HInt = AnInteger;
}
    public String toHexString(int StrLen) {
 String HexString;

 HexString = Integer.toString(HInt,16);
 while (HexString.length() < StrLen)
     HexString = "0" + HexString;
 return HexString.toUpperCase();
    }
}

This class simplifies the redraw method in the RGBcanvas class. The HexInt class also allows the hexadecimal result to be calculated with a single assignment statement.

Error Handling for RGBcanvas

You can further enhance the RGBcanvas class by adding error handling. Despite the label giving the valid range, there is always the possibility that a user will enter values outside the valid range. If the values entered exceed the acceptable limits, the applet should return an error message.

Error checking could be added to the controls to prevent the applet from invoking the redraw() method when the user enters invalid values. However, the redraw() method could be invoked from some other location that could also supply an incorrect value. Therefore, error checking is added to the Canvas class in the redraw() method.

The redraw() method must check that each of its inputs is valid. In this case, valid inputs are numbers between 0 and 255. If redraw() receives an input outside this range, it must return an error string instead of the hexadecimal string and leave the color of the canvas unchanged. The error string used here is "Learn to count", but you can use any string. The method uses an if statement to check for integers outside the range. The double pipe symbols || represent the logical OR operator. Here's the code for error checking the red color value:

if ((red < 0) || (red > 255)) {
  return "Learn to count";
}

All three error checks could be combined into one if statement. However, they are separated for clarity's sake. When the caller receives the message back from the Canvas object, it does not know whether the color changed. The caller simply displays the text string in the block provided and allows the user to decide what to do next. It is up to the user to determine that the input values were outside the specified range and to enter new values. However, incorrect values do not cause the program to abort, nor do they affect any other part of the program.

This method of error checking does not handle the possibility that the user may enter text instead of a number. If text is entered, the parseInt() method will generate an error. This will not be returned to the user, but because of the object-oriented nature of Java, this type of error will not cause a problem for the running applet. Although it is not needed for the users of this applet, code could be added to check each entry prior to converting it to an integer.

The final RGBcanvas class using the HexInt class and including error handling is shown in Listing 14.11.


Listing 14.11. The revised RGBcanvas class.
class RGBcanvas extends Canvas {
    int  RedValue = 12;
    int  GreenValue = 156;
    int   blueValue = 88;
    Color  createColor;

    public void paint(Graphics g) {
 Rectangle r = bounds();

 createColor = new Color(RedValue, GreenValue, blueValue);
 g.setColor(createColor);
 g.fillRect(0,0,r.width,r.height);
    }

    public String redraw(int red, int green, int blue) {
 String HexString;

 this.RedValue = red;
 this.GreenValue = green;
 this.blueValue = blue;
     if ((red < 0) || (red > 255)){
  return "Learn to count";
 }
 if ((green < 0) || (green > 255)){
  return "Learn to count";
 }
 if ((blue < 0) || (blue > 255)){
  return "Learn to count";
 }
 repaint();
 HexString = new HexInt(red).toHexString(2) + new HexInt(green).toHexString(2)
Â+ new HexInt(blue).toHexString(2);
 return HexString;
    }
}

Now that the display on the canvas looks good, you must create a class to operate the controls you provide for the user.

Creating the RGBcontrols Class

The RGBcontrols class shown in Listing 14.12 provides a place for data entry and display. The control extends the existing Panel class. The class contains eight objects arranged in a grid pattern. GridLayout allows the developer to specify a certain number of rows and columns. In this case, there are four rows and two columns. The grid is filled from left to right and from top to bottom. Each of the objects it contains are instances of defined Java objects.

TextField enables the user to edit a single line of text. The class has four possible constructors. The constructor used here takes a single string parameter and uses it as the initialization string for the new field. The TextField class is a subclass of TextComponent, which supplies a getText() method that returns text in the TextComponent. Because each field must be referenced individually to retrieve the values the user enters, the objects are given identifiers that are internal to the Panel class: redField, greenField, and blueField.

The labels for the data entry fields are created using the Label class from the Java API. The Label class displays a single line of read-only text. The class allows for the alignment to be specified as LEFT, RIGHT, or CENTER. In this case, the default alignment, LEFT, is used. The labels for the text entry fields are placed to the left of the fields themselves. The applet does not need to update these objects, so they are not explicitly named. They are created using the new command when they are added to the RGBcontrols object.

The object used to display the hexadecimal code is called HexValue and is declared as part of the RGBcontrols class. It must be explicitly named so that it can be referred to and its setText() method invoked to change the display value. The value returned from the RGBcanvas class redraw() method is used as input to the setText() method.

The button used to signal that the user has finished entering new values and would like to see the results is created using the Button class from the Java API. This is another object that the applet does not need to update. Therefore, the object does not need a name and is created when it is added to the layout. Here, the button is created as an instance of the class Button. This class supplies a constructor, which takes a string parameter and uses it as the label for the button.

Only one method in the Canvas class must be overridden: the action() method, which is defined in the Component class and triggered any time an action occurs in a component. There is only one action to which the applet responds in this class-pressing the button. If there were multiple actions, you could use a switch statement to determine which action had occurred.

In this case, an if statement at the beginning of the method checks for the triggering event (pressing a button). There is only one button in the object, so there is no need to determine which button was pressed. If additional buttons were added, the method could use a switch statement to determine which button was pressed by checking the label of the button that triggered the event.

When the button is pressed, the action() method uses the getText() method to get the strings in the text fields. action() then uses the trim() method, defined as part of the String class, to remove any whitespace from around the text. Next, action() creates integers from the strings using the parseInt() method. To do this, it must create an instance of the Integer object for each string.

When the conversion is complete, action() passes the resulting integers to the redraw() method of the Canvas object. The string returned from redraw() is displayed by the HexValue object using the setText() method, defined as part of the TextComponent class, of which TextField is a subclass.


Listing 14.12. The RGBcontrols class.
class RGBcontrols extends Panel {
   TextField redField; /* Field to enter the value for red */
   TextField greenField; /* Field to enter the value for green */
   TextField blueField; /* Field to enter the value for blue */
   Label HexValue; /* Location to display the hex value */
    RGBcanvas canvas;

    public RGBcontrols(RGBcanvas canvas) { /* primary method declaration */
 setLayout(new GridLayout(4,2));
 this.canvas = canvas;
 add(new Label("RED        Enter 0 to 255"));
 add(redField = new TextField("12"));
 add(new Label("GREEN   Enter 0 to 255"));
 add(greenField  = new TextField("156"));
 add(new Label("BLUE      Enter 0 to 255"));
 add(blueField = new TextField("88"));
 add(new Button("Display"));
 add(HexValue = new Label(""));
    }

    public boolean action(Event ev, Object arg) {
 if (ev.target instanceof Button) {
     HexValue.setText(canvas.redraw(
  Integer.parseInt(redField.getText().trim()),
  Integer.parseInt(greenField.getText().trim()),
  Integer.parseInt(blueField.getText().trim())));

     return true;
 }

 return false;
    }
}

This completes the creation of the classes needed for the RGB2Hex applet. The next section provides all the code needed to create the applet in its final form.

The Finished Applet

Figure 14.4 shows how the RGB2Hex applet looks in the Netscape Navigator. For additional practice in modifying Java objects, you might move the display box for the hex number from the RGBcontrols object to the RGBcanvas object. Be sure to modify the paint of the canvas so the rectangle that changes color does not cover the text field displaying the hexadecimal number.

Figure 14.4 : The RGB2Hex applet in Netscape.

The complete text for the RGB2Hex applet is shown in Listing 14.13. When you compile the source code for the applet, one class file will be created for each declared class. To run the applet, name the RGB2Hex class in the <APPLET> tag of an HTML document. The RGB2Hex class calls the other class files when they are needed.


Listing 14.13. The RGB2Hex applet.
import java.awt.*;
import java.applet.*;

/**
 * Peter Norton's  Guide to Java Programming * The RGB2Hex Applet
 * Converts Red, Green, and Blue values entered by the user to a
 * hexidecimal color code and displays the color. Can be run either
 * as a standalone application by typing "java RGB2Hex" or as an applet.
 */

public class RGB2Hex extends Applet {
    RGBcontrols controls;
    TextField test1;

    public void init() {
 setLayout(new BorderLayout());
 RGBcanvas c = new RGBcanvas();
 add("Center", c);
 add("North", controls = new RGBcontrols(c));
    }

    public void doColor() {
 controls.enable();
    }

    public void stop() {
 controls.disable();
    }

    public boolean handleEvent(Event e) {
 if (e.id == Event.WINDOW_DESTROY) {
     System.exit(0);
 }
 return false;
    }

    public static void main(String args[]) {
 Frame f = new Frame("RGB2Hex");
 RGB2Hex RGB2Hex = new RGB2Hex();

 RGB2Hex.init();
 RGB2Hex.doColor();

 f.add("Center", RGB2Hex);
 f.resize(300, 300);
 f.show();
    }
}

/* Provides a hexidecimal representation of an integer */
class HexInt {
    int HInt;

    public HexInt(int AnInteger){
 HInt = AnInteger;
    }

    public String toHexString(int StrLen) {
 String HexString;

 HexString = Integer.toString(HInt,16);
 while (HexString.length() < StrLen)
     HexString = "0" + HexString;
 return HexString.toUpperCase();
    }
}

/* Provides an object to display a color */
class RGBcanvas extends Canvas {
    int  RedValue = 12;
    int  GreenValue = 156;
    int   blueValue = 88;
    Color  createColor;

    public void paint(Graphics g) {
 Rectangle r = bounds();

 createColor = new Color(RedValue, GreenValue, blueValue);
 g.setColor(createColor);
 g.fillRect(0,0,r.width,r.height);
    }

    public String redraw(int red, int green, int blue) {
 String HexString;

 this.RedValue = red;
 this.GreenValue = green;
 this.blueValue = blue;
     if ((red < 0) || (red > 255)){
  return "Learn to count";
 }
 if ((green < 0) || (green > 255)){
  return "Learn to count";
 }
 if ((blue < 0) || (blue > 255)){
  return "Learn to count";
 }
 repaint();
 HexString = new HexInt(red).toHexString(2) + new HexInt(green).toHexString(2)
 Â+ new HexInt(blue).toHexString(2);
 return HexString;
    }
}

/* Provides for user entry of RGB values and displays hexidecimal */
class RGBcontrols extends Panel {
   TextField redField; /* Field to enter the value for red */
   TextField greenField;/* Field to enter the value for green */
   TextField blueField; /* Field to enter the value for blue */
   Label HexValue; /* Location to display the hex value */
    RGBcanvas canvas;

    public RGBcontrols(RGBcanvas canvas) { /* primary method declaration */
 setLayout(new GridLayout(4,2));
 this.canvas = canvas;
 add(new Label("RED        Enter 0 to 255"));
 add(redField = new TextField("12", 4));
 add(new Label("GREEN   Enter 0 to 255"));
 add(greenField  = new TextField("156", 4));
 add(new Label("BLUE      Enter 0 to 255"));
 add(blueField = new TextField("88",4));
 add(new Button("Display"));
 add(HexValue = new Label(""));
    }

    public boolean action(Event ev, Object arg) {
 if (ev.target instanceof Button) {
     HexValue.setText(canvas.redraw(
  Integer.parseInt(redField.getText().trim()),
  Integer.parseInt(greenField.getText().trim()),
  Integer.parseInt(blueField.getText().trim())));

     return true;
 }

 return false;
    }
}

Comparing the QuizMaker Applet with the RGB2Hex Applet

The RGB2Hex applet has some similarities to the QuizMaker applet. Both are created by extending the Java Applet class. Some of the same classes, buttons, and labels are used in both applets, although they appear different on the display. Both applets depend on the init() method to create additional objects. Both applets trap and handle user events.

The applets each demonstrate different points. The first example illustrates that applets do not have to define multiple new classes. The second example shows that objects can be created, used, and displayed without being explicitly named. It also demonstrates how multiple objects in an applet can work together without one having to create the other.

The overall organization in each applet is different as well. The QuizMaker applet, containing a single class, leaves the handling of events up to that class. The RGB2Hex applet divides the work better because it has three classes. The controls can handle responding to user events while the Canvas handles the display. The RGB2Hex class is responsible for creating instances of the other two classes and handles the starting and stopping of the applet.

The only remaining challenge in creating the applets in this chapter is testing and debugging the code. Testing is important in creating software because errors can be costly in terms of performance and user confidence. The next section provides some suggestions for testing and debugging Java applets.

Testing and Debugging

A well-designed applet is easy to test and debug; the best check against logic problems is a well-thought-out design. Object-oriented languages, such as Java, assist with this by encapsulating information and preventing the programmer from making modifications that can have unexpected effects on other portions of the code. This does not mean that all code written in Java will be bug free. It is still possible to expect an object to behave in one manner and for its actual behavior be different.

The easiest type of problem to fix is a compiler error. Some of the basic problems that will cause the compiler to complain include the following:

The errors generated by the Java compiler often pinpoint the problems exactly, yet it is also common for one of the listed mistakes to generate several unrelated compiler errors. For example, not declaring an instance variable that is passed to a method could result in a compiler error saying the method is not defined for the type of parameters specified. Missing braces can result in other errors, including undefined variables.

Java is case sensitive: TextField and textfield are considered two different objects; therefore, verify the case of each letter of identifiers that are not recognized by the compiler.

There are several steps you can take to minimize both compiler and runtime errors:

Summary

In this chapter you have created two intermediate Java applets. You have gained experience in working with a variety of the objects supplied in the Java API and with extending classes. You have practiced designing applets and determining how a specification can be expanded into a complete object-oriented design. You have gained some experience in a step-by-step construction of applets and learned some techniques for debugging applets. You should now feel comfortable creating your own intermediate Java applets.