Chapter 43

User Input and Interactivity with Java

by Jerry Ablan


CONTENTS

User interaction with your programs is by far the most important aspect of creating Java applets and applications. If your interface is bad, people will not want to use your program. Come up with a unique interface, however, and you could have the next "killer" application. But, keep in mind, creating those awesome interfaces requires you to start with some foundation.

This chapter will focus specifically on that Java foundation. Learning about all the different tools at your disposal will allow you to build cool interfaces and keep your users happy.

Using the Abstract Windowing Toolkit

The Abstract Windowing Toolkit (AWT) is Java's components package. This package contains all of the programming tools you need to interact with the user.

The AWT contains a number of familiar user interface elements. Figure 43.1 shows a Java applet with a sample of some of the components of the AWT.

Figure 43.1 : The AWT features a number of familiar components.

Figure 43.2 shows you a portion of the AWT's inheritance hierarchy.

Figure 43.2 : The AWT inherits all its user interface components from Component.

AWT Components

Components are the building blocks of the AWT. The end-user interacts directly with these components. The components provided by the AWT are

Containers

You need more than just components to create a good user interface. The components need to be organized into manageable groups. Containers hold, or contain, components. To use a component, it must be placed within a container. The container classes defined in the AWT are

TIP
Containers not only contain components, they are also components themselves. This means that a container can be placed within other containers.

Laying Out Your User Interface

Even though you have containers as a place to neatly store your UI components, you still need a way to organize the components within a container. That's where the layout managers come in. Each container is given a layout manager that decides where each component should be displayed. The layout managers in the AWT are

NOTE
As you know, Java is an object-oriented language, and the Java classes take advantage of this completely. Because of that, some of the methods discussed in this and the following sections may not be in the classes being discussed, but rather are inherited from a base class.

Buttons

Buttons are a simple mechanism, but they are one of the workhorses of any graphical interface. You find buttons on toolbars, dialog boxes, windows, and even in other components such as scroll bars.

Creating Buttons

The only thing you have to decide when creating a button is whether or not you want the button to be labeled. There are no other options for buttons.

To create an unlabeled button, use the following syntax:

Button myButton = new Button();

Creating a labeled button is an equally simple task

Button myButton = new Button( "Press Me" );

Once you have created a button, you need to add it to a container. Since your applet is already a container, you can add a button directly to your container or layout

Button myButton = new Button( "Press Me" );

add( myButton );

To change the label of your button, use setLabel

myButton.setLabel( "Pull Me!" );

To get the label for your button, use getLabel

String buttonLabel = myButton.getLabel();

NOTE
You may notice the lack of "image buttons"; that is, buttons that contain an image instead of text. These types of buttons are almost a necessity for creating toolbars. Unfortunately, they are not supported in the AWT. Hopefully, these will show up in a future version of the AWT, but for now, if you want an image button, you'll have to implement it yourself.

Using Buttons

All the components within the AWT have an action method that is called when certain events occur involving a component. In the case of the button, action is called when the button is pressed. The action method is similar to some of the event-handling methods you may have come across already, like keyDown or mouseDown.

NOTE
When an action takes place in a component, the AWT calls the handleEvent method in that component with an event type of ACTION_EVENT. The default handleEvent method calls the action method in the component. By default, the component doesn't handle the action, which causes the event to be passed to the handleEvent method in the parent container where, by default, the parent's action method is called. This continues until the action is either handled or ignored by the top-most container. A component signals that it has handled the event by returning a value of true from the event-handling method (action, handleEvent, or whatever). A return value of false from an event-handling method indicates that the component has not handled the event and the event should be passed up to the parent.

The format of the action method in all components is

public boolean action( Event event, Object objInfo )

where event is the Event that has occurred in the component, and objInfo provides additional information about the event. The objInfo parameter differs from event to event.

For buttons, objInfo is the label of the button that has been pressed. The event parameter contains other information specific to the action, such as the component where the action occurred (event.target) and the time the action occurred (event.when).

CAUTION
When checking to see if an event was generated by one of your components, be wary of the instanceof operator. If you have more than one of the same types of components in the same container, you may get a false positive response. That is to say, if you have two Buttons in your program, you'll get two positive instanceof operators.
So, be sure to store the instance of the components themselves and use the equality operator, ==, to check for equality.

Now that you know how to create a button and check for an action, you can create a button applet. A very simple example is an applet with buttons that change their background color. One way to do this is by putting the name of the color in the button label. Then in the action method, you look at the label of the button that was clicked and set the applet's background color based on that label. For example, the button to turn the background blue could be labeled "Blue." The action method would set the background to blue if the button's label was blue. The applet in Listing 43.1 demonstrates how to do this.


Listing 43.1  Button1Applet.java  Source Code
// Example 43.1 - Button1Applet
//
//  This applet creates two buttons named "Red" and "Blue".  When a
//  button is pressed, the background color of the applet is set to
//  the color named by that button's label.
//

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

public class
Button1Applet
extends Applet
{
     public void
     init()
     {
     add( new Button( "Red" ) );
     add( new Button( "Blue" ) );
     }

     public boolean
     action( Event evt, Object objInfo )
     {
     // Check to make sure this is a button action; if not,
// return false to indicate that the event has not been handled.
     if ( evt.target instanceof Button )
     {
     String butLab = ( String )objInfo;

     // Was the red one pushed?
     if ( butLab.equals( "Red" ) )
     setBackground( Color.red );
     else
     {
     // How about the blue?
     if ( butLab.equals( "Blue" ) )
     setBackground( Color.blue );
     else
     // We didn't handle it...
     return( false );
     }

     // Make our change visible...
     repaint();

     return( true );
     }

     // Nothing to do!?
     return( false );
     }
}

You will learn a better way to design this applet in the "Object-Oriented Thinking" section, later in this chapter.

Figure 43.3 shows you Button1Applet in operation.

Figure 43.3 : The buttons in Button1Applet change the applet's background color.

Labels

Labels are the simplest of the AWT components. They are text strings that are used only for decoration. Since they are "display-only," labels generate no events.

Creating Labels

There are three different ways to create a label. The simplest is to create an empty label, such as

Label myLabel = new Label();

Of course, an empty label isn't going to do you much good since there is nothing to see. A more useful label is one with some text, as in

Label myLabel = new Label( "This is a label" );

Labels can be left-justified, right-justified, or centered. The variables Label.LEFT, Label.RIGHT, and Label.CENTER can be used to set the alignment of a label. Here is an example of how to create a right-justified label

Label myLabel = new Label( "This is a right-justified label",
    Label.RIGHT );

You can change the text of a label with setText

myLabel.setText( "This is the new label text" );

You can also get the text of a label with getText

String labelText = myLabel.getText();

You can change the alignment of a label with setAlignment

myLabel.setAlignment( Label.CENTER );

You can also get the alignment of a label with getAlignment

int labelAlignment = myLabel.getAlignment();

Figure 43.4 shows you a sample label.

Figure 43.4 : Labels are simply text strings.

Check Boxes and Radio Buttons

