by Mark Wutka
As you learned in Chapter 28, "java.awt--Events," the AWT is a platform-independent user interface toolkit. In addition to the raw graphics functions presented in Chapter 28, the AWT contains a higher-level set of tools that includes buttons, lists, scroll bars, and other common components.
The AWT contains a number of familiar user interface elements. Figure 29.1 shows
a Java applet with a sample of some of the components of the AWT.
FIG. 29.1
The AWT features a number of familiar components.
Figure 29.2 shows you a portion of the AWT's inheritance hierarchy.
FIG. 29.2
The AWT inherits all of 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:
Although buttons are simple mechanisms, they are some 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 decision you must make when creating a button is whether you want the button to be labeled. There are no other options for buttons.
To create an unlabeled button, use the empty constructor:
public Button()
Creating a labeled button is an equally simple task:
public Button(String label)
Once you have created a button, you need to add it to a container. Because your applet is already a container, you can add a button directly to your applet:
Button myButton = new Button("Press Me"); add(myButton);
To change the label of a button, use setLabel:
public void setLabel(String newLabel)
To get the label for a button, use getLabel:
public String 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. If you want an image button, you have to implement it yourself or search one of the Java archives on the Internet for someone else's implementation of an image button.
Now that you are able to create a button and add it to your applet, it's time to learn how to make the button do something. Under the Java 1.0 event model, all the components within the AWT have an action method that is called when an action is taken on the 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, such as keyDown or mouseDown.
NOTE: The AWT does not call the action method directly. Instead, it calls the handleEvent method, which is responsible for handling all the events for a component. The handleEvent method acts as an event dispatcher. When it receives an Event.ACTION_EVENT event, it calls the action method. When it receives a KEY_PRESS event, it calls the keyDown method. If a method called by handleEvent returns a value of false, the handleEvent method will pass the event up to the handleEvent method in the parent container, which again performs the same dispatching duties. This process continues until handleEvent calls a method that returns true, or until the event reaches the topmost container.
public boolean action(Event event, Object whatAction)
where event is the event that has occurred in the component, and whatAction indicates what has occurred.
For buttons, whatAction 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 (event.target) and when (event.when) the action occurred.
CAUTION:
You should always check the event.target variable using the instanceof operator to make sure that the action is for the object you expect. For instance, if you expect that the action is for a Button, then you need to check to make sure that (event.target instanceof Button) is true.
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 its background color. One way to do this is to put the name of the color in the button label. Then, in the action method, you look at the label of the button that was pressed and set the applet's background color based on the 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 29.1 demonstrates how to do this.
import java.applet.*; import java.awt.*; // Example 29.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. // public class Button1Applet extends Applet { public void init() { add(new Button("Red")); add(new Button("Blue")); } public boolean action(Event evt, Object whatAction) { // 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)) { return false; } String buttonLabel = (String) whatAction; if (buttonLabel == "Red") { setBackground(Color.red); } else if (buttonLabel == "Blue") { setBackground(Color.blue); } repaint(); // Make the change visible immediately return true; } }
Figure 29.3 shows you the Button1Applet in operation.
FIG. 29.3
The buttons in Button1Applet change the applet's background color.
As you learned in Chapter 28, the Java 1.0 event model does not promote good object-oriented design. In the case of the Button1Applet, all the application logic is in the applet itself. There really isn't any part of this example that you can reuse as a compiled unit. You would have to cut and paste pieces out of the example to reuse any part of it.
While there is a slightly better way to approach the application under Java 1.0, the Java 1.1 event model makes it much easier to make a reusable piece of the application. You want to decentralize your program control. Ideally, your applet should just create some objects and "set them in motion," occasionally handling things that come up.
In Button1Applet, the main action is the setting of the applet's background color. Under Java 1.1, you can create an object that responds to an action event and then sets the background color of the applet. Since any component can have its background color changed, it seems silly to restrict the object to only changing applets. Listing 29.2 shows the BGSetter object that reacts to an action event by changing the background color on a specific component.
import java.applet.*; import java.awt.*; import java.awt.event.*; // This class listens for an action event, and then changes the // background color of a specified component. public class BGSetter extends Object implements ActionListener { Component component; Color color; public BGSetter(Component component, Color color) { this.component = component; this.color = color; } public void actionPerformed(ActionEvent evt) { component.setBackground(color); component.repaint(); } }
Now, all the applet needs to do is create some buttons and some BGSetters. Listing 29.3 shows the new version of the applet.
import java.applet.*; import java.awt.*; public class Button2Applet extends Applet { public void init() { Button red = new Button("Red"); add(red); red.addActionListener(new BGSetter(this, Color.red)); Button blue = new Button("Blue"); add(blue); blue.addActionListener(new BGSetter(this, Color.blue)); } }
Labels are the simplest of the AWT components. They are text strings that are used only for decoration. Because they are components, labels have an action method, but because they are "display-only," they do not generate an action event.
There are three different ways to create a label. The simplest is to create an empty label:
public Label()
Of course, an empty label isn't going to do you much good because there is nothing to see. You can create a label with some text by passing the text to the constructor:
public Label(String labelText)
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 when you create it:
public Label(String labelText, int alignment)
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:
public void setText(newLabelText)
You can also get the text of a label with getText:
public String getText()
You can change the alignment of a label with setAlignment:
public void setAlignment(int alignment) throws IllegalArgumentException
You can also get the alignment of a label with getAlignment:
public int getAlignment()
Figure 29.4 shows you a sample label.
FIG. 29.4
Labels are simply text strings.
Checkboxes are similar to buttons except that they are used as "yes-no" or "on-off" switches. Every time you click a checkbox, it changes from "off" to "on" or from "on" to "off." A close cousin to the checkbox 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 a group can be on at a time. Imagine what a radio would sound like if more than one station could be on at a time!
A checkbox contains two parts--a label and a state. The label is the text that is displayed next to the checkbox itself, while the state is a boolean variable that indicates whether the box is checked. By default, the state of a checkbox is false, or "off."
The Checkbox class has three constructors:
public Checkbox()
creates a checkbox with no label.
public Checkbox(String label)
creates a labeled checkbox.
public Checkbox(String label, CheckboxGroup group, boolean initialState)
creates a labeled checkbox that is checked if initialState is true. The group parameter indicates what checkbox group this checkbox belongs to. The CheckboxGroup class allows you to group checkboxes into mutually exclusive radio buttons. If you are creating a checkbox and not a radio button, pass null as the group.
You may check to see if a checkbox has been checked by using getState:
public boolean getState()
For example:
if (myCheckbox.getState()) { // The box has been checked } else { // The box has not been checked }
A radio button is just a special case of a checkbox. No RadioButton class exists. Instead, you create a set of radio buttons by creating checkboxes and putting them in the same checkbox group. The constructor for CheckboxGroup takes no arguments:
public CheckboxGroup()
Once you have created a checkbox group, you add checkboxes to the group by passing the group to the checkbox constructor. In other words, instead of adding existing checkboxes to a group explicitly, you create new checkboxes that belong to the group.
The following code fragment creates a checkbox group, then creates some checkboxes that belong to the group, and then adds them to the applet:
CheckboxGroup myCheckBoxGroup = new CheckboxGroup(); 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));
When you add checkboxes to a checkbox group, the last checkbox added as true is the box that is checked when the group is displayed.
public Checkbox getCurrent()
An item event for a checkbox or radio button is called whenever it is clicked. Under Java 1.1, you must create an object that implements the ItemListener interface in order to find out when a checkbox or radio button has been selected.
The ItemListener interface defines the itemStateChanged method, which is called when a checkbox or radio button is selected or deselected:
public abstract void itemStateChanged(ItemEvent event)
The ItemEvent object can tell you the object where the event occurred, the item selected, and the kind of selection. The getItemSelectable returns the object where the event occurred:
public ItemSelectable getItemSelectable()
The getItem method in ItemEvent tells you the value of the selected item. In this case, it returns the label of the checkbox or radio button:
public Object getItem()
The getStateChange method returns either ItemEvent.SELECTED or ItemEvent.DESELECTED depending on whether the object has been selected or deselected:
public int getStateChange()
The following code snippet shows how you can receive notification of a change in a checkbox or radio button:
public void itemStateChange(ItemEvent event) { if (event.getStateChange() == ItemEvent.SELECTED) { System.out.println(event.getItem() + " has been selected."); } else { System.out.println(event.getItem() + " has been deselected."); } }
Under the Java 1.0 event model, the whichAction parameter of the action method will be an instance of a Boolean class that is true if the checkbox was clicked on, or false if the checkbox 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 checkbox.
You can also use the getLabel method to determine which checkbox 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) // make sure this is a checkbox { Checkbox currentCheckbox = (Checkbox)evt.target; boolean checkboxState = currentCheckbox.getState(); if (currentCheckbox.getLabel() == "Check me if you like Java") { if (checkboxState) { // Code to handle "Check me if you like Java" being set to on } else { // Code to handle "Check me if you like Java" being set to off } return true; // the event has been handled } } return false; // the event has not been handled }
NOTE: Whenever you write an event-handling method such as handleEvent or action, you should return true only in cases where you actually handle the event. Notice that the example action method for checkboxes only returns true in the case where the event is a checkbox 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.
The Choice class provides a pop-up menu of text string choices. The current choice is displayed as the menu title.
To create a choice pop-up menu, you must first create an instance of the Choice class. Because 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 string items using the addItem method:
public synchronized void addItem(String item) throws NullPointerException
For example:
myChoice.addItem("Moe"); myChoice.addItem("Larry"); myChoice.addItem("Curly");
You may also change which item is currently selected either by name or index:
public synchronized void select(int pos) throws IllegalArgumentException public void select(String str)
If you want Curly to be selected, for instance, you could select him by name:
myChoice.select("Curly"); // Make "Curly" become selected item
You could also select Curly by his position in the list. Because he was added third and the choices are numbered starting at 0, Moe would be 0, Larry would be 1, and Curly would be 2:
myChoice.select(2); // Make the third list entry become selected
The getSelectedIndex method will return the position of the selected item:
public int getSelectedIndex()
Again, if Curly was selected, getSelectedIndex would return 2. Similarly, the getSelectedItem method returns the string name of the selected item:
public String getSelectedItem()
If Curly was selected, getSelectedItem would return 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:
public String getItem(int index)
Figure 29.6 shows a choice in its usual form, while Figure 29.7 shows a choice
with its menu of choices pulled down.
FIG. 29.6
The choice box displays its current selection.
FIG. 29.7
The button on the right of a choice pops up a menu of the possible choices.
Like other components that generate item events, you need to set up an ItemListener object in order to handle action events from a Choice object. An item event is generated whenever a choice is selected, even if it is the same choice.
Under Java 1.0, the action method for a choice is called whenever a choice is made, even if it is the same choice. 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)) { return false; } Choice whichChoice = (Choice) event.target; // See if this is an action for myChoice if (whichChoice == myChoice) { currentStooge = (String) whatAction; return true; // the event has been handled } return false; // it must have been a different Choice }
The List class allows you to create a scrolling list of values that may be selected either individually or many at a time. You may add and delete items from the list at any time, and even change which items are selected. The AWT handles all the scrolling for you.
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:
public List()
You may also set the number of list entries that are visible in the list window at any one time as well as determine whether to allow multiple selections:
public List(int rows, boolean allowMultipleSelections)
The following code fragment creates a list with 10 visible entries and multiple selections turned on:
List myList = new List(10, true); // True means allow multiple selections
Once you have created the list, you can add new entries with the addItem method:
public synchronized void addItem(String item)
For example:
myList.addItem("Moe"); myList.addItem("Larry"); myList.addItem("Curly");
You may also add an item at a specific position in the list:
public synchronized void addItem(String item, int index)
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 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 of the list
The List class provides a number of different methods for changing the contents of the list. The replaceItem method replaces an item at a given position with a new item:
public synchronized void replaceItem(String newValue, int position) 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:
public synchronized void delItem(int position)
The deleteItems method deletes a whole range of items from the list:
public synchronized void delItems(int start, int end)
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 of the items in the list with the clear method:
public synchronized void clear()
The getSelectedIndex method returns the index number of the currently selected item or -1 if no item is selected:
public synchronized int getSelectedIndex()
You can also get the selected item directly with getSelectedItem:
public synchronized String getSelectedItem()
For lists with multiple selections turned on, you can get all of the selections with getSelectedIndexes:
public synchronized int[] getSelectedIndexes()
The getSelectedItems returns all of the selected items:
public synchronized String[] getSelectedItems()
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.
public synchronized void select(int index)
If the list does not allow multiple selections, the previously selected item will be deselected.
You may deselect any item by calling the deselect method with the index of the item you want deselected:
public synchronized void deselect(int index)
The isSelected method tells you whether the item at a particular index is selected:
public synchronized boolean isSelected(int index)
For example:
if (myList.isSelected(0)) { // the first item in the list is selected }
You may turn multiple selections on and off with the setMultipleSelections method:
public void setMultipleSelections(boolean allowMultiples)
The allowsMultipleSelections method returns true if multiple selections are allowed:
public boolean allowsMultipleSelections()
For example:
if (myList.allowsMultipleSelections()) { // multiple selections are allowed }
Sometimes you may want to make sure a particular item is visible in the list window. You can do just that by passing the index of the item you want to make visible to makeVisible:
public void makeVisible(int index)
For example, suppose the list was positioned on item 0, but you wanted to make sure item 15 was showing in the window instead. You would call:
myList.makeVisible(15); // Make item 15 in the list visible
Under Java 1.1, the List object generates an ItemEvent whenever an item is selected or deselected. The getItem method in the ItemEvent returns the index of the selected item and not the item itself. The List object generates an action event when you double-click an item. The getActionCommand method in the ActionEvent returns the string label of the item selected.
Unlike the previous user interface components you have encountered in the Java 1.0 event model, the List class does not 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 will be equal to Event.LIST_SELECT, and event.arg will be 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 other event types.
The applet in Listing 29.4 sets up a List containing several values and uses a label to inform you whenever an item is selected or deselected:
// Example 29.4 - 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 scrollingList; public void init() { // First, create the List scrollingList = new List(3, true); // Now add a few items to the list scrollingList.addItem("Moe"); scrollingList.addItem("Larry"); scrollingList.addItem("Curly"); scrollingList.addItem("Shemp"); scrollingList.addItem("Curly Joe"); // Set Shemp to be selected scrollingList.select(3); // Finally, add the list to the applet add(scrollingList); // Now create a label to show the last event that occurred listStatus = new Label("You selected entry Shemp"); add(listStatus); } public boolean handleEvent(Event evt) { String selectionString; Integer selection; // Since you are handling events in the applet itself, // you need to check to make sure the event is for the scrollingList. if (evt.target == scrollingList) { // Check to see if this is a selection event if (evt.id == Event.LIST_SELECT) { // selection is the index of the selected item selection = (Integer) evt.arg; // use getItem to get the actual item. selectionString = "You selected entry "+ scrollingList.getItem( selection.intValue()); // Update the label listStatus.setText(selectionString); } else if (evt.id == Event.LIST_DESELECT) { // If this is a deselection, get the deselected item // selection is the index of the selected item selection = (Integer) evt.arg; // use getItem to get the actual item. selectionString = "You deselected entry "+ scrollingList.getItem( selection.intValue()); // Update the label listStatus.setText(selectionString); } } return true; } }
Figure 29.8 shows the output from ListApplet.
FIG. 29.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 handles multiple lines. Both of these classes share many similar methods because both are derived from a common class called TextComponent.
The easiest way to create a text field is with the empty constructor:
public TextField()
The empty constructor will create 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:
public TextField(int numColumns)
Sometimes you may want to initialize the text field with some text when you create it:
public TextField(String initialText)
Rounding out these combinations is a method for creating a text field that is initialized with text and has a fixed number of columns:
public TextField(String initialText, int numColumns)
It should come as no surprise to you that the methods for creating 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 with an unspecified number of rows and columns by using the empty constructor:
public TextArea()
You can initialize an area that contains some text with:
public TextArea(String initialText)
You can give a text area a fixed number of rows and columns with:
public TextArea(int numRows, int numColumns)
Finally, you can create a text area that has some initial text and a fixed size with:
public TextArea(String initialText, int numRows, int numColumns)
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:
public void setText(String newText)
You will certainly want to find out what text is in the component. You can use getText to do that:
public String getText()
You can find out what text has been selected (highlighted with the mouse) by using getSelectedText:
public String getSelectedText()
You can also find out where the selection starts and ends. The getSelectionStart and getSelectionEnd methods return integers that indicate the position within the entire text where the selection starts and ends:
public int getSelectionStart() public int getSelectionEnd()
For instance, if the selection started at the very beginning of the text, 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:
public void select(int selectionStart, int selectionEnd)
If you want to select the entire text, you can use selectAll as a shortcut:
public void selectAll()
You can also use setEditable to control whether the text in the component can be edited (if not, it is read-only):
public void setEditable(boolean canBeEdited)
The isEditable method will return true if the component is editable or false if it is not:
public boolean isEditable()
Text fields have some features that text areas do not. The TextField class allows you to set an echo character that is printed instead of the character that was typed. Echo characters are useful when making fields for entering passwords where you might make `*' the echo character. That way, you don't see the password on the screen--only a line of asterisks. Setting up an echo character is as easy as calling setEchoCharacter:
public void setEchoChar(char ch)
One of the most common uses of setEchoChar would be printing *'s for a password. The following code fragment sets the echo character to an asterisk:
myTextField.setEchoCharacter(`*'); // Print *s in place of what was typed
You can find out the echo character for a field with getEchoChar:
public char getEchoChar()
The echoCharIsSet method will return true if an echo character is set for the field or false if not:
public boolean echoCharIsSet()
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:
public int getColumns()
Text areas also have their own special features. 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:
public void appendText(String textToAdd)
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:
public void insertText(String newText, int position)
You can also use replaceText to replace portions of the text:
public void replaceText(String str, int start, int end)
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:
public int getColumns() public int getRows()
Like the List class, 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 users to press when they have finished editing the text. Then you can use getText to retrieve the edited text.
The TextField class either generates an ActionEvent or uses the action method (depending on whether you're using the Java 1.1 or Java 1.0 event model) only when the user presses return. You may find this useful, but again, you could create a button for the user to signal that he or she finished entering the text (especially if a number of text fields must be filled out).
Listing 29.5 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:
import java.awt.*; import java.applet.*; // TextApplet // This applet creates some text fields and a text area // to demonstrate the features of each. // 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 29.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.
FIG. 29.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:
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 another. 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 must add code to detect when the scroll bar changes and update the canvas as needed.
You can create a simple vertical scroll bar with the empty constructor:
public Scrollbar()
You can also specify the orientation of the scroll bar as either Scrollbar.HORIZONTAL or Scrollbar.VERTICAL:
public Scrollbar(int orientation)
You can create a scroll bar with a predefined orientation, position, page increment, minimum value, and maximum value:
public Scrollbar(int orientation, int position, int pageIncrement, int minimum, int maximum)
The following code creates a vertical scroll bar with a minimum value of 0, a maximum value of 100, a page size of 10, and a starting position of 50:
Scrollbar myScrollbar = new Scrollbar(Scrollbar.VERTICAL, 50, 10, 0, 100);
You can set the scroll bar's line increment with setLineIncrement:
public void setLineIncrement(int increment)
You can query the current line increment with getLineIncrement:
public int getLineIncrement()
You can set the page increment with setPageIncrement:
public void setPageIncrement()
You can also query the page increment with getPageIncrement.
public int getPageIncrement()
You can find out the scroll bar's minimum and maximum position values with getMinimum and getMaximum:
public int getMinimum() public int getMaximum()
The setValue method sets the scroll bar's current position:
public void setValue()
You can query the current position with getValue:
public int getValue()
The getOrientation method will return Scrollbar.VERTICAL if the scroll bar is vertical, or Scrollbar.HORIZONTAL is returned if it is horizontal:
public int getOrientation()
You can also set the position, page increment, minimum value, and maximum value with setValues:
public void setValue(int position, int pageIncrement, int minimum, int maximum)
The following code sets the position to 75, the page increment to 25, the minimum value to 0, and the maximum value to 500:
myScrollbar.setValues(75, 25, 0, 500);
Under Java 1.1, the Scrollbar class generates AdjustmentEvents and sends them to an AdjustmentListener object. The lone method defined by the AdjustmentListener interface is adjustmentValueChanged:
public void adjustmentValueChanged(AdjustmentEvent event)
A scroll bar can change three ways--in single units, in block units, or by absolute positioning (tracking). A single unit adjustment occurs when you click the arrows at either end of the scroll bar. A block adjustment occurs when you click the area between an arrow and the slider. An absolute adjustment occurs when you draw the slider around.
The getAdjustmentType in the AdjustmentEvent object returns either AdjustmentEvent.UNIT_INCREMENT, AdjustmentEvent.UNIT_DECREMENT, AdjustmentEvent.BLOCK_INCREMENT, AdjustmentEvent.BLOCK_DECREMENT, or AdjustmentEvent.Track:
public int getAdjustmentType()
Like the List class, the Scrollbar class does not make use of the action method under the Java 1.0 event model. You must use the handleEvent method to determine when a scroll bar has moved. The possible values of evt.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. 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.
By default, a Canvas has no size. This is very inconvenient when you are using a layout manager that needs to have some idea of a component's required size. At the minimum, you should implement your own size method in a canvas. It is even nicer to implement minimumSize and preferredSize, also.
import java.awt.*; // Example 29.6 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. // 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) { int circleDiameter, circleX, circleY; Dimension currentSize = size(); // Use the smaller of the height and width of the canvas. // This guarantees that the circle will be drawn completely. if (currentSize.width < currentSize.height) { circleDiameter = currentSize.width; } else { circleDiameter = currentSize.height; } 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. circleX = (currentSize.width - circleDiameter) / 2; circleY = (currentSize.height - circleDiameter) / 2; g.fillOval(circleX, circleY, circleDiameter, circleDiameter); } }
The CircleCanvas is only a component, not a runnable applet. In the next chapter, in the section "Grid Bag Layouts," you use this new class in an example of using the GridBagLayout layout manager.
The Component class defines a large number of methods that are common to all AWT components and containers. Almost all of the methods deal with either displaying the component or receiving input events.
You can control many simple things in a component, such as the foreground and background colors, the font, and whether the component is even shown. The setForeground and setBackground methods change the foreground and background colors of the component:
public void setForeground(Color c) public void setBackground(Color c)
While setForeground and setBackground are defined for all components, they may not always work at the moment as advertised under some Java implementations. Many Java implementations actually rely on the underlying windowing system to draw the components, and they may not be able to change the foreground and background colors for components easily.
You can query the foreground and background colors of any component with getForeground and getBackground:
public Color getForeground() public Color getBackground()
The hide and show methods control whether or not a component is visible on the screen:
public void hide()
keeps a component from being displayed. The component still exists, however.
public void show()
makes a component display itself. This method is important for frames because they are hidden by default.
public void show(boolean showComponent)
If showComponent is true, the component is displayed. If showComponent is false, the component is hidden.
The setFont method changes a component's font. This method is only useful for components that display text:
public void setFont(Font f)
You can query a component's current font with getFont:
public Font getFont()
The Component class also gives you access to the font metrics for a font:
public FontMetrics getFontMetrics(Font font)
The size and position are usually dictated to a component by the layout manager. The component can return its preferred and minimum size, but the layout manager still makes the decision on the actual size. The layout manager also decides a component's position (its x and y coordinates). Once the layout manager decides the position and size of a component, it invokes methods in the component to resize and position it.
The minimumSize method returns the minimum width and height a component must be given, while preferredSize returns the preferred width and height:
public Dimension minimumSize() public Dimension preferredSize()
The size method returns a component's actual width and height:
public Dimension size()
The move method sets the x and y coordinates for the upper-left corner of the component's display area:
public void move(int x, int y)
These coordinates are relative to the parent component's space. For example, if
a component was moved to 0,0 and its parent was located on the screen at 100,150,
the component would really be drawn at 100,150. Figure 29.10 illustrates the relationship
between a component's coordinates, the parent's coordinates, and the real screen
coordinates.
FIG. 29.10
A component's coordinates are relative to its parent container.
If you want to query a component's position relative to its parent's display area, use the location method:
public Point location()
The locate method finds the component that contains a particular x,y point:
public Component locate(int x, int y)
If the point is not within this component, the locate method returns null. If the point is within this component and the component contains subcomponents, it looks for a child component that contains the point. If one is found, locate returns that component. If not, it returns the current component. Note that locate only searches one level deep into the children. Once you get a child component, you can repeat the search.
The following method finds the component on the screen that occupies a particular x,y coordinate. If locate returns a container, it searches through that container's components until it finds the correct component.
public Component findComponent(int x, int y) { // Find out which component this x,y is inside Component whichComp = locate(x, y); // If the component is a container, descend into the container and // find out which of its components contains this x,y while (whichComp instanceof Container) { // If you have to search within a container, adjust the x,y to be relative // to the container. x -= whichComp.location().x; y -= whichComp.location().y; Component nextComp = whichComp.locate(x, y); // if locate returns the component itself, we're done if (nextComp == whichComp) break; whichComp = nextComp; } return whichComp; }
You may already be familiar with the key methods for component rendering (drawing on the screen). They are repaint, update, and paint.
public void repaint()
requests that this image be repainted as soon as possible. This will result in an eventual call to update, but maybe not immediately.
public void repaint(int x, int y, int width, int height)
repaints only the portion of the component within the rectangle specified by the parameters.
public void repaint(long tm)
requests that the component be repainted within tm milliseconds.
public void repaint(long tm, int x, int y, int width, int height)
requests that a specific portion of the component be repainted within tm milliseconds.
public void update(Graphics g)
initiates a repaint of the component onto graphics context g. The default update method erases the graphics context and calls the paint method.
public void paint(Graphics g)
redraws the component onto graphics context g.
When components are laid out by a layout manager, they are marked as being valid. That is, they have been examined and laid out. If a component changes size or some other aspect that requires the current layout to be altered, the component can be marked invalid by the invalidate method:
public void invalidate()
Invalidating a component marks it as changed. The next time the validate method in the component or its parent is called, the component layout is performed again. The format of the validate method is:
public void validate()
The validate method also makes use of the layout method in each child component of this component:
public void layout()
The default layout method for a component does nothing. In a container, however, the layout method causes the layout manager to recompute the position of each contained component.
You can get a reference to the parent container of your component by using the getParent method:
public Container getParent()
You can get a reference to the parent frame of an applet by tracing back through the applet's parent containers until you find a frame. You can get unpredictable results this way, but sometimes you can have fun with it. The following loop tries to find an applet's parent frame:
Container parent = getParent(); // Trace back up getting parents until there // are no more parents or we hit a Frame // while ((parent != null) && !(parent instanceof Frame)) { parent = parent.getParent(); } // At this point, parent will either be null or it will // be the parent frame for the applet
As you saw in the previous chapter, the handleEvent method notifies a component of incoming input. The handleEvent method is actually part of longer chain of event handling methods.
public void deliverEvent(Event evt)
sends an event to this component. This is the initial entry point for an event in the event- handling chain. This method passes the event on to the postEvent method.
public boolean postEvent(Event evt)
passes the event on to the handleEvent method. If the handleEvent method returns false, this method passes the event on to the parent component using the parent's postEvent method. If postEvent returns true, the event has been handled successfully.
public boolean handleEvent(Event evt)
examines the event and calls one of the following methods based on the event type: mouseEnter, mouseExit, mouseMove, mouseDrag, mouseDown, mouseUp, keyDown, keyUp, action, gotFocus, lostFocus.
You can keep a component from receiving input events by disabling it with the disable method:
public void disable()
To enable it again, call the enable method:
public void enable()
The isEnabled method will return true if a component is enabled:
public boolean isEnabled()