by Jerry Ablan
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.
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.
Components are the building blocks of the AWT. The end-user interacts directly with these components. The components provided by the AWT are
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. |
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 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.
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. |
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 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.
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 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!
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
}
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.
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.
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.
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.
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 );
}
The List class allows you to create a scrolling list of values that may be selected either individually or several at a time.
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. |
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
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.
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.
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);
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
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 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 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.
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.
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.
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 );
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 );
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.
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.
In addition to all of these wonderful components, the AWT provides several useful containers:
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 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.
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!" );
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
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();
}
}
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 );
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.
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.
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();
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.
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.
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:
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.
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.
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.
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 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.