Check boxes are similar to buttons except that they are used as "yes-no" or "on-off" switches. Every time you click a check box it changes from "off" to "on" or from "on" to "off." A close cousin to the check box is the radio button. Radio buttons are also "on-off" switches, but they are arranged in special, mutually-exclusive groups where only one button in the group can be on at a time. Imagine what a radio would sound like if you could have more than one station on at a time!

Creating Check Boxes

A check box has two parts-a label and a state. The label is the text that is displayed next to the check box itself, while the state is a Boolean variable that indicates whether or not the box is checked. By default, the state of a check box is false, or "off."

To create a check box with no label, use the following syntax:

Checkbox myCheckbox = new Checkbox();

To create a check box with a label, use the following syntax:

Checkbox myCheckbox = new Checkbox( "Check me if you like Java" );

You can also create a check box while setting its state by using the following syntax:

Checkbox myCheckbox = new Checkbox( "Check me if you like Java", null,
    true );

The null in the preceding code fragment refers to the CheckboxGroup to which the check box belongs. You use CheckboxGroup to create a set of radio buttons; for a normal check box, the CheckboxGroup will be null.

You use the following code to see if a check box has been checked with getState:

if ( myCheckbox.getState() )
{
     // The box has been checked
}
else
{
     // The box has not been checked
}

Creating Radio Buttons

Radio buttons are just a special case of check boxes. There is no RadioButton class. Instead, you create a set of radio buttons by creating check boxes and putting them in the same check box group. The constructor for CheckboxGroup takes no arguments and appears as

CheckboxGroup myCheckboxGroup = new CheckboxGroup()

Once you have created the group, you create the check boxes that will belong to this group by passing the group to the constructor. You can then add them to your layout as follows:

add( new Checkbox( "Favorite language is Java", myCheckboxGroup,
    true ) );
add( new Checkbox( "Favorite language is Visual Cobol", myCheckboxGroup,
    false ) );
add( new Checkbox( "Favorite language is Backtalk", myCheckboxGroup,
    false ) );

NOTE
When you add check boxes to a check box group, the last check box that is added as true is the box that is checked when the group appears.

You can find out which radio button is selected either by calling getState on each check box, or by calling getCurrent on the CheckboxGroup. The getCurrent method returns the check box that is currently selected.

Using Check Boxes and Radio Buttons

The action method for a check box or a radio button is called whenever it is clicked. The whichAction parameter of the action method will be an instance of a Boolean class that is true if the check box was clicked on, or false if the check box was clicked off. If you create an action method for a radio button, you should not rely on the whichAction parameter to contain the correct value. If a radio button is clicked when it is already on, the whichAction contains a false value even though the button is still on. You are safer just using the getState method to check the state of the radio button or the check box. You can also use the getLabel method to determine which check box has been checked. The following code fragment shows an action method that responds to a box being checked and retrieves the current state of the box:

public boolean
action( Event evt, Object whichAction )
{
     if ( evt.target instanceof Checkbox )
     {
     Checkbox  currentCheckbox = ( Checkbox )evt.target;
     boolean   checkboxState = currentCheckbox.getState();

     if ( currentCheckbox.getLabel().equals( "Check me if you like Java"
         ) )
{
     if ( checkboxState )
     {
     // Handle checkbox being on in here...
}
     else
     {
     // Handle checkbox being off in here...
}

     // We handled it!
     return( true );
     }

     // We did nothing...
     return( false );
     }
}

NOTE
Whenever you write an event-handling method like handleEvent or action, you should return true only in the cases where you actually handle the event. Notice that the example action method for check boxes only returns true in the case where the event is a check box event. It returns false in all other cases. You may also have cases where you handle an event but you still want to allow other classes to handle the same event. In those cases, you also return false.

Figure 43.5 shows you two check boxes and a group of three radio buttons.

Figure 43.5 : Check boxes are squared boxes with checks in them. Radio buttons are rounded and are marked with dots.

Choices

The Choice class provides a popup menu of text string choices. The current choice is displayed as the menu title. These are drop-down list boxes and combo boxes in other GUI platforms.

Creating Choices

To create a choice popup menu, you must first create an instance of the Choice class. Since there are no options for the choice constructor, the creation of a Choice should always look something like this

Choice myChoice = new Choice();

Once you have created the choice, you can add the following string items to it by using the addItem method.

myChoice.addItem( "Moe" );
myChoice.addItem( "Larry" );
myChoice.addItem( "Curly" );

You may also change which item is currently selected either by name or by index. If you want Curly to be selected, for instance, you can select him by name

myChoice.select( "Curly" );

You can also select Curly by his position in the list. Since he was added third, and the choices are numbered starting at 0, Moe is 0, Larry is 1, and Curly is 2 he can be selected by using

myChoice.select( 2 );

TIP
If you want your items to be in a particular order, you must place them into the Choice in that order. Java provides no sort capability for the Choice or List components.

The getSelectedIndex method returns the position of the selected item. Again, if Curly is selected, getSelectedIndex returns 2. Similarly, the getSelectedItem method returns the string name of the selected item, so if Curly is selected, getSelectedItem returns "Curly."

If you have an index value for an item and you want to find out the name of the item at that index, you can use getItem as follows:

String selectedItem = myChoice.getItem( 2 );

Figure 43.6 shows a choice in its usual form, while Figure 43.7 shows a choice with its menu of choices dropped down.

Figure 43.6 : The choice box displays its current selection.

Figure 43.7 : The button on the right of a choice pops up a menu of the possible choices.

Using Choices

The action method for a Choice is called whenever a selection is made, even if it is the same selection. The whatAction parameter contains the name of the selected item. The following code fragment gives an example action method for a Choice where the selection is stored in a String variable within the applet:

String     currentStooge;

public boolean
action( Event event, Object whatAction )
{
     // Check to make sure this is a choice object, if not
     //      indicate that the event has not been handled.
     if ( event.target instanceof Choice )
     {
     // See if this is an action for myChoice
     if ( ( Choice )event.target == myChoice )
     {
     currentStooge = ( String )whatAction;
     return( true );
     }
     }

     // Unhandled event...
     return( false );
}

Lists

The List class allows you to create a scrolling list of values that may be selected either individually or several at a time.

Creating Lists

You have two options when creating a List. The default constructor for the List class allows you to create a List that does not allow multiple selections by using

List myList = new List();

You may also set the number of list entries that are visible in the list window at any one time, and whether or not to allow multiple selections. The following code fragment creates a list with 10 visible entries and multiple selections turned on:

List myList = new List( 10, true );

Once you have created the list, you can add new entries to it with the addItem method

myList.addItem( "Moe" );
myList.addItem( "Larry" );
myList.addItem( "Curly" );

You may also add an item at a specific position in the list. The list positions are numbered from 0, so if you add an item at position 0, it goes to the front of the list. If you try to add an item at position -1, or try to add an item at a position higher than the number of positions, the item will be added to the end of the list. The following code adds "Shemp" to the beginning of the list, and "Curly Joe" to the end:

myList.addItem( "Shemp", 0 );        // Add Shemp at position 0
myList.addItem( "Curly Joe", -1 );   // Add Curly Joe to the end

TIP
If you want your items to be in a particular order, you must place them into the List in that order. Java provides no sort capability for the Choice or List components.

List Features

