August 1, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Getting Back to Basics with GUIs

  • August 26, 2008
  • By Richard G. Baldwin
  • Send Email »
  • More Articles »

Java Programming Notes # 2600


Preface

General

Most of us have come to appreciate the use of relatively standardized GUI components, often based either on the AWT or on Swing. However, Swing and AWT components aren't always appropriate. For example, what if your clientele has absolutely no appreciation for standardized GUI components and may not even be able to read. What if your business is writing educational software for children in the five to ten year age range. You will probably agree that the standardized Swing GUI components are not particularly appropriate for children in that age range.

Or, your business may be writing game software for older children and adults. In that case, your will probably want the look and feel of the GUI to be based on the theme of the game. You certainly won't want it look like a word processing or spreadsheet program.

In those cases, you must get back to basics and either find an API of GUI components appropriate for the purpose, or develop the GUI components yourself.

That is what this tutorial lesson is all about. In this lesson, I will introduce you to the methodology for creating your own custom GUI components using Greenfoot by creating a pair of buttons used to turn the pages in a Greenfoot scenario.

Viewing tip

I recommend that you open another copy of this document in a separate browser window and use the following links to easily find and view the figures and listings while you are reading about them.

Figures

  • Figure 1. Buttons for turning the page.
  • Figure 2. Class diagram for scenario named ArrowButton02.
  • Figure 3. The six arrow images used in the scenario
  • Figure 4. Button states for each of three pages.
  • Figure 5. Description of the mouseMoved method.
  • Figure 6. Description of the mouseClicked method.

Listings

  • Listing 1. Beginning of the class named ArrowButton02.
  • Listing 2. Constructor for ArrowButton02.
  • Listing 3. Beginning of the class named ArrowButtonManager02.
  • Listing 4. Making background images available.
  • Listing 5. Beginning of the class named RightArrow.
  • Listing 6. The constructor for the RightArrow class.
  • Listing 7. Beginning of the act method.
  • Listing 8. Display red or green image on the button.
  • Listing 9. Responding to a click on the RightArrow button.
  • Listing 10. Source code for the class named ArrowButton02.
  • Listing 11. Source code for the class named ArrowButtonManager02.

Supplementary material

I recommend that you also study the other lessons in my extensive collection of online programming tutorials. You will find a consolidated index at www.DickBaldwin.com.

General background information

Sometimes its easy to forget that despite the sophistication of the JavaBeans event model and the components that are included in the Swing API, a GUI is nothing more than a bunch of images rendered on the screen along with the ability to detect various mouse and keyboard operations in and among those images. The following list identifies some of the custom GUI components that may be needed if your software needs a custom GUI.

  • Toggle switches
  • Text in various forms
  • Sliders
  • Scoreboards
  • Counters
  • Sound effects
  • Various kinds of buttons
  • Menus
  • Checkboxes
  • Radio buttons
  • Lists and combo boxes
  • Dialogs
  • Progress bars
  • Spinners
  • Tooltips

Obviously, we won't be able to cover all of these GUI components in this lesson, or even in this series of lessons. But, we'll do the best we can to cover as many as we can.

Preview

In this lesson, I will show you how to create and test a pair of buttons of the kind as shown on the left and right sides Figure 1. (Note that the two buttons at the bottom are part of the Greenfoot runtime environment that was used to develop and test these buttons.)

Figure 1. Buttons for turning the page.

An online version is available

I have published an online version of this scenario named ArrowButton02 at the Greenfoot gallery (see Resources). You can run the scenario online at that URL and I encourage you do so while you are reading this lesson.

Buttons for turning the page

The buttons on the left and right side of Figure 1 are the kind of buttons that you might see in a child's educational game that could be used to allow the child to "turn a page" or to progress back and forth through different scenes or worlds.

Mouse is touching the right button

