Chapter 12

!

Applets in Cyberspace





As we mentioned in the text, the lablets for this chapter tie together nearly all of the Java language features and programming topics that we have discussed throughout the book. These programs make use of most of Java's statements and standard classes, as well as arrays, packages, inheritance, exceptions, and threads, all in the realistic context of creating graphical and animated buttons. The resulting classes are written generally so that they can be used directly in any future programs that you write. So, by completing this last set of exercises you will have reached the point where you can implement useful, re-usable, "industrial-strength" widgets of your own devising (with a little help from us).
The new material that is illustrated here, dealing primarily with Java's multimedia classes, also represents an interesting closure because it presents Java in its original intended context: as a language for writing programs for the Worldwide Web. The relationship between Java and HTML is, at long last, made explicit here, and the virtues of the aforementioned language features become more obvious than ever.


Lab Objectives

In this lab, you will:
 o

View the two lablets for this chapter from within a single HTML page.

 o

See how we can provide parameters to an applet using HTML, and how applets access and make use of parameters.

 o

Experiment with the parts of the lablets that use the Image and MediaTracker classes.

 o

Extend both lablets to do more advanced image processing.

Exercises

  1. Typically, we ask you to start a set of lab exercises by running the lablet for the chapter, and this last chapter is no different in that regard. What is different is that there are two lablets to run. You could compile and run each one separately, but we've already provided you with everything you need to view both applets in action at once.

    1. Here's the listing of the HTML file "sample.html" that we use to display our applets:
      <HTML>
         <HEAD>
            <TITLE>Ch. 12 Lablet</TITLE>
         </HEAD>
      	
         <BODY bgcolor = white>
         <H1>Two Button Applets</H1>
         <BR>
         <HR>
         <APPLET CODE = "OldButtoner.class" WIDTH = 82 HEIGHT = 27 ALIGN = left>
            <PARAM name = "pattern" value = "bttn*.gif">
            <PARAM name = "numPix" value = "2">
            <PARAM name = "label" value = "Home">
            <PARAM name = "destURL" value = "http://www.bogus.edu/">
         </APPLET>
         <APPLET CODE = "Buttoner.class" WIDTH = 82 HEIGHT = 27 ALIGN = right>
            <PARAM name = "pattern" value = "animate/ab*.gif">
            <PARAM name = "numPix" value = "11">
            <PARAM name = "label" value = "Home">
            <PARAM name = "destURL" value = "http://www.alsobogus.org/">
         </APPLET>
         The button on the left is an ordinary GraphicButton.  The one on the
         right is an AnimatedButton.  To make life easier when running this,
         neither of the buttons actually take you anywhere.
         <HR>
         <A HREF = "Buttoner.java">See the source.</A>
         </BODY>
      </HTML>
      
      This is the file that is described in Section 12.4 of the text. It contains two APPLET elements, one referring to our first lablet (OldButtoner), and the other referring to our second lablet (Buttoner). Viewing this file will run both lablets and display them on the same browsed page. Run the applets now. Click on the buttons to watch them do their stuff. If you'd like to see (or copy) the images we use for each of the buttons, go to the image page.

    2. Not only do we have two lablets referenced from a single HTML file, but our lablets are composed of four classes, a collection of image files (with ".gif" extensions), and a package. It is important before we start working with these programs that you understand the relationships between all of the files involved. Look at the source code for the following four classes, and then answer the questions below.


      1. What is myWidgets?
        Answer:


      2. What does myWidgets contain?
        Answer:


      3. Which files use myWidgets? How does each file use it?
        Answer:


      4. What type of object is OldButtoner?
        Answer:


      5. OldButtoner refers to which of our buttons, GraphicButton or AnimatedButton?
        Answer:


      6. As it is currently invoked from "sample.html," which image files are used by OldButtoner?
        Answer:


      7. What type of object is Buttoner?
        Answer:


      8. Which of our button classes does Buttoner refer to?
        Answer:


      9. In Java terms, what is the relationship between GraphicButton and AnimatedButton?
        Answer:


      10. In ordinary language, describe the relationship between GraphicButton and AnimatedButton.
        Answer:


  2. Before we begin experimenting with the Java code that implements our new buttons, let's look more closely at the HTML code that we're using to invoke our applets. By changing the parameter values that we provide for the applets, we can illustrate many of their features and capabilities. Make each of the following changes, one at a time, to the original version of "sample.html". Then, record and explain how the applets and browser responded to the change.

    1. Change the value of OldButtoner's "label" parameter to "Graphic".
      Result:


    2. Change the value of Buttoner's "label" parameter to "Animate".
      Result:


    3. Remove the "label" parameter from both APPLET elements.
      Result:


    4. Change the value of OldButtoner's "numPix" parameter to "5".
      Result:


    5. Change the value of OldButtoner's "numPix" parameter to "1".
      Result:


    6. Change the value of OldButtoner's "pattern" parameter to "wrong*.gif".
      Result:


    7. Change the value of OldButtoner's "pattern" parameter to "animate/ab*.gif".
      Result:


    8. Change the value of one of the "destURL" parameters to any legal URL that you know, like that of your personal home page. If you don't know any others, you can always use the value "http://www.hamilton.edu/academics/compsci/".
      Result:


  3. Now, in our more customary way, we ask you to make some changes to the Java code for our lablets. We will concentrate, as you would expect, on those language features that implement the lablet's abilities to process applet parameters and images. Make these changes to the original version of the indicated file, and record and explain either the resulting error, or the change in behavior.

    Make the following changes to the class OldButtoner:

    1. Remove the line that reads:
      import myWidgets.*;
      Result:


    2. Change the line in function init() that reads:
      numImgs = getIntParameter("numPix", 2);
      to read:
      numImgs = getIntParameter("numPix", 0);
      Result:


    3. Change the line in init() that reads:
      theLabel = getParameter("label");
      to read:
      theLabel = getParameter("myLabel");
      Result:


    4. Remove the lines in function loadImages() that read
      try
      {
      tracker.waitForID(i);
      }
      catch (InterruptedException e)
      { }
      Result:


    5. Change the line in function getParameterInfo():
      String[][] aboutParams = {
      to
      String[] aboutParams = {
      Result:


    6. Remove the open brace from the line in getParameterInfo() that reads:
      String[][] aboutParams = {
      and one of the close braces from the line that reads:
      {"destURL", "URL","destination when clicked"}};
      Result:


    Make the following changes to the class GraphicButton:

    1. Change the line that reads:
      protected Image[] theImage;
      to read:
      private Image[] theImage;
      Result:


    2. Change the line that reads:
      protected int curImage = 1;
      to read:
      protected int curImage = 0;
      Result:


    3. Remove (or comment out) the line in function fitLabel() that reads:
      FontMetrics fm = getFontMetrics(getFont());
      Result:


    4. Change the line in function fitLabel() that reads:
      labelBase = (thisHeight+fm.getAscent() - fm.getDescent())/ 2;
      to read
      labelBase = (thisHeight+fm.getAscent() - fm.getDescent());
      Result:


    5. Remove (or comment out) the line in function mouseReleased() that reads:
      listeners.actionPerformed(ae);
      Result:


    Make the following change to the class Buttoner:

    1. Change the line in function init() that reads:
      theButton = new AnimatedButton(images, theLabel, 100);
      to read
      theButton = new AnimatedButton(images, theLabel, 0);
      Result:


  4. It is time, at last, to make some more substantive changes to the original version of our lablets, ones that will extend their behavior in more useful ways. As usual, we ask you to make the proposed extensions one at a time, testing them out as you go. Since they build upon one another, do them in the order listed.

    1. Right now, the label colors for an up, down, or highlighted GraphicButton are tailored to look good with one particular image set. A red highlight color would be a pretty bad choice, though, if the button image happened also to be red. Change GraphicButton so that its three label colors can be set when the constructor is called.

    2. As currently implemented, a GraphicButton acts visually like an ordinary AWT button: When the mouse goes down over the button, the image changes, but it is changed back immediately when the mouse is released. Change GraphicButton so that it produces a "locking button"--one that "goes down" when clicked, and stays that way until it is clicked again, when it "pops up."

    3. Now, extend class GraphicButton so that the button it produces is disabled when it is in the "down" state. That is, clicking on it when it is already "down" should not direct you to a new URL, but should merely "pop the button up," by changing its image and enabling it.

    4. At present, our AnimatedButton "bounces through" the images used to represent its "up" state. That is, if we provide a total of 5 images for an animated button (image 0 to be used for the "down" state, and images 1-4 for its "up" state), it displays the "up" images in the order 1, 2, 3, 4, 3, 2, 1, 2, 3, 4, 3, 2, 1,. . . . Change the algorithm so that animated images cycle through their "up" images, displaying our 4 images in this order: 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4,. . . .

    5. You may have already noticed that our two applet classes, OldButtoner and Buttoner, are nearly identical. The only significant difference is that one creates a GraphicButton object, and the other creates an AnimatedButton. Create a new applet, named NewButtoner, which consolidates these two applets into one. NewButtoner, like the original versions of its predecessors, should accept parameters for its image file pattern, the number of images, a label, and a destination URL. Based, though, on the value of the "numPix" parameter, NewButtoner should attempt to create a button of the appropriate type. If the value of "numPix" is greater than 2, an AnimatedButton should be produced; otherwise, a GraphicButton will be created. As before, it no "numPix" parameter is specified, or an illegal number is entered for its value, NewButtoner should simply create a default AWT button.


Postlab Exercises

  1. Using your "locking buttons" version of GraphicButton from Exercise 4.b above, create an applet that produces a "locking button group"--that is, a collection of locking graphic buttons displayed in a single panel, only one of which can be "down" at any time.

  2. If we want them to perform as advertised, we must provide two images to be used in rendering a GraphicButton, and at least three for an AnimatedButton. Let's try to simplify things for the users of our classes, as follows.

    1. Change class GraphicButton so that it accepts a single image as a parameter (you can use the value of the "pattern" parameter to specify the file name for the image, and can get rid of the "numPix" parameter). Then, have GraphicButton use an image filter, [pp. 532-535] to create a different version of the image that will be displayed for the button's "down" state. For "sculptural" buttons, like the images we've provided, an InvertFilter often works well.

    2. Change class AnimatedButton so that it, too, requires only a single image as its "pattern" parameter. It should, like the revised GraphicButton above, use a filter to produce the image to be used for the button's "down" state. The "up" states for the animated button should be produced be repositioning the button's label. That is, the image for the animated button will not change when the button is "up," but the position of the label will. So, an animated button with a "label" value of "Hi!" might cycle through four animated images as follows.



    3. Finally, have both buttons produce another filtered image (using a FadeFilter [Ex. 12, p. 566], for example) for use when the button is disabled, and implement an override of the function setEnabled() so that a disabled button shows up as faded and will not respond to any user actions.

  3. Now that you know how to create custom widgets, you don't have to be limited to just the ones in the AWT. For example, a spinner is a widget that contains a text label, a field for displaying an integer, and a pair of arrows, used to increment and decrement the value displayed. Here's what a spinner might look like on a gray background:

    A spinner constructor should allow the user to specify the label text, the upper and lower limits of the number, and the number's initial value. Along with responding appropriately to user input, a Spinner object should have methods setValue() and getValue() that allow access to the displayed number. Implement a Spinner class and make an applet containing a Spinner object.


Last updated: December 4, 1998
Rick Decker
Department of Computer Science
Hamilton College
Clinton, NY 13323