The List class provides a number of different methods for changing the contents of the list. The replaceItem method will replace an item at a given position with a new item, such as

myList.replaceItem( "Dr. Howard", 0 );
         // Replace the first item in the list with "Dr. Howard"

You can delete an item in the list with deleteItem as follows:

myList.deleteItem( 1 );
         // Delete the second item in the list (0 is the first)

The deleteItems method deletes a whole range of items from the list. The following code removes items from the list starting at position 2, up to and including position 5

myList.deleteItems( 2, 5 );
         // Delete from position 2 up to and including position 5

You can delete all the items in the list by using the clear method as follows:

myList.clear();

Using the following code, the getSelectedIndex method returns the index number of the currently selected item, or -1 if no item is selected:

int currentSelection = myList.getSelectedIndex();

You can also get the selected item directly, with getSelectedItem as follows:

String selectItem = myList.getSelectedItem();

For lists with multiple selections turned on, you can get all the selections as getSelectedIndexes by using

int currentSelections[];
currentSelections = myList.getSelectedIndexes();

Using the following code, the getSelectedItems returns all the selected items:

String selectedItems[];
selectItems = myList.getSelectItems();

CAUTION
You should only use getSelectedIndex and getSelectedItem on lists without multiple selections. If you allow multiple selections, you should always use getSelectedIndexes and getSelectedItems.

You may select any item by calling the select() method with the index of the item you want selected. If the list does not allow multiple selections, the previously selected item will be deselected when you select a new item, such as

myList.select( 2 );       // Select the third item in the list

You may deselect any item by calling the deselect method with the index of the item you want deselected. This is performed as follows:

myList.deselect( 0 );     // Deselect the first item in the list

The isSelected method tells you whether or not the item at a particular index is selected, as in

if ( myList.isSelected( 0 ) )
{
     // the first item in the list is selected
}

You may turn multiple selections on and off with the setMultipleSelections method

myList.setMultipleSelections( true );
         // turn multi-select on, false turns it off

The allowsMultipleSelections method returns true if multiple selections are allowed

if ( myList.allowsMultipleSelections() )
{
     // multiple selections are allowed
}

Sometimes, you might make sure a particular item is visible in the list window. You can do that by passing the index of the item you want to make visible to makeVisible. For example, suppose the list was positioned on item 0, but you wanted to make sure that item 15 was showing in the window instead; you would call

myList.makeVisible( 15 );          // Make item 15 in the list visible

Using Lists

Unlike the previous GUI components you have encountered, the List class does not primarily make use of the action method. Instead, you must use the handleEvent method to catch list selection and deselection events. The handleEvent method is called whenever you select or deselect an item in a list. The format of handleEvent is

public boolean handleEvent( Event event )

When an item on a list is selected, event.id is equal to Event.LIST_SELECT, and event.arg is an instance of an integer whose value is the index of the selected item. The deselect event is identical to the select event except that event.id is Event.LIST_DESELECT. LIST_SELECT and LIST_DESELECT are declared in the Event class as static variables, as are all the other event types.

NOTE
An ACTION_EVENT event is generated when the user double-clicks a List item. You can use this notification just as if a button was pressed.

The applet in Listing 43.2 sets up a List containing several values and uses a label to inform you whenever an item is selected or deselected.


Listing 43.2  Source Code for ListApplet.java
//
//      Example 43.2 - ListApplet
//
//      This applet creates a scrolling list with several choices and
//      informs you of selections and deselections using a label.
//

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

public class
ListApplet
extends Applet
{
     Label      listStatus;
     List       myList;

     public void
     init()
     {
     // Create the list...
     myList = new List( 3, true );

     myList.addItem( "Moe" );
     myList.addItem( "Larry" );
     myList.addItem( "Curly" );
     myList.addItem( "Shemp" );
     myList.addItem( "Curly Joe" );

     // Set Shemp to be selected
     myList.select( 3 );

     // Finally, add the list to the applet
     add( myList );

     // Now create a label to show us the last event that occurred
     listStatus = new Label( "You selected entry Shemp" );
     add( listStatus );
     }

     public boolean
     handleEvent( Event evt )
     {
     String        selStr;
     Integer   sel;

     // Always check to see if the event is for what you think!
     if ( evt.target == myList )
     {
     // Check to see if this is a sel event
     switch ( evt.id )
{
     case      Event.LIST_SELECT:
     // sel is the index of the selected item
     sel = ( Integer )evt.arg;

     // use getItem to get the actual item.
     selStr = "You selected entry " +
     myList.getItem( sel.intValue() );

     // Update the label
     listStatus.setText( selStr );
     break;

     case      Event.LIST_DESELECT:
     // If this is a deselection, get the deselected item
     // sel is the index of the selected item
     sel = ( Integer )evt.arg;

     // use getItem to get the actual item.
     selStr = "You deselected entry " +
     myList.getItem( sel.intValue() );

     // Update the label
     listStatus.setText( selStr );
     break;
     }

     // We handled events!
     return( true );
     }

     // We did nothing...
     return( false );
     }
}

Figure 43.8 shows the output from ListApplet.

Figure 43.8 : The ListApplet program lets you select and deselect list items.

Text Fields and Text Areas

The AWT provides two different classes for entering text data: TextField and TextArea. The TextField class handles only a single line of text, while the TextArea class handles multiple lines. Both of these classes share many similar methods because they both are derived from a common class called TextComponent.

Creating Text Fields

The easiest way to create a text field is by using the following code:

TextField myTextField = new TextField();

This creates an empty text field with an unspecified number of columns. If you want to control how many columns are in the text field, you can do so with the following:

TextField myTextField = new TextField(40);     // Create 40-column
    text field

Sometimes you may want to initialize the text field with some text when you create it, such as

TextField myTextField = new TextField("This is some initial text");

Rounding out these combinations is a method for creating a text field initialized with text, having a fixed number of columns, such as

TextField myTextField = new TextField("This is some initial text", 40);

Creating Text Areas

It should come as no surprise to you that the methods used to create text areas are similar to those for text fields. In fact, they are identical, except that when giving a fixed size for a text area, you must give both columns and rows. You can create an empty text area having an unspecified number of rows and columns with

TextArea myTextArea = new TextArea();

If you want to initialize an area with some text, use the following line of code:

TextArea myTextArea = new TextArea("Here is some initial text");

You can give a text area a fixed number of rows and columns with

TextArea myTextArea = new TextArea(5, 40 );      // 5 rows, 40 columns

Finally, you can create a text area having some initial text and a fixed size with

TextArea myTextArea = new TextArea(
      "Here is some initial text", 5, 40); // 5 rows, 40 cols

Common Text Component Features

The TextComponent abstract class implements a number of useful methods that may be used on either TextArea or TextField classes.

You will probably want to put text into the component at some point. You can do that with setText, as in the following:

myTextField.setText("This is the text now in the field");

You will certainly want to find out what text is in the component. You can use getText to do that with

String textData = myTextArea.getText();

You can find out what text has been selected (highlighted with the mouse) by using getSelectedText like this:

String selectedStuff = myTextArea.getSelectedText();

You can also find out where the selection starts and where it ends. The getSelectionStart and getSelectionEnd methods return integers that indicate the position within the entire text where the selection starts and ends. For instance, if the selection started at the very beginning of the text, as getSelectionStart would return 0