In Figure 1, the mouse (which doesn't show in the screen shot) is touching the button on the right. That button has turned green indicating that it is okay to click the button to turn to the next page. If the last page was currently showing in the display area, the button would turn red (see Figure 4) instead of green and clicking the button would have no effect.

Will use Greenfoot

For a variety of reasons that I won't bore you with here, I have elected to use the Greenfoot IDE in this lesson. (See Getting Started with the Java IDE named Greenfoot in Resources.) If you haven't done so already, I recommend that you download and install the free Greenfoot IDE so that you can replicate the sample scenario that I will explain in this lesson. (Greenfoot projects are commonly referred to as scenarios. See Resources for a link to the Greenfoot download page.)

Discussion and sample code

Will explain in fragments

This scenario consists of two classes of my own design:

  • ArrowButton02
  • ArrowButtonManager02

The buttons shown on the left and right sides of Figure 1 were instantiated from static top-level classes encapsulated in the second class in the above list. An object of the first class in the above list places the buttons in the world shown in Figure 1 so that they can be exercised.

The class diagram for this scenario is shown in Figure 2.

Figure 2. Class diagram for scenario named ArrowButton02.

A brief discussion of Greenfoot

If this is your first exposure to Greenfoot, I suggest that you go back and read the lesson titled Getting Started with the Java IDE named Greenfoot (see Resources) before continuing with this lesson.

Briefly, however, the classes named World and Actor in Figure 2 are part of the IDE. To create and run a scenario in Greenfoot, the programmer extends the World class to create a specific world, and extends the Actor class to create one or more actors that perform in that world. There are many other possibilities as well, but that explanation should suffice for this scenario.

The class named ArrowButton02

The class named ArrowButton02, which begins in Listing 1, is relatively straightforward. This is the class that defines my custom world in which the actors perform.

Listing 1. Beginning of the class named ArrowButton02.

public class ArrowButton02 extends World{
  ArrowButtonManager02.RightArrow rightArrow;
  ArrowButtonManager02.LeftArrow leftArrow;

Listing 1 begins by declaring reference variables that will hold references to the two button objects shown on the right and the left in Figure 1. The classes from which the buttons will be instantiated are named RightArrow and LeftArrow. Each of those classes is a static top-level class that is encapsulated in the class named ArrowButtonManager02. Therefore, it is necessary to qualify the name of the class when it is referred to as shown by the boldface code in Listing 1.

Constructor for ArrowButton02

The constructor for this class, which is shown in Listing 2, does the following:

  • Sets the size and grid pattern of the world.
  • Instantiates the right and left arrow buttons shown in Figure 1.
  • Adds the two buttons to the world in specified locations.
  • Sets the initial background image for the world.

Listing 2. Constructor for ArrowButton02.

  public ArrowButton02(){//constructor
    super(450,450,1);
    rightArrow = new ArrowButtonManager02.RightArrow();
    leftArrow = new ArrowButtonManager02.LeftArrow();
    addObject(rightArrow,400,225);
    addObject(leftArrow,50,225);
    setBackground(new GreenfootImage("bathroom-tile.gif"));
  }//end constructor
}//end class

Except for the boldface super statement that sets the size and grid pattern of the world, the code in Listing 2 should be fairly obvious based on the method names and your prior knowledge of Java programming.

Review of the grid structure

A Greenfoot world consists of a uniform rectangular grid of square cells. The first two parameters to the super statement in Listing 2 specify the width and the height of the world respectively as measured in cells. The third parameter specifies the length of each side of each square cell in pixels. Because I specified that length as 1, each cell is a single pixel. Therefore, my world is a rectangular grid 450 pixels wide by 450 pixels high.

The origin of the grid is at the upper-left corner with positive horizontal dimensions extending to the right and positive vertical dimensions extending down.

Placement of the arrow images

Each arrow is a rectangular image 71 pixels wide and 53 pixels high with some portions being transparent. Greenfoot considers the geometric center of the rectangle to be the "handle" for the image. Thus, the first call to the addObject method in Listing 2 causes that image to be added to the world with the center of the image being placed at a coordinate value of 400x225 pixels. The second call to the addObject method causes the other image to be placed at a coordinate value of 50x225 pixels.

Setting the background

Finally, the last statement in the constructor uses an image file named "bathroom-tile.gif" to create an object of the GreenfootImage class and uses that object to establish the initial background for the world shown in Figure 1. Note that Actor images that are added to the world, such as the arrow images in this case, always appear in front of the background image and can move around in front of the background image leaving it intact.

Setting the z-order

Although it is not an issue in this scenario, it is possible for two actors to occupy the same space and the question then arises as to which actor object will be painted on top the other. The World class provides a method named setPaintOrder that lets you specify the painting order (z-order) of actors instantiated from different classes. However, the z-order of objects of the same class cannot be specified. It appears experimentally that objects are painted on top of objects of the same class that were added to the world earlier but I don't know if you can count on that always being the case.

Operational results

It would probably be a good idea to show you some operational results before getting into the technical details of the code that produces those results. (Once again, I recommend that you run the online version and observe its behavior while you are reading this material.)

The arrow images

Each arrow button actually consists of three images as shown by the six images in Figure 3. The three images in the top row of figure 3 were used for one of the buttons and the three images in the bottom row were used for the other button.

Figure 3. The six arrow images used in the scenario.

Note that the image files that are displayed in Figure 3 are in JPEG format. I used the free GNU Image Manipulation Program (see gimp in Resources) to convert the files to PNG format with all of the white areas converted to transparent areas before using them in the scenario. Had I not done that, the white rectangular border and the white arrows would have shown in Figure 1 producing a rather ugly result.

Image scaling

You may also have noticed that the images in Figure 3 are twice the size of the images in Figure 1. Later, I will show you where the size of each image is reduced by a factor of two in the Java code. Obviously, I could have done that in gimp, but I purposely left the images too large in order to illustrate how to scale images in Greenfoot.

Operational sequence

This scenario consists of three different pages or scenes. The user progresses from one page to the next by pressing one of the two arrows on the left and right sides of the individual images shown in the six frames in Figure 4.

Figure 4. Button states for each of three pages.

Arrow button on the three sequential pages

The three sequential pages in this scenario are shown from top to bottom in Figure 4. When the mouse is not touching a button, the button always displays the neutral image with the background image showing through. However, when the mouse touches a button, the image that is displayed turns either red or green to indicate whether it is possible to move forward or backward to another page.

The first page in the sequence

For example, the top-left frame in Figure 4 is displaying the first page in the sequence. Touching the left arrow on that page with the mouse causes the button to turn red indicating that clicking the button will be of no effect. However, touching the right button, as shown in the top-right frame in Figure 4, causes the button to turn green, indicating that clicking the button will turn the page to the center-left frame showing the brick wall.

The middle page in the sequence

The center-left and center-right frames in Figure 4 show the middle page of the three pages in the sequence. Both buttons turn green when touched by the mouse on this page because it is allowable to click the left-arrow button and turn back to the first page, or click the right-arrow button and turn forward to the third page.

The third and final page in the sequence

Finally, the red button in the bottom-right frame indicates that clicking that button will be of no effect because there are no more pages to turn to. However, the green button in the bottom-left frame indicates that it is allowable to click that button to turn the page back to the previous page in the sequence.

The class named ArrowButtonManager02

The purpose of this class, which begins in Listing 3, is to encapsulate a pair of static top-level classes from which a RightArrow object and a LeftArrow object can be instantiated.

Because objects of these two classes are intended to work in concert, and because they need to share some information, the two classes were encapsulated inside this class as static top-level classes.

This class also maintains the information that objects of the RightArrow and LeftArrow classes need to share.

Listing 3. Beginning of the class named ArrowButtonManager02.

public class ArrowButtonManager02 extends Actor{
  protected static int rightClickCnt = 0;
  protected final static int rightClickLim = 2;
  protected final static int leftClickLim = 2;
  protected static int leftClickCnt = leftClickLim;

Behavior of the variables and constants

When the scenario starts, the user is viewing the first page in the sequence by default. The variable named rightClickCnt in Listing 3 indicates which page the user is currently viewing. This variable has a value of zero when the user is viewing the first page in the sequence. It is incremented by one each time the user clicks a green right-arrow button and is decremented by one each time the user clicks a green left-arrow button.

Some redundancy
I just this moment realized that the constants named rightClickLim and leftClickLim are redundant. A single constant could have been used for both purposes since the number of pages is the same regardless of the direction in which the pages are being turned. I also could have gotten by having both arrows share a common click counter.

The constant named rightClickLim is used to specify the number of pages in the sequence. The value of this constant should be set to one less than the actual number of pages in the sequence.

The variable named leftClickCnt is incremented by one each time the user clicks a green left-arrow button and is decremented by one each time the user clicks a green right-arrow button. Therefore, this variable has a value of 2 when the first page is being viewed and has a value of 0 when the third page is being viewed.

The background images

As the user turns the pages by clicking the right and left-arrow buttons, the background image for the world is switched among the three images shown in Figure 4. Listing 4 instantiates three objects of type GreenfootImage from the three image files shown and stores references to those files in an array for access by the control code in later parts of the program.

Listing 4. Making background images available.

  protected final static GreenfootImage[] backgrounds = {
                   new GreenfootImage("bathroom-tile.gif"),
                   new GreenfootImage("brick.jpg"),
                   new GreenfootImage("burlap.jpg")};

  //Note that this class doesn't need a constructor or an
  // act method.

The image files

Unlike the arrow images required to create the buttons, the three image files in Listing 4 are in the standard Greenfoot distribution along with many other images. Therefore, they will be readily available to you if you choose to replicate this scenario. Although I didn't find any arrow images in the standard distribution, there are some smiley faces there that could easily be substituted for the arrow images that I used in my implementation of this scenario. Or, you can download the source code for my implementation of this scenario (see Resources) and extract the arrow images from the downloaded zip file.

No constructor or act method required

The class named ArrowButtonManager02 is simply a container for the static variables and constants described above and the static classes that I will explain shortly. Therefore, this class doesn't need either a constructor or an act method.

What is an act method?

If you have studied my earlier lessons on the Greenfoot IDE (see Resources), you will already know that every object instantiated from a class that extends the Actor class (see Figure 2) may override an inherited act method. The code that is written into the overridden version of the act method controls the behavior of the actor in the world.

Figure 1 shows a Reset button and a Pause button. When the scenario is loaded, the Pause button is a Run button. Clicking the Run button causes it to change into a Pause button. Clicking the Pause button causes it to change back into a Run button. Clicking the Reset button stops the execution and resets the state of the program to the state that it had immediately following compilation.

The Act button and the slider
When you export a scenario, you have the option of including or excluding the Act button and the speed slider. They were excluded when the scenario that produced Figure 1 was exported.

Not the actual IDE

The screen shot image shown in Figure 1 is not a screen shot of the actual IDE. (The IDE is too wide to fit in this narrow publication format without making it smaller and reducing the legibility of the text.) Rather, Figure 1 shows a screen shot of an exported executable version of the scenario.

Controlling the act order
You can call the World method named setActOrder to control the order in which the act methods are executed. Act order is specified by class: objects of one class will always act before objects of some other class. The order of objects of the same class cannot be specified.

The Act button and the speed slider

In addition to the Run/Pause button, the IDE also contains an Act button and an animation speed slider. Each time you click the Act button, the act method belonging to every Actor object is executed once. This makes it possible for you to execute the animation one step at a time. If you click the Run button, the act method belonging to every actor is executed repeatedly. Thus, the Run button triggers an animation loop, the speed of which can be controlled either through program code or manually using the speed slider.

The class named RightArrow

The class named ArrowButtonManager02 extends the Actor class (see Listing 3) and encapsulates two static top-level classes named RightArrow and LeftArrow. These two classes are very similar, differing only to the extent necessary to accommodate the fact that an object of one is used to turn the pages forward and the other is used to turn the pages backwards.

The class named RightArrow is used to instantiate a button object of the type shown on the right side of the image in Figure 1. While a button of this type might be useful for a number of purposes, its primary use in this scenario is to "turn the pages" of a multi-page scenario in a forward direction as described earlier. This button is similar to one that you might see in a children's educational game, or perhaps in an online picture gallery.

Three images are used

As I described earlier, the bottom three images in Figure 3 are used to represent the button in its three different states. All three images consist of a filled blue oval with a cutout of an arrow pointing to the right. The NEUTRAL version of the button in the bottom left in Figure 3 has a transparent cutout. The "STOP" version has the cutout colored red and the "GO" version has the cutout colored green. All three versions consist of the oval in a rectangle, but the area outside of the oval is transparent so that the background image shows through the edges of the rectangle as shown in Figure 4.

Behavior of the buttons

The neutral version of the button is displayed whenever the mouse is not touching the button. The green version is displayed when the user touches the button with the mouse and there are more pages to be explored in the direction indicated by the arrow. The red version is displayed when the user touches the button with the mouse and there are no more pages to be explored in that direction.

Clicking a green RightArrow button with the mouse causes the next page to the right to be displayed. Clicking a red RightArrow button has no effect at all.

As explained earlier, variables and constants in the containing class named ArrowButtonManager02 are used to track the number of the page currently being viewed, along with the limit on the number of total pages that may be viewed.

Also, as explained earlier, an array in the superclass is used to maintain references to a set of GreenfootImage objects that are used to set the background for each page.

In the ideal case, only the data in the containing class needs to be changed to use this button with worlds having different numbers of pages and different background images on those pages.

An object of this class is intended to be used in conjunction with an object of a companion class named LeftArrow. For that reason, this class and the companion class were encapsulated inside the superclass as static top-level classes.

Beginning of the class named RightArrow

The class named RightArrow begins in Listing 5.

Listing 5. Beginning of the class named RightArrow.

public static class RightArrow 
                              extends ArrowButtonManager02{
  GreenfootImage goRightArrow;
  GreenfootImage stopRightArrow;
  GreenfootImage neutralRightArrow;

Listing 5 declares three variables of type GreenfootImage that will be used to store references to three objects containing the png versions of the images shown in the bottom row in Figure 3.

The constructor for the RightArrow class

The constructor for the RightArrow class is shown in Listing 6.

Listing 6. The constructor for the RightArrow class.

  public RightArrow(){//constructor
    //Construct and scale the three GreenfootImage objects
    // that are used to represent the button in the world.
    goRightArrow = new GreenfootImage("gorightarrow.png");
    goRightArrow.scale(goRightArrow.getWidth()/2,
                       goRightArrow.getHeight()/2);
    stopRightArrow = 
                  new GreenfootImage("stoprightarrow.png");
    stopRightArrow.scale(stopRightArrow.getWidth()/2,
                         stopRightArrow.getHeight()/2);
    neutralRightArrow = 
               new GreenfootImage("neutralrightarrow.png");
    neutralRightArrow.scale(neutralRightArrow.getWidth()/2,
                          neutralRightArrow.getHeight()/2);
                          
    //Set the default image on the button.
    setImage(neutralRightArrow);
  }//end constructor

The constructor begins by instantiating GreenfootImage objects for each of the three png files containing the arrows shown in the bottom row of Figure 3 and then scaling those images to one-half their original size. Note that the width and the height of an image must be scaled independently of one another.

The last statement in the constructor sets the default image for the button to be the same as the bottom left image in Figure 3 where all of the white area in Figure 3 is transparent allowing the background image to show through.

Beginning of the act method

The beginning of the act method for the RightArrow class is shown in Listing 7.

Listing 7. Beginning of the act method.

  public void act(){
    if(Greenfoot.mouseMoved(getWorld())){
      setImage(neutralRightArrow);
    }//end if

Greenfoot provides a mouse-event handling methodology that is somewhat simplified relative to that which you experience when programming with the JavaBeans event model. (Note, however, that you are not prevented from using the JavaBeans event model if you choose to do so.)

Listing 7 uses the static method named mouseMoved of the class named Greenfoot to return the button to the state that displays the neutral image when the mouse is moved from touching the button to touching the world.

Description of the mouseMoved method

A partial description of the mouseMoved method is provided in Figure 5.

Figure 5. Description of the mouseMoved method.

public static boolean mouseMoved(java.lang.Object obj)

Returns true if the mouse has been moved on the given object.

The mouse is considered to be moved on an object if the mouse pointer is above that object.

If the parameter is an Actor the method will only return true if the move is on the given actor. If there are several actors at the same place, only the top-most actor will receive the move.

If the parameter is a World then true will be returned if the move was on the world background.

If the parameter is null, then true will be returned for any move, independent of the target under the move location.

Calling the getWorld method

In this case, the return value from the getWorld method was passed as a parameter to the mouseMoved method. (According to the Greenfoot documentation, the getWorld method returns a reference to the world that the button actor lives in.)

Keep in mind that the act method is executed repetitively and the call to the mouseMoved method is made each time the act method is executed. Therefore, if the mouse was more recently moved on the world background than on the button actor, the setImage method in Listing 7 will be executed causing the neutral image to be displayed on the button.

Display red or green image on the button

If the mouse was most recently moved on the RightArrow object, either the red or green image needs to be displayed on the button. The code in Listing 8 determines which page is currently being viewed and uses that information to select either the red image or the green image and to display that image on the button.

Listing 8. Display red or green image on the button.

    if(Greenfoot.mouseMoved(this) &&
                          (rightClickCnt < rightClickLim)){
      //Set the image to the green button
      setImage(goRightArrow);
    }else{
      if(Greenfoot.mouseMoved(this) &&
                         (rightClickCnt >= rightClickLim)){
        //Set the image to the red button.
        setImage(stopRightArrow);
      }//end if
    }//end else

The mouseClicked method

A partial description of the mouseClicked method of the Greenfoot class is provided in Figure 6.

Figure 6. Description of the mouseClicked method.

public static boolean mouseClicked(java.lang.Object obj)

Returns true if the mouse has been clicked (pressed and released) on the given object.

If the parameter is an Actor the method will only return true if the mouse has been clicked on the given actor. If there are several actors at the same place, only the top most actor will receive the click.

If the parameter is a World then true will be returned if the mouse was clicked on the world background.

If the parameter is null, then true will be returned for any click, independent of the target clicked on.

Other code may be required
In a more elaborate scenario, it may be necessary to perform other operations in addition to simply changing the background image when the button is clicked.

Responding to a click on the RightArrow button

When the RightArrow button is clicked and the user is viewing the first or second of the three pages in the scenario (the button turns green), the program should turn to the next page by displaying the background image that is appropriate for that page. (See the three background images in Figure 4.)

If the viewer is already viewing the third page when the button is clicked (the button turns red), the click should simply be ignored. These operations are accomplished by the code in Listing 9.

Listing 9. Responding to a click on the RightArrow button.

    if(Greenfoot.mouseClicked(this) &&
                          (rightClickCnt < rightClickLim)){
      rightClickCnt++;
      leftClickCnt--;
      //Add code here to completely populate the new scene
      // in addition to changing the background.
      getWorld().setBackground(backgrounds[rightClickCnt]);
      
      //Cause the arrow to turn red at the limit.
      if(rightClickCnt >= backgrounds.length - 1){
        setImage(stopRightArrow);
      }//end if
      
    }//end if
  }//end act
}//end static top-level class named RightArrow

Update the state variables

In addition, if the page is turned, the variable named rightClickCnt is incremented and the variable named leftClickCnt is decremented as described earlier.

End of the act method and end of the RightArrow class

Listing 9 also signals the end of the method named act and the end of the class named RightArrow.

The class named LeftArrow

A static top-level class named LeftArrow is also encapsulated in the class named ArrowButtonManager02. An object of this class is used for the arrow on the left side of Figure 1. As mentioned earlier, this class is very similar to the RightArrow class, differing only to the extent necessary to accommodate the fact that an object of one class is used to turn the pages forward and an object of the other class is used to turn the pages backwards. Therefore, an explanation of the LeftArrow class shouldn't be needed.

An online version of the scenario

I have published an online version of this scenario named ArrowButton02 at the Greenfoot gallery (see Resources). You can run the scenario online at that URL and I encourage you do so while you are reading this lesson.

You can also download the source code for the scenario, including both the png and the jpg versions of the six image files used for the buttons.

Run the scenario

I encourage you to either download my source code from the Greenfoot gallery, or copy the code from Listing 10 and Listing 11 and create your own version of the scenario. Experiment with the code, making changes, and observing the results of your changes. Make certain that you can explain why your changes behave as they do.

Summary

In this lesson, I introduced you to the methodology for creating your own custom GUI components using Greenfoot by creating a pair of buttons used to turn the pages in a Greenfoot scenario.

What's next?

Future lessons in this series will develop more complex GUI components using more complex Greenfoot scenarios.

Resources

Complete program listings

Complete listings of the source code for the scenario discussed in this lesson are shown in Listing 10 and Listing 11 below.

Listing 10. Source code for the class named ArrowButton02.

import greenfoot.*;
/**
 * This is the world class for a scenario that is designed
 * to illustrate how to use custom arrow buttons to scroll
 * the background of the world right and left through
 * three different scenes.
 * 
 * This scenario illustrates the kind of behavior that you
 * might see in a child's educational game where the player
 * is allowed to progress back and forth through different
 * scenes or worlds.
 * 
 * @author Dick Baldwin 
 * @version July 6, 2008
 */
public class ArrowButton02 extends World{
  ArrowButtonManager02.RightArrow rightArrow;
  ArrowButtonManager02.LeftArrow leftArrow;

  public ArrowButton02(){//constructor
    //Set the size of the world, populate the world with
    // two custom buttons, and set the initial background
    // for the world. Note that the classes from which the
    // button objects are instantiated are static top-level
    // classes of the class named ArrowButtonManager02.
    super(450,450,1);
    rightArrow = new ArrowButtonManager02.RightArrow();
    leftArrow = new ArrowButtonManager02.LeftArrow();
    addObject(rightArrow,400,225);
    addObject(leftArrow,50,225);
    setBackground(new GreenfootImage("bathroom-tile.gif"));
  }//end constructor
}//end class

 

Listing 11. Source code for the class named ArrowButtonManager02.

import greenfoot.*;

/**
 * The purpose of this class is to encapsulate a pair of
 * static top-level classes from which a RightArrow object
 * and a LeftArrow object can be instantiated.  Because
 * objects of these two classes are intended to work in
 * concert, and because they need to share some 
 * information, the two classes were encapsulated inside
 * this class as static top-level classes.
 * 
 * This class also maintains the information that objects
 * of the RightArrow and LeftArrow classes need to share.
 * 
 * @author Dick Baldwin 
 * @version July 6, 2008
 */
public class ArrowButtonManager02 extends Actor{
  //The following variables are used to keep track of how
  // many times the user has scrolled the scene to the
  // right and to the left. They are also used to determine
  // when the user has scrolled to the limit in either 
  // direction.  Set the limit values to one less than the
  // number of scenes in the world.
  protected static int rightClickCnt = 0;
  protected final static int rightClickLim = 2;
  protected final static int leftClickLim = 2;
  protected static int leftClickCnt = leftClickLim;

  //The following array stores references to GreenfootImage
  // objects that are used to set the background of the
  // world each time the user clicks one of the buttons.
  protected final static GreenfootImage[] backgrounds = {
                   new GreenfootImage("bathroom-tile.gif"),
                   new GreenfootImage("brick.jpg"),
                   new GreenfootImage("burlap.jpg")};

  //Note that this class doesn't need a constructor or an
  // act method.

  //Here is the beginning of a pair of static top-level
  // classes.

//=======================================================//
/**
 * This is a class from which a "right arrow" button can
 * be constructed.  While the button may be useful for a
 * variety of purposes, the primary intended purpose is to
 * scroll a world right and left through several different 
 * background scenes, much as you might see in a children's
 * educational game where the child can progress forward 
 * and backwards through a sequence of different "worlds."
 * 
 * Three different images are used to represent the button.
 * All three images consist of a filled blue oval with a
 * cutout of an arrow pointing to the right.  The NEUTRAL
 * version of the button has a transparent cutout.  The
 * "GO" version has the cutout colored green.  The "STOP"
 * version has the cutout colored red.
 * 
 * The neutral version is displayed whenever the mouse is
 * not over the button.  The green version is displayed 
 * when the user points to the button with the mouse and
 * there are more worlds to the right for the user to
 * explore.  The red version is displayed when the user
 * points to the button with the mouse and there are no 
 * more worlds to the right to be explored.
 * 
 * Clicking a green button with the mouse causes the next
 * scene to the right to be displayed in the world.  
 * Clicking a red button has no effect at all.
 * 
 * Variables and constants in the containing class named
 * ArrowButtonManager02 are used to track the number
 * of times the user has scrolled to the right along with
 * the limit on the number of allowable scrolls to the 
 * right
 * 
 * An array in the superclass is used to maintain 
 * references to a set of GreenfootImage objects that are
 * used to set the background for each of the scenes.
 * 
 * In the ideal case, only the data in the containing class
 * needs to be changed to use this button with worlds 
 * having different numbers of background scenes and 
 * different actual background images.
 * 
 * An object of this class is intended to be used in
 * conjunction with an object of a companion class named
 * LeftArrow.  For that reason, this class and the 
 * companion class were encapsulated inside the superclass
 * as static top-level classes.
 * 
 * @author Dick Baldwin 
 * @version July 6, 2008
 */
public static class RightArrow 
                              extends ArrowButtonManager02{
  GreenfootImage goRightArrow;
  GreenfootImage stopRightArrow;
  GreenfootImage neutralRightArrow;

  public RightArrow(){//constructor
    //Construct and scale the three GreenfootImage objects
    // that are used to represent the button in the world.
    goRightArrow = new GreenfootImage("gorightarrow.png");
    goRightArrow.scale(goRightArrow.getWidth()/2,
                       goRightArrow.getHeight()/2);
    stopRightArrow = 
                  new GreenfootImage("stoprightarrow.png");
    stopRightArrow.scale(stopRightArrow.getWidth()/2,
                         stopRightArrow.getHeight()/2);
    neutralRightArrow = 
               new GreenfootImage("neutralrightarrow.png");
    neutralRightArrow.scale(neutralRightArrow.getWidth()/2,
                          neutralRightArrow.getHeight()/2);
                          
    //Set the default image on the button.
    setImage(neutralRightArrow);
  }//end constructor

  public void act(){
    //Cause the image representing the button to return to
    // the neutral version when the mouse is not over the
    // button.
    if(Greenfoot.mouseMoved(getWorld())){
      setImage(neutralRightArrow);
    }//end if

    //Cause the cutout arrow portion of the button to
    // change from transparent to either red or green
    // depending on whether the user has already scrolled
    // to the right as far as is allowed whenever the
    // user points the mouse at the button.
    if(Greenfoot.mouseMoved(this) &&
                          (rightClickCnt < rightClickLim)){
      //Set the image to the green button
      setImage(goRightArrow);
    }else{
      if(Greenfoot.mouseMoved(this) &&
                         (rightClickCnt >= rightClickLim)){
        //Set the image to the red button.
        setImage(stopRightArrow);
      }//end if
    }//end else

    //When the button is clicked and the user hasn't 
    // already scrolled as far to the right as is allowed
    // (meaning the button will turn green), increment and 
    // decrement the counters that are maintained in the 
    // superclass named ArrowButtonManager02. Ignore the
    // click if the user has already scrolled as far to the
    // right as is allowed.
    //Also use the new value of the counter to set the
    // background of the world to the correct background
    // image.
    if(Greenfoot.mouseClicked(this) &&
                          (rightClickCnt < rightClickLim)){
      rightClickCnt++;
      leftClickCnt--;
      //Add code here to completely populate the new scene
      // in addition to changing the background.
      getWorld().setBackground(backgrounds[rightClickCnt]);

      //Cause the arrow to turn red at the limit.
      if(rightClickCnt >= backgrounds.length - 1){
        setImage(stopRightArrow);
      }//end if

    }//end if
  }//end act
}//end static top-level class named RightArrow
//=======================================================//

/**
 * See the description of the class named RightArrow. This
 * class is similar to that one except that the arrow
 * button instantiated from this class points to the left
 * instead of to the right.
 * 
 * @author Dick Baldwin 
 * @version July 6, 2008
 */
public static class LeftArrow extends ArrowButtonManager02{
  GreenfootImage goLeftArrow;
  GreenfootImage stopLeftArrow;
  GreenfootImage neutralLeftArrow;

  public LeftArrow(){//constructor
    goLeftArrow = new GreenfootImage("goleftarrow.png");
    goLeftArrow.scale(goLeftArrow.getWidth()/2,
                      goLeftArrow.getHeight()/2);
    stopLeftArrow = 
                   new GreenfootImage("stopleftarrow.png");
    stopLeftArrow.scale(stopLeftArrow.getWidth()/2,
                        stopLeftArrow.getHeight()/2);
    neutralLeftArrow = 
                new GreenfootImage("neutralleftarrow.png");
    neutralLeftArrow.scale(neutralLeftArrow.getWidth()/2,
                           neutralLeftArrow.getHeight()/2);

    setImage(neutralLeftArrow);
  }//end constructor

  public void act(){
    if(Greenfoot.mouseMoved(getWorld())){
      setImage(neutralLeftArrow);
    }//end if

    if(Greenfoot.mouseMoved(this) &&
                            (leftClickCnt < leftClickLim)){
      setImage(goLeftArrow);
    }else{
      if(Greenfoot.mouseMoved(this) &&
                           (leftClickCnt >= leftClickLim)){
        setImage(stopLeftArrow);
      }//end if
    }//end else

    if(Greenfoot.mouseClicked(this) &&
                            (leftClickCnt < leftClickLim)){
      leftClickCnt++;
      rightClickCnt--;
      getWorld().setBackground(backgrounds[rightClickCnt]);

      //Cause the arrow to turn red at the limit.
      if(leftClickCnt >= backgrounds.length - 1){
        setImage(stopLeftArrow);
      }//end if

    }//end if
  }//end act
}//end static top-level class named LeftArrow
//=======================================================//

}//end class ArrowButtonManager02

 


Copyright

Copyright 2008, Richard G. Baldwin. Reproduction in whole or in part in any form or medium without express written permission from Richard Baldwin is prohibited.

About the author

Richard Baldwin is a college professor (at Austin Community College in Austin, TX) and private consultant whose primary focus is a combination of Java, C#, and XML. In addition to the many platform and/or language independent benefits of Java and C# applications, he believes that a combination of Java, C#, and XML will become the primary driving force in the delivery of structured information on the Web.

Richard has participated in numerous consulting projects and he frequently provides onsite training at the high-tech companies located in and around Austin, Texas. He is the author of Baldwin's Programming Tutorials, which have gained a worldwide following among experienced and aspiring programmers. He has also published articles in JavaPro magazine.

In addition to his programming expertise, Richard has many years of practical experience in Digital Signal Processing (DSP). His first job after he earned his Bachelor's degree was doing DSP in the Seismic Research Department of Texas Instruments. (TI is still a world leader in DSP.) In the following years, he applied his programming and DSP expertise to other interesting areas including sonar and underwater acoustics.

Richard holds an MSEE degree from Southern Methodist University and has many years of experience in the application of computer technology to real-world problems.

Baldwin@DickBaldwin.com






Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel