Technical: Java
Advanced Search
Apple Developer Connection
Member Login Log In | Not a Member? Contact ADC

Building the Rollover Button



File: RolloverButton.java


Contents

Overview
1) Declaring the Data Members

2) Initializing the Rollover Button

3) Implementing refreshImage( )

4) Implementing handleMousePressed( )

5) Implementing handleMouseReleased( )

6) Implementing handleRollover( )
Summary

Overview

The RolloverButton is the second tier of a series of classes that encapsulates the functionality of buttons for the slide show controller. As the image below demonstrates, this class is derived from ImageButton.

Button Diagram

While the ImageButton class contains basic functionality such as MouseEvent handling and methods to handle images and paint the component (see Building the Image Button), it defines several abstract methods that are implemented in this class. These methods are handleRollover( ) and handleMousePressed( ). This class implements these methods in order to provide rollover functionality; i.e., when the user hovers over a button, the image changes. When the user clicks on the button, the image changes to a depressed button state. The state returns to normal when the user leaves the button.

This class also defines a single abstract function called initImages( ) which must be implemented in the derived classes ForwardButton, BackwardButton, and PlayPauseButton.

Back to top

Steps to Follow

Step 1 - Declaring the data members

The class RolloverButton is an abstract class. Like the ImageButton class, this means that it cannot be directly instantiated. Only derived classes that implement the initImages( ) method which is declared as abstract (more on this later) may be instantiated. We are extending ImageButton in order to take advantage of all of the basic image and event handling behavior we implemented in that class.

You may notice that there are no import statements at the beginning of the class. That is because we require no additional imports other than the implicit java.lang.* package. Our class knows about the ImageButton class because these two classes are in the same package.

public abstract class RolloverButton extends ImageButton
{
    //Declare data members
    //Insert "RolloverButton data members"


Locate the RolloverButton data members clipping in the RolloverButton folder and drag it directly below the last line of code shown above. Your code should now look like this:

public abstract class RolloverButton extends ImageButton
{
    //Declare data members
    //Insert "RolloverButton data members"
    protected String upImage;
    protected String downImage;
    protected String rolloverImage;


We declare three data members, all of which are strings. These are the names of the images to be used for the various states. The first, upImage is the default image to use when the user is outside the bounds of the button and the button is not depressed. The second, downImage is used when the user has clicked the mouse on the button and has not yet released the button. Lastly, the rolloverImage is the name of the image to use when the user is hovering over the button with the mouse cursor, but the button has not yet been pressed.

Now that we have our data members, it is time to look at the constructor.

Back to top

Step 2 - Initializing the Rollover Button

We initialize the button in the constructor.

Public RolloverButton( )
{
    //Initialize the state of the button
    //Insert "RolloverButton init state"


Locate the RolloverButton init state clipping in the RolloverButton folder and drag it directly below the last line of code shown above. Your code should now look like this:

public RolloverButton( )
{
    //Initialize the state of the button
    //Insert "RolloverButton init state"
    upImage = "up";
    downImage = "down";
    rolloverImage = "rollover";
    initImages( );
    setImage(upImage);
}


We assign the three data members identifiers that we will be using to refer to the individual images. For example, we associate the string “up” with the variable upImage. The string “up” is what will be used as the key in the hashtable for the image to be used when the button is in its up state.

Next we call our initImages( ) method. Again, this is an abstract method and is not defined in this class. Subclasses must override this method and specify the actual images to be used.

Finally, we call setImage( ) using the upImage as the key. If no image is specified, nothing will happen. We recall from Step 7 in ImageButton that we check to see if an image is loaded. If "up" was not found in our hashtable, it will be null, and thus setImage( ) won’t do anything. Now it is time to look at refreshImages( ).

Back to top

Step 3 - Implementing refreshImage( )

When we need to update the state of the button, refreshImage( ) is used. It checks the current button state and loads the correct image to display.

/**
 * Sub classes need to define this to handle initializing their
 * images, and state information.
 */
 protected abstract void initImages( );
	
/**
 * Sets the button to be in the correct configuration for the
 * current state.
 */
 Public void refreshImage( )
 {
     //Handle determining the current state, and reacting 
     //appropriately
     //Insert "RolloverButton refreshImage"


After the abstract declaration of initImages( ) which we previously discussed, we reach refreshImage( ). This method is only called from our derived class PlayPauseButton, but it could be useful to any future derived classes that might need this functionality, which is why we have chosen to place it in this class rather than PlayPauseButton. Locate the RolloverButton refreshImage clipping in the RolloverButton folder and drag it directly below the last line of code shown above. Your code should now look like this:

/**
 * Sub classes need to define this to handle initializing their
 * images, and state information.
 */
 Protected abstract void initImages( );
	
/**
 * Sets the button to be in the correct configuration for the
 * current state.
 */
 Public void refreshImage( )
 {
     //Handle determining the current state, and reacting 
     //appropriately
     //Insert "RolloverButton refreshImage"
     if (isMouseInside)
     {
         if (isMouseDown)
         {
             setImage(downImage);
         }
         else
         {
             setImage(rolloverImage);
         }
     }
     else
     {
         setImage(upImage);
     }
}


This is fairly self explanatory. We check to see if the mouse is inside the button (recall that the Boolean isMouseInside is a data member from our base class, ImageButton) and then check to see if the mouse is down (isMouseDown is also from ImageButton). If the mouse is down and inside our button, we set the image to our down image. If the mouse is inside the button, but not down, we set the button image to the rollover image. If the mouse is not inside our button, we set the image to the upImage.

Here is a logic table for our rollover button:

  Mouse Inside Mouse Outside
Button Up
rolloverImage
upImage
Button Down
downImage
upImage


Now that we have our rollover behavior specified, it is time to define handleMousePressed( ).

Back to top

Step 4 - Implementing handleMousePressed( )

As we recall from ImageButton, when we get a MouseEvent of the type MousePressed, we set some internal flags and then call the abstract method handleMousePressed( ). Here is where we implement that abstract method to respond to mouse presses.

/**
 * Gets called when the mouse button is pressed on this button.
 */
 Protected void handleMousePressed( )
 {
     //Set the image to the appropriate image for a mouse press.
     //Insert "RolloverButton mousePressed"


Locate the RolloverButton mousePressed clipping in the RolloverButton folder and drag it directly below the last line of code shown above. Your code should now look like this:

/**
 * Gets called when the mouse button is pressed on this button.
 */
 Protected void handleMousePressed( )
 {
     //Set the image to the appropriate image for a mouse press.
     //Insert "RolloverButton mousePressed"
     setImage(downImage);
}


When the button is pressed, we set the current image to the downImage. Pretty easy! You are beginning to see how easy our underlying architecture is making the definition of this class. Adding extra functionality is quite straightforward.

Now it’s time for handleMouseReleased( ).

Back to top

Step 5 - Implementing handleMouseReleased( )

The handleMouseReleased( ) method is called when the mouse is released over the button. It takes two Boolean parameters; the first indicates whether the mouse is inside the button, and the second indicates whether the mouse was pressed inside the button before this method was called.

/**
 * Gets called when the mouse button is released on this button.
 * @param isMouseInside, if true, the mouse is located inside 
 * the button area, if false the mouse is outside the button.
 * @param wasMouseDown, if true the mouse was down inside this 
 * button before this method was called.
 */
 Protected void handleMouseRelease(Boolean isMouseInside, 
                                   Boolean wasMouseDown)
 {
     //Set the image to the appropriate image for a mouse 
     //release, and calls the super classes version to include 
     //inherited functionality.
     //Insert "RolloverButton mouseReleased"


Locate the RolloverButton mouseReleased clipping in the RolloverButton folder and drag it directly below the last line of code shown above. Your code should now look like this:

/**
 * Gets called when the mouse button is released on this button.
 * @param isMouseInside, if true, the mouse is located inside 
 * the button area, if false the mouse is outside the button.
 * @param wasMouseDown, if true the mouse was down inside this 
 * button before this method was called.
 */
 Protected void handleMouseRelease(Boolean isMouseInside, 
                                   Boolean wasMouseDown)
 {
     //Set the image to the appropriate image for a mouse 
     //release, and calls the super classes version to include 
     //inherited functionality.
     //Insert "RolloverButton mouseReleased"
     if (isMouseInside)
{ setImage(rolloverImage); } super.handleMouseRelease(isMouseInside);
}


If the user is inside the button we call setImage( ) with the rollover image. We then call our superclass handleMouseRelease( ) method to inherit default button release behavior. Regardless of the location of the mouse, we still want the superclass to execute its code.

Last but not least is the function handleRollover( ).

Back to top

Step 6 - Implementing handleRollover( )

The last method in this file is handleRollover( ). It is used to determine which image to used based on the state information passed into the routine. It looks very similar to refresh( ) but uses parameterized information instead of stored state information.

/**
 * Gets called when the mouse crosses into or out of the button 
 * area.
 * @param isMouseInside, is true if the mouse is in the button 
 * area, false if it is outside.
 * @param isMouseDown, is true if the mouse button is pressed, 
 * false if it is not.
 */
 Protected void handleRollover(Boolean isMouseInside, 
                               Boolean isMouseDown)
 {
       //Handle determining the current state, and reacting 
       //appropriately
       //Insert "RolloverButton handleRollover"


Locate the RolloverButton handleRollover clipping in the RolloverButton folder and drag it directly below the last line of code shown above. Your code should now look like this:

/**
 * Gets called when the mouse crosses into or out of the button 
 * area.
 * @param isMouseInside, is true if the mouse is in the button 
 * area, false if it is outside.
 * @param isMouseDown, is true if the mouse button is pressed, 
 * false if it is not.
 */
 Protected void handleRollover(Boolean isMouseInside, 
                               Boolean isMouseDown)
 {
       //Handle determining the current state, and reacting 
       //appropriately
       //Insert "RolloverButton handleRollover"
       if (isMouseInside)
       {
           if (isMouseDown)
           {
               setImage(downImage);
           }
           else
           {
               setImage(rolloverImage);
           }
       }
       else
       {
           setImage(upImage);
       }
}


This code should look quite familiar. If the mouse is inside the button and down, we see the image to downImage. If it is inside, but not down, we set the image to rolloverImage. If the mouse is not inside, set the image to upImage.

It happens that the logic for this method turns out to be the same for the refresh method, but this does not necessarily have to be the case. So in order to keep the generality which makes for robust classes, we have chosen not to combine these two methods.

Back to top

Summary

That completes the work we have to do on this file. As you can see, implementing the RolloverButton was far easier than ImageButton. That is because we are taking advantage of the basic behaviors of ImageButton and adding only the functionality necessary to give rollover behavior to our button. We implemented two methods that were declared as abstract from ImageButton, handleRollover( ), and handleMousePressed( ) as well as some additional methods for refreshing the state, and handling mouse released messages.

Now it’s time to complete the final tier of our button classes, ForwardButton, BackwardButton, and PlayPauseButton. Click here to return to the main tutorial document.