int selectionStart, selectionEnd;
selectionStart = myTextField.getSelectionStart();
selectionEnd = myTextField.getSelectionEnd();

You can also cause text to be selected with the select method

myTextField.select(0, 4);
         // Selects the characters from position 0 through 4

If you want to select the entire text, you can use selectAll as a shortcut, as in

myTextArea.selectAll();     // Selects all the text in the area

You can also use setEditable to control whether the text in the component can be edited (if not, it is read-only) by typing

myTextField.setEditable(false);
         // Don't let anyone change this field

The isEditable method will return true if the component is editable or false if it is not.

Text Field Features

Text fields have some features that text areas do not have. The TextField class allows you to set an echo character that is printed instead of the character that was typed. This is useful when making fields for entering passwords, where you might make '*' the echo character. Setting up an echo character is as easy as calling setEchoCharacter

myTextField.setEchoCharacter('*'); // Print *s in place of what was typed

You can find out the echo character for a field with getEchoChar

char echoChar = myTextField.getEchoChar();

The echoCharIsSet method returns true if there is an echo character set for the field or false if not.

Finally, you can find out how many columns are in the text field (how many visible columns, not how much text is there) by using the getColumns method

int numColumns = myTextField.getColumns();

Text Area Features

Text areas also have special features that are all their own. Text areas are usually used for editing text, so they contain some methods for inserting, appending, and replacing text. You can add text to the end of the text area with appendText:

myTextArea.appendText(
     "This will be added to the end of the text in the area");

You can also insert text at any point in the current text with insertText. For instance, if you add text at position 0, you will add it to the front of the area

myTextArea.insertText(
     "This will be added to the front of the text in the area", 0);

You can also use replaceText to replace portions of the text. Here is an example that uses the getSelectionStart and getSelectionEnd functions from TextComponent to replace selected text in a TextArea with "[CENSORED]"

myTextArea.replaceText("[CENSORED]", myTextArea.getSelectionStart(),
     myTextArea.getSelectionEnd());

Finally, you can find out the number of columns and the number of rows in a text area with getColumns and getRows.

Using Text Fields and Text Areas

The TextArea class does not use the action method. However, in this case, you probably do not need to use the handleEvent method, either. The events you would get for the TextArea would be keyboard and mouse events, and you want the TextArea class to handle those itself. What you should do instead is create a button for the user to click when they have finished editing the text. Then you can use getText to retrieve the edited text.

The TextField class does use the action method but only in the case of the user pressing return. You may find this useful, but again, you could create a button for the user to signal that they have finished entering the text (especially if there are a number of text fields they must fill out).

Listing 43.3 creates two text fields: a text area with an echo character defined, and a text area that displays the value of the text entered in one of the text fields.


Listing 43.3  Source Code for TextApplet.java
//
//     Example 43.3 -- TextApplet
//
//     This applet creates some text fields and a text area
//     to demonstrate the features of each.
//

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

public class
TextApplet
extends Applet
{
     protected TextField      inputField;
     protected TextField      passwordField;
     protected TextArea        textArea;

     public void
     init()
     {
     inputField = new TextField();   // unspecified size
     add( inputField );

     passwordField = new TextField( 10 ); // 10 columns
     passwordField.setEchoCharacter( '*' ); // print '*' for input
     add( passwordField );

     textArea = new TextArea( 5, 40 ); // 5 rows, 40 cols
     textArea.appendText( "This is some initial text for the text
         area." );
textArea.select( 5, 12 ); // select "is some"

     add( textArea );
     }

     // The action method looks specifically for something entered in the
     // password field and displays it in the textArea
     public boolean
     action( Event evt, Object whichAction )
     {
     // Check to make sure this is an event for the passwordField
     // if not, signal that the event hasn't been handled
     if ( evt.target != passwordField )
     {
     return( false );  // Event not handled
     }

     // Now, change the text in the textArea to "Your password is: "
     // followed by the password entered in the passwordField

     textArea.setText( "Your password is: " +
     passwordField.getText() );

     return( true );   // Event has been handled
     }
}

Figure 43.9 shows the text fields and text area set up by the TextApplet example. Notice how small the first text field is because its size was left unspecified.

Figure 43.9 : Text fields and text areas allow the entry of text.

Scroll Bars

The Scrollbar class provides a basic interface for scrolling that can be used in a variety of situations. The controls of the scroll bar manipulate a position value that indicates the scroll bar's current position. You can set the minimum and maximum values for the scroll bar's position as well as its current value. The scroll bar's controls update the position in three ways: "line," "page," and "absolute." The arrow buttons at either end of the scroll bar update the scroll bar position with a line update. You can tell the scroll bar how much to add to the position (or subtract from it) for a line update; the default is 1. A page update is performed whenever the mouse is clicked on the gap between the slider button and the scrolling arrows. You may also tell the scroll bar how much to add to the position for a page update. The absolute update is performed whenever the slider button is dragged in one direction or the other. You have no control over how the position value changes for an absolute update, except that you are able to control the minimum and maximum values.

An important aspect of the Scrollbar class is that it is only responsible for updating its own position. It is unable to cause any other component to scroll. If you want the scroll bar to scroll a canvas up and down, you have to add code to detect when the scroll bar changes and update the canvas as needed.

Creating Scroll Bars

You can create a simple vertical scroll bar with

Scrollbar myScrollbar = new Scrollbar();

You can also specify the orientation of the scroll bar as either Scrollbar.HORIZONTAL or Scrollbar.VERTICAL

Scrollbar myScrollbar = new Scrollbar( Scrollbar.HORIZONTAL );

You can create a scroll bar with a predefined orientation, position, page increment, minimum value, and maximum value. The following code creates a vertical scroll bar with a starting position of 50, a page size of 10, a minimum value of 0, and a maximum value of 100:

Scrollbar myScrollbar = new Scrollbar( Scrollbar.VERTICAL, 50, 10, 0,
    100 );

Scroll Bar Features

You can set the scroll bar's line increment with setLineIncrement

myScrollbar.setLineIncrement( 2 );
         // Arrow button increment/decrement by 2 each time

You can query the current line increment with getLineIncrement

int lineIncrement = myScrollbar.getLineIncrement();

You can set the page increment with setPageIncrement

myScrollbar.setPageIncrement( 20 );
         // Page update adds/subtracts 20 each time

You can also query the page increment with getPageIncrement

int pageIncrement = myScrollbar.getPageIncrement();

You can find out the scroll bar's minimum and maximum position values with getMinimum and getMaximum

int minimum = myScrollbar.getMinimum();
int maximum = myScrollbar.getMaximum();

The setValue method sets the scroll bar's current position

myScrollbar.setValue( 25 );     // Make the current position 25

You can query the current position with getValue

int currentPosition = myScrollbar.getValue();

The getOrientation method returns Scrollbar.VERTICAL if the scroll bar is vertical, or Scrollbar.HORIZONTAL if it is horizontal

if ( myScrollbar.getOrientation() == Scrollbar.HORIZONTAL )
{
     // Code to handle a horizontal scrollbar
}
else
{
   // Code to handle a vertical scrollbar
}

You can also set the position, page increment, minimum value, and maximum value with setValues. The following code sets the position to 75, the page increment to 25, the minimum value to 0, and the maximum to 500:

myScrollbar.setValues( 75, 25, 0, 500 );

Using Scrollbars

Like the TextArea class, the Scrollbar class does not make use of the action method. You must use the handleEvent method to determine when a scrollbar has moved. The possible values of event.id for events generated by the Scrollbar class are:

You may not care which of these events is received. In many cases, you may only need to know that the scroll bar position is changed, and you would call the getValue method to find out the new position.

Canvases

The Canvas class is a component with no special functionality. It is mainly used for creating custom graphic components. You create an instance of a Canvas with

Canvas myCanvas = new Canvas();

However, you will almost always want to create your own special subclass of Canvas that does whatever special function you need. You should override the Canvas paint method to make your Canvas do something interesting. Listing 43.4 creates a CircleCanvas class that draws a filled circle in a specific color.


Listing 43.4  Source Code for CircleCanvas.java
//
// Example 43.4 -- CircleCanvas class
//
// This class creates a canvas that draws a circle on itself.
// The circle color is given at creation time, and the size of
// the circle is determined by the size of the canvas.
//

import     java.awt.*;

public class
CircleCanvas
extends Canvas
{

     Color       circleColor;

     // When you create a CircleCanvas, you tell it what color to use.
     public
     CircleCanvas( Color drawColor )
     {
     circleColor = drawColor;
     }

     public void
     paint( Graphics g )
     {
     Dimension currentSize = size();

     // Use the smaller of the height and width of the canvas.
     // This guarantees that the circle will be drawn completely.

     int circleDiameter = Math.min( currentSize.width,
         currentSize.height );

     // Set the color...
     g.setColor( circleColor );

     // The math here on the circleX and circleY may seem strange.
     // The x and y
// coordinates for fillOval are the upper-left coordinates of the
     // rectangle
// that surrounds the circle.  If the canvas is wider than the
     // circle, for
// instance, we want to find out how much wider (i.e., width -
     // diameter)
// and then, since we want equal amounts of blank area on both
     // sides, we divide the amount of blank area by 2.  In the
     // case where the diameter
// equals the width, the amount of blank area is 0.

     int circleX = ( currentSize.width - circleDiameter ) / 2;
     int circleY = ( currentSize.height - circleDiameter ) / 2;

     g.fillOval( circleX, circleY, circleDiameter, circleDiameter );
     }
}

The CircleCanvas is only a component, not a runnable applet. Later in this chapter, in the "Grid Bag Layouts" section, you'll use this new class in an example of using the GridBagLayout layout manager.

Containers

In addition to all of these wonderful components, the AWT provides several useful containers:

Panels

Since panels are only used for organizing components, there are very few things you can actually do to a panel. You create a new panel with

Panel myPanel = new Panel();

You can then add the panel to another container. For instance, you might want to add it to your layout

add( myPanel );

You can also nest panels; that is, one panel containing one or more other panels

Panel mainPanel, subPanel1, subPanel2;
subPanel1 = new Panel();   // create the first sub-panel
subPanel2 = new Panel();   // create the second sub-panel
mainPanel = new Panel();   // create the main panel

mainPanel.add( subPanel1 );  // Make subPanel1 a child (sub-panel)
                             // of mainPanel
mainPanel.add( subPanel2 );  // Make subPanel2 a child of mainPanel

You can nest panels as many levels deep as you like. For instance, in the above example, you could have made subPanel2 a child of subPanel1 (obviously with different results).

Listing 43.5 shows how to create panels and nest sub-panels within them.


Listing 43.5  Source Code for PanelApplet.java
//
// Example 43.5 -- PanelApplet
//
// The PanelApplet applet creates a number of panels and
// adds buttons to them to demonstrate the use of panels
// for grouping components.
//

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

public class
PanelApplet
extends Applet
{
     public void
     init()
     {
     // Create the main panels
     Panel mainPanel1 = new Panel();
     Panel mainPanel2 = new Panel();

     // Create the sub-panels
     Panel subPanel1 = new Panel();
     Panel subPanel2 = new Panel();

     // Add a button directly to the applet
     add( new Button( "Applet Button" ) );

     // Add the main panels to the applet
add( mainPanel1 );

     add( mainPanel2 );

     // Give mainPanel1 a button and a sub-panel
     mainPanel1.add( new Button( "Main Panel 1 Button" ) );
     mainPanel1.add( subPanel1 );

     // Give mainPanel2 a button and a sub-panel
     mainPanel2.add( new Button( "Main Panel 2 Button" ) );
     mainPanel2.add( subPanel2 );

     // Give each sub-panel a button
     subPanel1.add( new Button( "Sub-panel 1 Button" ) );
     subPanel2.add( new Button( "Sub-panel 2 Button" ) );
     }
}

Figure 43.10 shows the output from PanelApplet.

Figure 43.10 : Panels, like other containers, help group components together.

Frames

Frames are a powerful feature of the AWT. They enable you to create separate windows for your application. For instance, you might want your application to run outside the main window of a Web browser. You can also use frames to build stand-alone graphical applications.

Creating Frames

You can create a frame that is initially invisible and has no title with

Frame myFrame = new Frame();

You can give the frame a title when you create it, but it will still be invisible

Frame myFrame = new Frame( "Hi!  This is my frame!" );

Frame Features

Once you have created a frame, you will probably want to see it. Before you can see the frame, you must give it a size. Use the resize method to set the size

myFrame.resize( 300, 100 );  // Make the frame 300 pixels wide, 100 high

You can use the show method to make it visible

myFrame.show();     // Show yourself, Frame!

You can send a frame back into hiding with the hide method. Even though the frame is invisible, it still exists

myFrame.hide();

As long as a frame exists, invisible or not, it is consuming some amount of resources in the windowing system it is running on. If you have finished with a frame, you should get rid of it with the dispose method

myFrame.dispose();     // Gets rid of the frame and releases its resources

You can change the title displayed at the top of the frame with setTitle

myFrame.setTitle( "With Frames like this, who needs enemies?" );

The getTitle method returns the frame's title

String currentTitle = myFrame.getTitle();

The Frame class has a number of different cursors. You can change the frame's cursor with setCursor

myFrame.setCursor( Frame.HAND_CURSOR );        // Change cursor to a hand

The available cursors are

The getCursorType method returns one of these values, indicating the current cursor type.

If you do not want to allow your frame to be resized, you can call setResizable to turn resizing on or off

myFrame.setResizable( false );     // Turn resizing off

You can change a frame's icon with setIconImage

myFrame.setIconImage( someIconImage );
         // someIconImage must be an instance of Image

Using Frames to Make Your Applet Run Stand-Alone

You can create applets that can run either as an applet or as a stand-alone application. All you need to do is write a main method in the applet that creates a Frame and then creates an instance of the applet that belongs to the frame. Listing 43.6 shows an applet that can run either as an applet or as a stand-alone application.


Listing 43.6  Source Code for StandaloneApplet.java
//     Example 43.6 -- StandaloneApplet
//
// This is an applet that runs either as
// an applet or a stand-alone application.  To run
// stand-alone, it provides a main method that creates
// a frame, then creates an instance of the applet and
// adds it to the frame.
//

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

public class
StandaloneApplet
extends Applet
{
     public void
     init()
     {
     add( new Button( "Standalone Applet Button" ) );
     }

     public static void
     main( String args[] )
     {
     // Create the frame this applet will run in
     Frame appletFrame = new Frame( "Some applet" );

     // Create an instance of the applet
     Applet myApplet = new StandaloneApplet();

     // Initialize and start the applet
     myApplet.init();
     myApplet.start();

     // The frame needs a layout manager
     appletFrame.setLayout( new FlowLayout() );

     // Add the applet to the frame
     appletFrame.add( myApplet );

     // Have to give the frame a size before it is visible
     appletFrame.resize( 300, 100 );

     // Make the frame appear on the screen
     appletFrame.show();
     }
}

Adding Menus to Frames

You can attach a MenuBar class to a frame to provide drop-down menu capabilities. You can create a menu bar with the following code:

MenuBar myMenuBar = new MenuBar();

Once you have created a menu bar, you can add it to a frame using the setMenuBar method

myFrame.setMenuBar( myMenuBar );

Once you have a menu bar, you can add menus to it. The following code fragment creates a menu called "File" and adds it to the menu bar:

Menu fileMenu = new Menu( "File" );
myMenuBar.add( fileMenu );

Some windowing systems allow you to create menus that stay up after you release the mouse button. These are referred to as "tear-off" menus. You can specify that a menu is a "tear-off" menu when you create it

Menu tearOffMenu = new Menu( "Tear Me Off", true );
         // true indicates it can be torn off

In addition to adding submenus, you will want to add menu items to your menus. Menu items are the parts of a menu that the user actually selects. Menus, on the other hand, are used to contain menu items, as well as submenus. For instance, the File menu that is on many systems contains menu items such as New, Open, Save, and Save As. If you created a menu structure with no menu items, the menu structure would be useless because there would be nothing to select. You may add menu items to a menu in two ways. You can simply add an item name with

fileMenu.add( "Open" );     // Add an "Open" option to the file menu

You can also add an instance of a MenuItem class to a menu

MenuItem saveMenuItem = new MenuItem( "Save" );
         // Create a "Save" menu item
fileMenu.add( saveMenuItem );        // Add the "Save" option to the
                                     // file menu

You can enable and disable menu items by using enable and disable. When you disable a menu item, it still appears on the menu, but it usually appears in gray (depending on the windowing system). You cannot select menu items that are disabled. The format for enable and disable is

saveMenuItem.disable();     // Disables the save option from the file menu
saveMenuItem.enable();      // Enables the save option again

In addition to menu items, you can add submenus and menu separators to a menu. A separator is a line that appears on the menu to separate sections of the menu. To add a separator, just call the addSeparator method

fileMenu.addSeparator();

To create a submenu, create a new instance of a menu and add it to the current menu

Menu printSubmenu = new Menu( "Print" );
fileMenu.add( printSubmenu );
printSubmenu.add( "Print Preview" );
         // Add print preview as option on Print menu
printSubmenu.add( "Print Document" );
         // Add print document as option on Print menu

You can also create special check box menu items. These items function like the check box buttons. The first time you select one, it becomes checked, or "on." The next time you select it, it becomes unchecked, or "off." To create a check box menu item, use the following code:

CheckboxMenuItem autoSaveOption = new CheckboxMenuItem( "Auto-save" );
fileMenu.add( autoSaveOption );

You can check to see whether or not a check box menu item is checked with getState

if ( autoSaveOption.getState() )
{
     // autoSaveOption is checked, or "on"
}
else
{
     // autoSaveOption is off
}

You can set the current state of a check box menu item with setState

autoSaveOption.setState( true );     // Explicitly turn auto-save
                                     // option on

Normally, menus are added to a menu bar in a left to right fashion. Many windowing systems, however, create a special "help" menu that is on the far right of a menu bar. You can add such a menu to your menu bar with the setHelpMenu method

Menu helpMenu = new Menu();
myMenuBar.setHelpMenu( helpMenu );

Using Menus

Whenever a menu item is selected, it generates an action. The whichAction parameter to the action method is the name of the item selected

public boolean
action( Event evt, Object whichAction )
{
     //First, make sure this event is a menu selection
     if ( evt.target instanceof MenuItem )
     {
     if ( ( String )whichAction.equals( "Save" ) )
     {
     // Handle save option
     }
     }

     return( true );
}

Listing 43.7 shows an application that sets up a simple File menu with New, Open, and Save menu items, a check box called Auto-Save, and a Print submenu with two menu items on it.


Listing 43.7  Source Code for MenuApplication.java
import     java.awt.*;
import     java.applet.*;

public class
MenuApplication
extends Frame
{
     public static void
     main( String[] args )
     {
     new MenuApplication();
     }

     public
     MenuApplication()
     {
     //Call my dad's constructor...
     super( "Menu Example" );

     //Create the menu bar
     MenuBar myBar = new MenuBar();
     setMenuBar( myBar );

     //Create the file menu and add it to the menubar...
Menu fileMenu = new Menu( "File" );
     myBar.add( fileMenu );

     //Add the New and Open menuitems
fileMenu.add( new MenuItem( "New" ) );
     fileMenu.add( new MenuItem( "Open" ) );

     //Create a disabled Save menuitem
MenuItem saveMenuItem = new MenuItem( "Save" );
     saveMenuItem.disable();
     fileMenu.add( saveMenuItem );

     //Add an Auto-Save checkbox, followed by a separator
fileMenu.add( new CheckboxMenuItem( "Auto-Save" ) );
     fileMenu.addSeparator();

     //Create the Print submenu
     Menu printSubmenu = new Menu( "Print" );
     fileMenu.add( printSubmenu );
     printSubmenu.add( "Print Preview" );
     printSubmenu.add( "Print Document" );

     //Must resize the frame before it can be shown
     resize( 300, 200 );

     //Make the frame appear on the screen
     show();
     }
}

Figure 43.11 shows the output from the MenuApplication program, with the "Print Document" option in the process of being selected.

Figure 43.11 : The AWT provides a number of popular menu features, including checked menu items, disabled menu items, and separators.

Dialog Boxes

Dialog boxes are pop-up windows that are not quite as flexible as frames. You can create a dialog box as either modal or non-modal. The term modal means the dialog box blocks input to other windows while it is being shown. Non-modal, conversely, does not block input. This is useful for dialog boxes where you want to stop everything and get a crucial question answered such as "Are you sure you want to quit?" An example of a non-modal dialog box is a control panel that changes settings in an application while the application continues to run.

Creating Dialog Boxes

You must first have a frame to create a dialog box. A dialog box cannot belong to an applet. However, an applet may create a frame to which the dialog box can then belong. You must specify whether a dialog box is modal or non-modal at the time it is created because you cannot change its "modality" once it has been created. The following example creates a modal dialog box whose parent is myFrame:

Dialog myDialog = new Dialog( myFrame, true );
    // true means modal dialog

You can also create a dialog box with a title

Dialog myDialog = new Dialog( myFrame, "A Non-Modal Dialog", false );
         // false = non-modal

NOTE
Since a dialog box cannot belong to an applet, your use of dialog boxes can be somewhat limited. One solution is to create a dummy frame as the dialog box's parent. Unfortunately, you cannot create modal dialog boxes this way because only the frame and its children would have their input blocked; the applet would continue on its merry way. A better solution is to use the technique discussed in the "Frames" section of this chapter in which you create a stand-alone application using frames, and then have a "bootstrap" applet create a frame and run the real applet in it.

Once you have created a dialog box, you can make it visible using the show method

myDialog.show();

Dialog Box features

The Dialog class has the following methods in common with the Frame class:

void setResizable( boolean );
     boolean isResizable();
     void setTitle(String);
     String getTitle();

The isModal method will return true if the dialog box is modal. This is the only method that the Dialog class has that the Frame does not.

A Reusable OK Dialog Box

Listing 43.8 shows the OKDialog class, which provides an OK dialog box that displays a message and waits for you to click OK.


Listing 43.8  Source Code for OKDialog.java
//
//     Example 43.8 - OK Dialog class
//
//     OKDialog - Custom dialog that presents a message and waits for
//     you to click the OK button.
//
//     Example use:
//    Dialog ok = new OKDialog(parentFrame, "Click OK to continue");
//    ok.show();      // Other input will be blocked until OK is pressed
//     As a shortcut, you can use the static createOKDialog that will
//     create its own frame and activate itself:
//    OKDialog.createOKDialog("Click OK to continue");
//

import     java.awt.*;

public class
OKDialog
extends Dialog
{
     protected Button      okButton;
     protected static Frame    createdFrame;

     public
     OKDialog( Frame parent, String message )
     {
     super( parent, true );   // Must call the parent's constructor

     // This Dialog box uses the GridBagLayout to provide a pretty good
     // layout.
GridBagLayout gridbag = new GridBagLayout();
     GridBagConstraints constraints = new GridBagConstraints();

     //Create the OK button and the message to display
     okButton = new Button( "OK" );
     Label messageLabel = new Label( message );

     setLayout( gridbag );

     // The message should not fill, it should be centered within
     // this area, with
// some extra padding.  The gridwidth of REMAINDER means this
     // is the only
// thing on its row, and the gridheight of RELATIVE means
     // there should only
// be one thing below it.
     constraints.fill = GridBagConstraints.NONE;
     constraints.anchor = GridBagConstraints.CENTER;
     constraints.ipadx = 20;
     constraints.ipady = 20;
     constraints.weightx = 1.0;
     constraints.weighty = 1.0;
     constraints.gridwidth = GridBagConstraints.REMAINDER;
     constraints.gridheight = GridBagConstraints.RELATIVE;

     gridbag.setConstraints( messageLabel, constraints );
     add( messageLabel );

     // The button has no padding, no weight, taked up minimal width, and
// Is the last thing in its column.
constraints.ipadx = 0;
     constraints.ipady = 0;
     constraints.weightx = 0.0;
     constraints.weighty = 0.0;
     constraints.gridwidth = 1;
     constraints.gridheight = GridBagConstraints.REMAINDER;

     gridbag.setConstraints( okButton, constraints );

     add( okButton );

     // Pack is a special window method that makes the window take
     // up the minimum
// space necessary to contain its components.
pack();
     }

     // The action method just waits for the OK button to be clicked and
// when it is it hides the dialog box, causing the show() method to
     // return
//      back to whoever activated this dialog box.

     public boolean
     action( Event evt, Object whichAction )
     {
     if ( evt.target == okButton )
     {
     hide();

     if ( createdFrame != null )
     createdFrame.hide();
     }

     return( true );
     }

     // Shortcut to create a frame automatically, the frame is a
     // static variable
// so all dialog boxes in an applet or application can use the
     // same frame.
public static void
     createOKDialog( String dialogString )
     {
     // If the frame hasn't been created yet, create it
     if ( createdFrame == null )
     createdFrame = new Frame( "Dialog" );

     // Create the dialog box now
OKDialog okDialog = new OKDialog( createdFrame, dialogString );

     // Shrink the frame to just fit the dialog
     createdFrame.resize( okDialog.size().width, okDialog.size().height );

     // Show the dialog box
okDialog.show();
     }
}

The DialogApplet in Listing 43.9 pops up an OK dialog box whenever the user clicks a button.


Listing 43.9  Source Code for DialogApplet.java
//
// Example 43.9       -- DialogApplet
//
// Dialog applet creates a button, and when you click
// the button it brings up an OK dialog.  The input
// to the original button should be blocked until
// the OK button in the dialog box is clicked.
//

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

public class
DialogApplet
extends Applet
{
     protected Button      launchButton;

     public void
     init()
     {
     launchButton = new Button( "Give me an OK" );
     add( launchButton );
     }

     public boolean
     action( Event event, Object whichAction )
     {
     // Make sure this action is for the launchButton
     if ( event.target != launchButton )
     return( false );

     // Create and display the OK dialog
     OKDialog.createOKDialog( "Click OK when you are ready" );

     // Signal that we've handled the event
     return( true );
     }
}

Figure 43.12 shows DialogApplet's OK dialog box.

Figure 43.12 : The OKDialog class creates a dialog box with an OK button.

Layout Managers

By using layout managers, you tell the AWT where you want your components to go relative to the other components. The layout manager figures out exactly where to put them. This helps you make platform-independent software. When you position things by absolute coordinates, it can cause odd results if someone running Windows 95 in 640´480 resolution tries to run an applet designed to fit on a 1280´1024 X-terminal.

The AWT provides five different types of layout managers:

Flow Layouts

A FlowLayout class treats a container as a set of rows. The height of the rows is determined by the height of the items placed in the row. The FlowLayout starts adding new components from left to right. If it cannot fit the next component onto the current row, it drops down to the next row and starts again from the left. It also tries to align the rows by using either left-justification, right-justification, or centering. The default alignment for a FlowLayout is centered, which means that when it creates a row of components, it will try to keep the components centered with respect to the left and right edges.

TIP
The FlowLayout layout manager is the default layout manager for all applets.

To create a FlowLayout with centered alignment and attach it to your applet, use the following code:

myFlowLayout = new FlowLayout();
setLayout( myFlowLayout );

To create a FlowLayout with a left-justified alignment, use the following code:

myFlowLayout = new FlowLayout( FlowLayout.LEFT );

The different types of FlowLayout alignment are FlowLayout.LEFT, FlowLayout.RIGHT, and FlowLayout.CENTER.

You may also give the FlowLayout horizontal and vertical gap values. These values specify the minimum amount of horizontal and vertical space to leave between components. These gaps are given in units of screen pixels. The following code is used to create a right-justified FlowLayout with a horizontal gap of 10 pixels and a vertical gap of five pixels:

myFlowLayout = new FlowLayout( FlowLayout.RIGHT, 10, 5 );

Figure 43.13 shows five buttons arranged in a flow layout.

Figure 43.13 : The flow layout places components from left to right.

Grid Layouts

A GridLayout class divides a container into a grid of equally-sized cells. When you add components to the container, the GridLayout places them from left to right, starting in the top left cells. When you create a GridLayout class, you must tell it how many rows and columns you want. If you give it a number of rows, it will compute the number of columns needed. If, instead, you give it a number of columns, it will compute the number of rows needed. If you add six components to a GridLayout with two rows, it will create three columns. The format of the GridLayout constructor is

GridLayout( int numberOfRows, int numberOfColumns )

If you create a GridLayout with a fixed number of rows, you should use 0 for the number of columns. If you have a fixed number of columns, use 0 for the number of rows.

NOTE
If you pass GridLayout non-zero values for both the number of rows and the number of columns, it will only use the number of rows. The number of columns will be computed based on the number of components and the number of rows. GridLayout(3, 4) is exactly the same as GridLayout(3, 0).

You may also specify a horizontal and vertical gap. The following code creates a GridLayout with 4 columns, a horizontal gap of 8, and a vertical gap of 10:

GridLayout myGridLayout = new GridLayout( 0, 4, 8, 10 );

Figure 43.14 shows five buttons arranged in a grid layout.

Figure 43.14 : The grid layout allocates equally sized areas for each component.

Border Layouts

A BorderLayout class divides a container up into five areas named "North", "South", "East", "West", and "Center". When you add components to the container, you must use a special form of the add method that includes one of these five area names. These five areas are arranged like the points on a compass. A component added to the "North" area is placed at the top of the container, while a component added to the "West" area is placed on the left side of the container. The BorderLayout class does not allow more than one component in an area. You may optionally specify a horizontal gap and a vertical gap. To create a BorderLayout without specifying a gap, use the following code:

BorderLayout myBorderLayout = new BorderLayout();

To create a BorderLayout with a horizontal gap of 10 and a vertical gap of 20, use the following code:

BorderLayout myBorderLayout = new BorderLayout( 10, 20 );

To add myButton to the "West" area of the BorderLayout, use the following code:

myBorderLayout.add( "West", myButton );

CAUTION
The BorderLayout class is very picky about how and where you add components. If you try to add a component by using the regular add method (without the area name), you will not see your component. If you try to add two components to the same area, you will only see the last component added.
Also, the add method is case-sensitive. You must spell "North", "South", "East", "West", and "Center" exactly as shown. Otherwise, your additions will not show.

Listing 43.10 shows a BorderLayoutApplet that creates a BorderLayout, attaches it to the current applet, and adds some buttons to the applet.


Listing 43.10  Source Code for BorderLayoutApplet.java
// This applet creates a BorderLayout and attaches it
// to the applet. Then it creates buttons and places
// in all possible areas of the layout.
//

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

public class
BorderLayoutApplet
extends Applet
{
     public void
     init()
     {
     //First create the layout and attach it to the applet
     setLayout( new BorderLayout() );

     //Now create some buttons and lay them out
     add( "North", new Button( "North" ) );
     add( "South", new Button( "South" ) );
     add( "East", new Button( "East" ) );
     add( "West", new Button( "West" ) );
     add( "Center", new Button( "Center" ) );
     }
}

Figure 43.15 shows five buttons arranged in a border layout.

Figure 43.15 : The border layout places components at the north, south, east, and west compass points, as well as in the center.

Grid Bag Layouts

The GridBagLayout class, like the GridLayout, divides a container into a grid of equally-sized cells. Unlike the GridLayout, however, the GridBagLayout class decides how many rows and columns it will have, and it allows a component to occupy more than one cell, if necessary. The total area that a component occupies is called its display area. Before you add a comp-onent to a container, you must give the GridBagLayout a set of "suggestions" on where to put the component. These suggestions are in the form of a GridBagConstraints class. The GridBagConstraints class has a number of variables to control the placement of a component:

When you want to add a component to a container by using a GridBagLayout, you create the component, then create an instance of GridBagConstraints and set the constraints for the component. For instance,

GridBagLayout myGridBagLayout = new GridBagLayout();
setLayout( myGridBagLayout );
         // Set the applet's layout manager to myGridBagLayout

Button myButton = new Button( "My Button" );
GridBagConstraints constraints = new GridBagConstraints();
constraints.weightx = 1.0;
constraints.gridwidth = GridBagConstraints.RELATIVE;
constraints.fill = GridBagConstraints.BOTH;

Next, you set the component's constraints in the GridBagLayout with the following code:

myGridLayout.setConstraints( myButton, constraints );

Now you may add the component to the container

add( myButton );

The applet in Listing 43.11 uses the GridBagLayout class to arrange a few instances of CircleCanvas (created earlier in this chapter).


Listing 43.11  Source Code for CircleApplet.java
//
// Example 43.11 -- CircleApplet
//
// This circle demonstrates the CircleCanvas class we
// created. It also shows you how to use the GridBagLayout
// to arrange the circles.
//

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

public class
CircleApplet
extends Applet
{
     public void
     init()
     {
     GridBagLayout gridbag = new GridBagLayout();
     GridBagConstraints constraints = new GridBagConstraints();
     CircleCanvas newCircle;

     setLayout( gridbag );

     // We'll use the weighting to determine relative circle sizes.
     // Make the
// first one just have a weight of 1. Also, set fill for both
     // directions
//so it will make the circles as big as possible.
     constraints.weightx = 1.0;
     constraints.weighty = 1.0;
     constraints.fill = GridBagConstraints.BOTH;

     //Create a red circle and add it
     newCircle = new CircleCanvas( Color.red );
     gridbag.setConstraints( newCircle, constraints );
     add( newCircle );

     //Now, we want to make the next circle twice as big as the previous
     //one, so give it twice the weight.
     constraints.weightx = 2.0;
     constraints.weighty = 2.0;

     //Create a blue circle and add it
     newCircle = new CircleCanvas( Color.blue );
     gridbag.setConstraints( newCircle, constraints );
     add( newCircle );

     // We'll make the third circle the same size as the first one,
     // so set the
//weight back down to 1.
     constraints.weightx = 1.0;
     constraints.weighty = 1.0;

     //      Create a green circle and add it.
     newCircle = new CircleCanvas( Color.green );
     gridbag.setConstraints( newCircle, constraints );
     add( newCircle );
     }
}

Figure 43.16 shows the three circle canvases from the GridBagApplet.

Figure 43.16 : The GridBagApplet creates three circle canvases.

Insets

Insets are not layout managers, but instead, are instructions to the layout manager about how much space to leave around the edges of the container. The layout manager determines the inset values for a container by calling the container's insets method. The insets method returns an instance of an Insets class, which contains the values for the top, bottom, left, and right insets. For example, if you want to leave a 20 pixel gap between the components in your applet and the applet border, you should create an insets method in your applet as follows:

public Insets
insets()
{
     return( new Insets( 20, 20, 20, 20 ) );
         // Inset by 20 pixels all around
}

The constructor for the Insets class takes four inset values in the order of top, left, bottom, and right.

Figure 43.17 shows what the GridBagApplet looks like when it uses the preceding insets method. The gap between the circles is not from the Insets class, but from the fact that the circles are smaller. The gaps on the top, bottom, left, and right are created by the Insets class.

Figure 43.17 : Insets create a gap between components and the edges of their containers.