Chapter 11

The AWT Class Library


CONTENTS


This chapter covers the classes and interfaces of the Abstract Windowing Toolkit (AWT). Here you'll learn how the AWT classes and interfaces are used to create the graphical user interface (GUI) of applets and stand-alone applications. The listings in this chapter are sample programs that illustrate the use of these GUI components. When you are finished with this chapter, you will be able to use the AWT classes and interfaces in your own Java applets and applications.

Introduction to the AWT

The classes and interfaces of the Abstract Windowing Toolkit (AWT) are used to develop stand-alone applications and to implement the GUI controls used by applets. These classes support all aspects of GUI development, including event handling.

The Component and Container classes are two of the most important classes in the java.awt package. The Component class provides a common superclass for all classes that implement GUI controls. The Container class is a subclass of the Component class and can contain other AWT components. It is well worth your while to familiarize yourself with the API description of these two classes.

The Window class is a subclass of the Container class that provides a common set of methods for implementing windows. The Window class has two subclasses, Frame and Dialog, that are used to create Window objects. The Frame class is used to create a main application window, and the Dialog class is used to implement dialog boxes. Let's explore the Frame class first and then look at the Dialog class.

Using the Frame Class to Implement Application Windows

The Frame class is a subclass of Window that encapsulates an application window. A Frame object is capable of containing a menu bar and displaying a title. Listing 11.1 shows how a Frame object is used to implement a simple window program.


Listing 11.1. The FrameExample program.
import java.awt.*;

public class FrameExample extends Frame {
public static void main(String args[]){
  FrameExample win = new FrameExample();
}
public FrameExample() {
  super("FrameExample");
  pack();
  resize(400,400);
  show();
}
public void paint(Graphics g) {
  g.drawString("A Basic Window Program",100,100);
}
public boolean handleEvent(Event event) {
  if(event.id==Event.WINDOW_DESTROY){
   System.exit(0);
   return true;
  }else return false;
}
}

After you create a Frame object within an application, you use the show() method to display the frame. The show() method is inherited from the Window class. Other methods used in the initial display of a Frame object are the pack() and resize() methods. The pack() method, like the show() method, is inherited from the Window class. It organizes the components contained in a Window object and determines the Window object's size. The resize() method is inherited from the Component class. It is used to resize a Window object to a particular dimension.

This small program introduces the basic structure of stand-alone applications. The main class of the program subclasses the Frame class and creates a single main() method like those used in console programs. The main() method uses the FrameExample() constructor to create a window for an application.

The FrameExample() constructor uses the superclass constructor to set the title of the window to FrameExample. The pack() method is typically used to pack the components of the window, which allows Java to organize the component objects on the window. The resize() method is invoked to resize the window to 400 pixels by 400 pixels. Finally, the show() method is invoked to cause the window to be displayed.

The paint() method is invoked by the runtime system to initially paint the contents of the application window and to repaint the window if it is moved, resized, or covered. The paint() method is passed an object of the Graphics class as a parameter. This object is used to update the window's display by drawing on its default canvas. The paint() method of FrameExample draws the text A Basic Window Program at the coordinates (100,100).

The handleEvent() method usually provides the primary event handling for AWT components. A handleEvent() method is typically provided with a program's Frame subclass. The handleEvent() method of FrameExample looks for a WINDOW_DESTROY event and shuts down the program using the exit() method of the System class. The Event class is covered in the section titled "Handling Events in Programs That Use Windows."

Figure 11.1 shows the window initially displayed by the FrameExample program.

Figure 11.1 : The FrameExample program's initial display.

Using Menus and Menu Bars

The MenuBar class provides an implementation of the menu bar commonly attached to stand-alone applications. It is a subclass of the MenuComponent class, which provides a common set of methods for all menu-related classes. You attach a MenuBar object to a Frame object using the setMenuBar() method of the Frame class.

A MenuBar object contains one or more Menu objects that implement pull-down menus. The Menu class provides methods for adding MenuItem objects and separators to the pull-down menu implemented by a Menu object. It also provides methods for accessing the MenuItem objects contained in a Menu object. Because the Menu class is a subclass of the MenuItem class, a Menu object can contain another Menu object, thus allowing multiple levels of cascading menus to be created. The program shown in Listing 11.2 illustrates this concept.


Listing 11.2. The MenuExample program.
import java.awt.*;

public class MenuExample extends Frame {
 String menuSelection = "Select a menu item.";
 public static void main(String args[]){
  MenuExample win = new MenuExample();
 }
 public MenuExample() {
  super("MenuExample");
  pack();
  resize(400,400);
  addMenus();
  show();
 }
 void addMenus() {
  MenuBar menubar = new MenuBar();
  Menu file = new Menu("File");
  Menu edit = new Menu("Edit");
  Menu view = new Menu("View");
  file.add("Open");
  file.add("Save");
  file.add("Close");
  file.add("Quit");
  edit.add("Copy");
  edit.add("Cut");
  edit.add("Paste");
  view.add("Zoom");
  menubar.add(file);
  menubar.add(edit);
  menubar.add(view);
  setMenuBar(menubar);
 }
 public void paint(Graphics g) {
  g.drawString(menuSelection,100,100);
 }
 public boolean handleEvent(Event event) {
  if(event.id==Event.WINDOW_DESTROY){
   System.exit(0);
   return true;
  }else if(event.id == Event.ACTION_EVENT &&
    event.target instanceof MenuItem){
   if("Quit".equals(event.arg)){
    System.exit(0);
    return true;
   }else{
    menuSelection = "You selected "+event.arg.toString()+".";
    repaint();
    return true;
   }
  }else return false;
 }
}

The MenuItem class is a subclass of the MenuComponent class that is used to implement an item contained in a pull-down menu. It provides methods for enabling and disabling (graying out) the label associated with a MenuItem object and for setting and retrieving the label. The MenuItem class has two subclasses-Menu and CheckboxMenuItem. You have already been introduced to the Menu class; the CheckboxMenuItem class implements a menu item that can be checked or unchecked and provides methods that can be used to set and retrieve its checked status. To learn more about check boxes, see the section "Check Boxes and Radio Buttons."

The MenuComponent class is the superclass of these menu classes. Its methods are used to perform general menu-related operations, such as those used to create menu items.

The MenuContainer interface defines those methods that must be implemented by any class that contains a menu-related object. The MenuContainer interface is implemented by the Frame, Menu, and MenuBar classes.

The MenuExample program follows the same general structure as the FrameExample program shown in Listing 11.1. It invokes the addMenus() method in the MenuExample() constructor to set up the window's menus. Notice that the menuSelection variable is a String object and is declared as a field variable of the MenuExample class.

The addMenus() method creates a MenuBar object and some Menu objects and then adds menu items to the Menu objects. The Menu objects are then added to the MenuBar object, and the MenuBar object is set on the application window using the setMenuBar() method.

The paint() method is overridden to draw the menu item selected by the user on the window's default canvas. Note that you generally don't call the paint() method directly. The paint() method is invoked automatically when you use these methods: show(), repaint(), or update().

The handleEvent()method of the FrameExample program is expanded to check for an ACTION_EVENT object with a MenuItem as its target in order to handle the action of a user selecting an item from a menu. It updates the menuSelection object to identify the menu item selected by the user. The repaint() method is used to cause the window to be redrawn, which, as discussed, invokes the paint() method for you.

Figure 11.2 shows the window initially displayed by the MenuExample program.

Figure 11.2 : The MenuExample program's initial display.

Handling Events in Programs That Use Windows

The Event class is central to the Java window event-generation and -handling mechanism. Event objects are generated by a user who interacts with a Java window program or applet and by the Java runtime system. User-generated events occur when users make selections on a menu or press a key. Events generated by the runtime system include errors and exceptions. They are handled by a set of predefined event-handling methods that are defined by the Component class and its subclasses. These methods are overridden to perform custom event processing.

The Event class defines numerous constants to identify the events that are defined for the AWT classes. It is important that you review these constants to become familiar with the types of events that may need to be handled by your programs. You'll become aware of the common event handling performed for the various window components by working through the example programs in this chapter.

Implementing Dialog Boxes with the Dialog Class

The Dialog class, like the Frame class, is a subclass of the Window class. Whereas the Frame class is used to implement a main application window, the Dialog class is used to implement dialog boxes that pop up to present information and interact with the user of a window program or applet. Two types of Dialog objects can be created. A modal dialog box is a Dialog object that must be acted on and closed before a user is able to access other application windows. A non-modal dialog box does not have this restriction.

The program shown in Listing 11.3 illustrates the use of the Dialog class.


Listing 11.3. The DialogExample program.
import java.awt.*;

public class DialogExample extends Frame {
 Dialog dialog;
 public static void main(String args[]){
  DialogExample win = new DialogExample();
 }
 public DialogExample() {
  super("DialogExample");
  pack();
  resize(400,400);
  addMenus();
  createDialog();
  show();
 }
 void addMenus() {
  MenuBar menubar = new MenuBar();
  Menu file = new Menu("File");
  Menu dialog = new Menu("Dialog");
  file.add("Quit");
  dialog.add("Show");
  dialog.add("Hide");
  menubar.add(file);
  menubar.add(dialog);
  setMenuBar(menubar);
 }
 void createDialog() {
  dialog = new Dialog(this,"Dialog Box",false);
  dialog.resize(200,200);
 }
 public boolean handleEvent(Event event) {
  if(event.id==Event.WINDOW_DESTROY){
   System.exit(0);
   return true;
  }else if(event.id == Event.ACTION_EVENT &&
    event.target instanceof MenuItem){
   if("Quit".equals(event.arg)){
    System.exit(0);
    return true;
   }else if("Show".equals(event.arg)){
    dialog.show();
    return true;
   }else{
    dialog.hide();
    return true;
   }
  }else return false;
 }
}

The DialogExample program follows the same structure as the FrameExample and MenuExample programs. It creates the dialog variable to refer to a dialog box that it creates and displays. The createDialog() method is invoked from the DialogExample constructor to create this dialog box.

The addMenus() method has been updated to support menu items for showing and hiding the dialog box.

The createDialog() method creates a non-modal dialog box and resizes it to a 200 pixel ¥ 200 pixel size. The dialog box is not displayed until the Show menu item is selected and handled by the handleEvent() method.

The handleEvent() method handles the Show menu item by causing the dialog box to be displayed via the show() method of the Window class. It handles the Hide menu item by invoking the hide() method of the Component class.

Note
The show() method of the Window class overrides the show() method of the Component class and is used to display Window objects. Unlike the show() method of the Component class, the show() method of the Window class does more than merely display the window; it will also bring the window to the front if the window is already visible.

Figure 11.3 shows the window initially displayed by the DialogExample program.

Figure 11.3 : The DialogExample porgram's initial display.

Using the FileDialog Class to Access the Local File System

The FileDialog class is a subclass of the Dialog class and is used to provide the capability to select a file from a directory listing. The FileDialog class provides the capability to use separate dialog boxes for loading and saving files.

The program shown in Listing 11.4 illustrates the use of the FileDialog class.


Listing 11.4. The FileDialogExample program.
import java.awt.*;

public class FileDialogExample extends Frame {
 FileDialog dialog;
 public static void main(String args[]){
  FileDialogExample win = new FileDialogExample();
 }
 public FileDialogExample() {
  super("FileDialogExample");
  pack();
  resize(400,400);
  addMenus();
  createDialog();
  show();
 }
 void addMenus() {
  MenuBar menubar = new MenuBar();
  Menu file = new Menu("File");
  Menu dialog = new Menu("Dialog");
  file.add("Quit");
  dialog.add("Show");
  menubar.add(file);
  menubar.add(dialog);
  setMenuBar(menubar);
 }
 void createDialog() {
  dialog = new FileDialog(this,"File Dialog Box");
 }
 public boolean handleEvent(Event event) {
  if(event.id==Event.WINDOW_DESTROY){
   System.exit(0);
   return true;
  }else if(event.id == Event.ACTION_EVENT &&
    event.target instanceof MenuItem){
   if("Quit".equals(event.arg)){
    System.exit(0);
    return true;
   }else if("Show".equals(event.arg)){
    dialog.show();
    return true;
   }else{
    return false;
   }
  }else return false;
 }
}

The FileDialogExample program is very similar to the DialogExample program except that instead of creating and displaying a Dialog object, it displays a FileDialog object. Notice that the Hide menu item has been removed. This is because the File dialog box is modal and cannot be hidden after it is displayed.

The createDialog() method creates the FileDialog object and titles it with the text File Dialog Box.

Figure 11.4 shows the window initially displayed by the FileDialogExample program.

Figure 11.4 : The FileDialogExample program's initial display.

Organizing Components Using the Panel and Layout Classes

This section discusses the AWT classes that are used to organize components within applications and applets.

The Panel class is the most common class for organizing components within stand-alone applications. It is a subclass of the Container class and is displayed as a panel within a window. It inherits almost all of its methods from its Container and Component superclasses. The program shown in Listing 11.5 illustrates the use of the Panel class.

Note
The Applet class is a subclass of the Panel class that is used to implement a panel within a Web browser's display window. It adds many useful methods that provide access to the capabilities of the browser.


Listing 11.5. The PanelExample program.
import java.awt.*;

public class PanelExample extends Frame {
public static void main(String args[]){
  PanelExample win = new PanelExample();
}
public PanelExample() {
  super("PanelExample");
  pack();
  resize(400,400);
  addMenus();
  addPanel();
  show();
}
void addMenus() {
  MenuBar menubar = new MenuBar();
  Menu file = new Menu("File");
  file.add("Quit");
  menubar.add(file);
  setMenuBar(menubar);
}
void addPanel() {
  Panel panel = new Panel();
  panel.add(new Button("one"));
  panel.add(new Button("two"));
  panel.add(new Button("three"));
  panel.add(new Button("four"));
  panel.add(new Button("five"));
  add("South",panel);
}
public boolean handleEvent(Event event) {
  if(event.id==Event.WINDOW_DESTROY){
   System.exit(0);
   return true;
  }else if(event.id == Event.ACTION_EVENT &&
    event.target instanceof MenuItem){
   if("Quit".equals(event.arg)){
    System.exit(0);
    return true;
   }else{
    return false;
   }
  }else return false;
}
}

The PanelExample program follows the same structure of the programs you've studied so far in this chapter. It invokes the addPanel() method from its constructor to add a Panel object that contains Button objects. No event handling is provided for the buttons, so when you click on them, nothing happens. Buttons and button-related event handling is covered in the section "Labels and Buttons." It is included here to show how components can be added to a panel and then added to the main application window.

Figure 11.5 shows the window initially displayed by the PanelExample program.

Figure 11.5 : The PanelExample program's initial display.

The LayoutManager interface defines methods that must be implemented by classes that are used to organize the way Component objects are laid out in a Container object. Five AWT classes implement this interface: BorderLayout, CardLayout, FlowLayout, GridBagLayout, and GridLayout. These classes are used to lay out objects that are instances of the Container class and its subclasses in the following manner:

The GridBagConstraints class is used to create objects that specify the size and positioning of an object that is controlled by a GridBagLayout object.

Note
The Insets class provides the capability to add margins to the layout and can be used with the GridBagConstraints class.

The program shown in Listing 11.6 illustrates the use of the five layout classes.


Listing 11.6. The LayoutExample program.
import java.awt.*;

public class LayoutExample extends Frame {
public static void main(String args[]){
  LayoutExample win = new LayoutExample();
}
public LayoutExample() {
  super("LayoutExample");
  addMenus();
  addPanels();
  pack();
  resize(600,600);
  show();
}
void addMenus() {
  MenuBar menubar = new MenuBar();
  Menu file = new Menu("File");
  file.add("Quit");
  menubar.add(file);
  setMenuBar(menubar);
}
void addPanels() {
  setLayout(new GridLayout(3,2));
  Panel flow = new Panel();
  Panel border = new Panel();
  Panel card = new Panel();
  Panel grid = new Panel();
  Panel gridbag = new Panel();
  border.setLayout(new BorderLayout());
  card.setLayout(new CardLayout());
  grid.setLayout(new GridLayout(2,2));
  gridbag.setLayout(new GridBagLayout());
  addButtons(flow);
  addButtons(card);
  addButtons(border);
  addButtons(grid);
  addButtons(gridbag);
  add(flow);
  add(card);
  add(border);
  add(grid);
  add(gridbag);
}
void addButtons(Panel panel){
  if(panel.getLayout() instanceof BorderLayout) {
   panel.add("North",new Button("one"));
   panel.add("East",new Button("two"));
   panel.add("South",new Button("three"));
   panel.add("West",new Button("four"));
  }else if(panel.getLayout() instanceof GridBagLayout) {
   GridBagLayout layout = (GridBagLayout) panel.getLayout();
   GridBagConstraints constraint1 = new GridBagConstraints();
   constraint1.fill = GridBagConstraints.BOTH;
   constraint1.gridwidth = 1;
   constraint1.gridheight = 1;
   constraint1.gridx = 0;
   constraint1.gridy = 0;
   GridBagConstraints constraint2 = new GridBagConstraints();
   constraint2.fill = GridBagConstraints.BOTH;
   constraint2.gridwidth = 2;
   constraint2.gridheight = 1;
   constraint2.gridx = 1;
   constraint2.gridy = 0;
   GridBagConstraints constraint3 = new GridBagConstraints();
   constraint3.fill = GridBagConstraints.BOTH;
   constraint3.gridwidth = 2;
   constraint3.gridheight = 1;
   constraint3.gridx = 0;
   constraint3.gridy = 1;
   GridBagConstraints constraint4 = new GridBagConstraints();
   constraint4.fill = GridBagConstraints.BOTH;
   constraint4.gridwidth = 1;
   constraint4.gridheight = 1;
   constraint4.gridx = 2;
   constraint4.gridy = 1;
   Button button1 = new Button("one");
   Button button2 = new Button("two");
   Button button3 = new Button("three");
   Button button4 = new Button("four");
   layout.setConstraints(button1,constraint1);
   panel.add(button1);
   layout.setConstraints(button2,constraint2);
   panel.add(button2);
   layout.setConstraints(button3,constraint3);
   panel.add(button3);
   layout.setConstraints(button4,constraint4);
   panel.add(button4);
  }else{
   panel.add(new Button("one"));
   panel.add(new Button("two"));
   panel.add(new Button("three"));
   panel.add(new Button("four"));
  }
}
public boolean handleEvent(Event event) {
  if(event.id==Event.WINDOW_DESTROY){
   System.exit(0);
   return true;
  }else if(event.id == Event.ACTION_EVENT &&
    event.target instanceof MenuItem){
   if("Quit".equals(event.arg)){
    System.exit(0);
    return true;
   }else{
    return false;
   }
  }else return false;
 }
}

The LayoutExample program is twice as long as the programs you've looked at so far in this chapter because it performs quite a bit more setup in order to display panels that illustrate each of the five layout classes.

In this program, the addPanels() method sets the layout of the application window to a three-row by two-column grid. Five panels illustrating the five layout classes are added to this grid.

The addButtons() method is used to add buttons to the panels to show how each of the five different layouts causes the buttons to be displayed. Buttons are laid out along the edges and center of a BorderLayout object. A GridBagLayout object is laid out using GridBagConstraints objects. The field variables of these objects are updated to specify the position, size, and fill mode of the buttons that are added to the GridBagLayout object. The buttons added to Panel objects using the other layouts do not require any special setup.

Figure 11.6 shows the window initially displayed by the LayoutExample program.

Figure 11.6 : The LayoutExample program's initial display.

Using Common GUI Controls

This section introduces the common GUI controls provided by the AWT and shows how to handle the events associated with these controls. The controls covered are provided by the Label, Button, Checkbox, Choice, List, TextField, and TextArea classes. Other GUI controls are discussed later in this chapter.

Labels and Buttons

The Label class is used to display a line of read-only text. It provides methods to set and retrieve the text of a Label object and to align the text within the object's display.

The Button class provides the capability to use buttons within Java applications and applets. Button objects are labeled with a text string; using images with buttons is not currently supported by Java. The clicking of a button results in an Event object that is identified as an ACTION_EVENT object. The program shown in Listing 11.7 illustrates the use of the Label and Button classes.


Listing 11.7. The ButtonExample program.
import java.awt.*;

public class ButtonExample extends Frame {
 Label label = new Label("Default Text");
 public static void main(String args[]){
  ButtonExample win = new ButtonExample();
 }
 public ButtonExample() {
  super("ButtonExample");
  addMenus();
  addButtons();
  pack();
  resize(400,400);
  show();
 }
 void addMenus() {
  MenuBar menubar = new MenuBar();
  Menu file = new Menu("File");
  file.add("Quit");
  menubar.add(file);
  setMenuBar(menubar);
 }
 void addButtons() {
  add("North",label);
  label.setAlignment(Label.CENTER);
  Panel panel = new Panel();
  panel.add(new Button("one"));
  panel.add(new Button("two"));
  panel.add(new Button("three"));
  panel.add(new Button("four"));
  add("Center",panel);
}
public boolean handleEvent(Event event) {
  if(event.id==Event.WINDOW_DESTROY){
   System.exit(0);
   return true;
  }else if(event.id == Event.ACTION_EVENT &&
    event.target instanceof MenuItem){
   if("Quit".equals(event.arg)){
    System.exit(0);
    return true;
   }else{
    return false;
   }
  }else if(event.id == Event.ACTION_EVENT &&
    event.target instanceof Button){
   label.setText((String) event.arg);
   return true;
  }else return false;
 }
}

The ButtonExample program illustrates the use of the Button and Label classes by displaying the label of the last button clicked by a user using a Label object. The Label object is initially labeled with the string Default Text upon program startup. The addButtons() method is invoked from within the ButtonExample constructor to set up the Label and Button objects.

The handleEvent() method checks for ACTION_EVENT events with a Button target to handle the user's button clicks. It handles the event by setting the Label object to the label of the button that was clicked.

Figure 11.7 shows the window initially displayed by the ButtonExample program.

Figure 11.7 : The ButtonExample program's initial display.

Check Boxes and Radio Buttons

The Checkbox class provides the capability to implement radio buttons as well as check boxes. The CheckboxGroup class is used to group Checkbox objects and identify that they should be treated as radio buttons instead of as check boxes.

The Checkbox class provides methods for retrieving and modifying its checked state and label. The checking and unchecking of a check box or radio button causes an ACTION_EVENT Event object to be generated.

The program shown in Listing 11.8 illustrates the use of check boxes and radio buttons.


Listing 11.8. The CheckboxExample program.
import java.awt.*;

public class CheckboxExample extends Frame {
 Label label = new Label("Default Text");
 Checkbox checkbox[] = new Checkbox[6];
 public static void main(String args[]){
  CheckboxExample win = new CheckboxExample();
 }
 public CheckboxExample() {
  super("CheckboxExample");
  addMenus();
  addComponents();
  pack();
  resize(400,400);
  show();
 }
 void addMenus() {
  MenuBar menubar = new MenuBar();
  Menu file = new Menu("File");
  file.add("Quit");
  menubar.add(file);
  setMenuBar(menubar);
 }
 void addComponents() {
  add("North",label);
  label.setAlignment(Label.CENTER);
  Panel panel = new Panel();
  Panel panel1 = new Panel();
  panel1.setLayout(new GridLayout(3,1));
  Panel panel2 = new Panel();
  panel2.setLayout(new GridLayout(3,1));
  checkbox[0] = new Checkbox("one");
  checkbox[1] = new Checkbox("two");
  checkbox[2] = new Checkbox("three");
  CheckboxGroup group = new CheckboxGroup();
  checkbox[3] = new Checkbox("four",group,false);
  checkbox[4] = new Checkbox("five",group,false);
  checkbox[5] = new Checkbox("six",group,false);
  for(int i=0;i<3;++i) panel1.add(checkbox[i]);
  for(int i=3;i<6;++i) panel2.add(checkbox[i]);
  panel.add(panel1);
  panel.add(panel2);
  add("Center",panel);
}
public boolean handleEvent(Event event) {
  if(event.id==Event.WINDOW_DESTROY){
   System.exit(0);
   return true;
  }else if(event.id == Event.ACTION_EVENT &&
    event.target instanceof MenuItem){
   if("Quit".equals(event.arg)){
    System.exit(0);
    return true;
   }else{
    return false;
   }
  }else if(event.id == Event.ACTION_EVENT &&
    event.target instanceof Checkbox){
   String text = "";
   for(int i=0;i<6;++i) {
    if(checkbox[i].getState()) text += checkbox[i].getLabel() + " ";
   }
   label.setText(text);
   return true;
  }else return false;
 }
}

The CheckboxExample program displays the results of user check box and radio button clicks by updating the text displayed by a Label object.

The checkbox[] array is used to store both check boxes and radio buttons. The addComponents() method is invoked by the CheckboxExample() constructor to add the check boxes and radio buttons to the application window.

The addComponents() method places the Label object to be updated in the top center of the application window. It then creates three Panel objects, two of which are placed on the third Panel object. Both of the second-level panels are set up using the grid-style layout with one column and three rows. The three check boxes are placed in one panel, and the three radio buttons are placed in the other. A CheckboxGroup object is used to organize the radio buttons into a common CheckboxGroup object.

The ACTION_EVENT event associated with a user checking on a check box is handled by determining which check boxes and radio buttons are checked and displaying their labels using the Label object at the top of the window. Play around with the program to see how check boxes are treated differently than radio buttons.

Figure 11.8 shows the window initially displayed by the CheckboxExample program.

Figure 11.8 : The CheckboxExample program's initial display.

Choices and Lists

The Choice class implements a list of choices from which a single choice may be selected. Its methods provide the capability to update the list and query its status.

The List class implements lists from which a single or multiple selections may be made. Its methods provide the capability to update the elements of a list and query their selection status. The program shown in Listing 11.9 illustrates the use of the Choice and List classes.


Listing 11.9. The ListExample program.
import java.awt.*;

public class ListExample extends Frame {
 Label label = new Label("Default Text");
 Choice choice = new Choice();
 List list = new List(3,true);
 public static void main(String args[]){
  ListExample win = new ListExample();
 }
 public ListExample() {
  super("ListExample");
  addMenus();
  addComponents();
  pack();
  resize(400,400);
  show();
 }
 void addMenus() {
  MenuBar menubar = new MenuBar();
  Menu file = new Menu("File");
  file.add("Quit");
  menubar.add(file);
  setMenuBar(menubar);
 }
 void addComponents() {
  add("North",label);
  label.setAlignment(Label.CENTER);
  Panel panel = new Panel();
  Panel panel1 = new Panel();
  Panel panel2 = new Panel();
  try {
   choice.addItem("one");
   choice.addItem("two");
   choice.addItem("three");
  } catch (NullPointerException ex) {
  }
  panel1.add(choice);
  list.addItem("four");
  list.addItem("five");
  list.addItem("six");
  list.addItem("seven");
  list.addItem("eight");
  panel2.add(list);
  panel.add(panel1);
  panel.add(panel2);
  add("Center",panel);
}
public boolean handleEvent(Event event) {
  if(event.id==Event.WINDOW_DESTROY){
   System.exit(0);
   return true;
  }else if(event.id == Event.ACTION_EVENT &&
    event.target instanceof MenuItem){
   if("Quit".equals(event.arg)){
    System.exit(0);
    return true;
   }else{
    return false;
   }
  }else if(event.target instanceof Choice ||
     event.target instanceof List){
   String text = choice.getSelectedItem() + " ";
   for(int i=0;i<5;++i) {
    if(list.isSelected(i)) text += list.getItem(i) + " ";
   }
   label.setText(text);
   return true;
  }else return false;
 }
}

The ListExample program illustrates the similarities and differences between the Choice and List classes. The label, list, and choice variables are used to provide access to their related GUI components. These field variables are created and initialized in the beginning of the class description.

The addComponents() method adds a Label object at the top of the window and then creates three panels. The panel variable refers to the main Panel object and is added to the center of the application window. The panel1 and panel2 variables refer to Panel objects that are placed on the left and right sides of the area covered by the main panel. A Choice object is created and added to the left panel, and a List object is created and added to the right panel.

The handleEvent() method is updated to check for events related to the Choice or List classes and updates the Label object with the user's selections.

Figure 11.9 shows the window initially displayed by the ListExample program.

Figure 11.9 : The ListExample program's initial display.

Text Fields and Text Areas

The TextField class provides the capability to enter a single line of text. To allow users to enter password information without revealing the password to onlookers, you can use the TextField class, which allows you to set an alternate character to display instead of the actual text. The alternate characters are used only to mask the characters and do not affect the actual data entered. Most programs set the echo character to an asterisk. To set an alternate character, you use the setEchoCharacter() method.

The TextArea class provides the capability to enter multiple lines of text. It provides horizontal and vertical scrollbars to scroll the text that is entered.

The TextComponent class is the superclass of the TextField and TextArea classes and provides several methods that are common to both of these classes. The setEditable()method allows TextField and TextArea objects to be defined as read-only.

The program shown in Listing 11.10 illustrates the use of the TextField and TextArea classes.


Listing 11.10. The TextExample program.
import java.awt.*;

public class TextExample extends Frame {
 TextField textfield = new TextField("Enter text here.");
 TextArea textarea = new TextArea("And it will be inserted here!");
 public static void main(String args[]){
  TextExample win = new TextExample();
 }
 public TextExample() {
  super("TextExample");
  addMenus();
  addComponents();
  pack();
  resize(400,400);
  show();
 }
 void addMenus() {
  MenuBar menubar = new MenuBar();
  Menu file = new Menu("File");
  file.add("Quit");
  menubar.add(file);
  setMenuBar(menubar);
 }
 void addComponents() {
  add("North",textfield);
  add("Center",textarea);
}
public boolean handleEvent(Event event) {
  if(event.id==Event.WINDOW_DESTROY){
   System.exit(0);
   return true;
  }else if(event.id == Event.ACTION_EVENT &&
    event.target instanceof MenuItem){
   if("Quit".equals(event.arg)){
    System.exit(0);
    return true;
   }else{
    return false;
   }
  }else if(event.id == Event.ACTION_EVENT &&
     event.target instanceof TextField){
   textarea.insertText(textfield.getText()+"\n",0);
   return true;
  }else return false;
 }
}

The TextExample program creates a TextField object and a TextArea object and displays them in the North and Center regions of the application window. When the user enters text into the TextField object and presses the Enter key, the text is inserted at the beginning of the TextArea object.

The TextExample class creates and initializes the TextField and TextArea objects. Notice how the initial text to be displayed in these fields is specified in their respective constructors.

The handleEvent() method checks for an action event that is identified as a TextField object, and then updates the TextArea object with the text contained in the TextField object. The getText() method of the TextComponent class is used to retrieve the user's text from the TextField object. The insertText()method of the TextArea class is then used to insert this text at the beginning of the TextArea object.

Figure 11.10 shows the window initially displayed by the TextExample program.

Figure 11.10 : The TextExample program's initial display.

Drawing with the Canvas and Graphics Classes

The Canvas class provides the capability to display a Graphics object within a window area. The paint() method of the Graphics class is used to update the Graphics object associated with a Canvas object. The Graphics class is an abstract class that provides numerous methods for drawing objects and displaying images. Access to a Graphics object is provided via the paint() method of the Canvas and Component classes. The program shown in Listing 11.11 illustrates the use of the Canvas and Graphics classes.


Listing 11.11. The GraphicsExample program.
import java.awt.*;

public class GraphicsExample extends Frame {
 LeftCanvas lcanvas = new LeftCanvas();
 RightCanvas rcanvas = new RightCanvas();
 public static void main(String args[]){
  GraphicsExample win = new GraphicsExample();
 }
 public GraphicsExample() {
  super("GraphicsExample");
  addMenus();
  addComponents();
  pack();
  resize(200,200);
  show();
 }
 void addMenus() {
  MenuBar menubar = new MenuBar();
  Menu file = new Menu("File");
  file.add("Quit");
  menubar.add(file);
  setMenuBar(menubar);
 }
 void addComponents() {
  setLayout(new GridLayout(1,2));
  add(lcanvas);
  add(rcanvas);
 }
 public void paint(Graphics g) {
  lcanvas.repaint();
  rcanvas.repaint();
 }
 public boolean handleEvent(Event event) {
  if(event.id==Event.WINDOW_DESTROY){
   System.exit(0);
   return true;
  }else if(event.id == Event.ACTION_EVENT &&
    event.target instanceof MenuItem){
   if("Quit".equals(event.arg)){
    System.exit(0);
    return true;
   }else{
    return false;
   }
  }else return false;
 }
}

class LeftCanvas extends Canvas {
 public LeftCanvas() {
  super();
 }
 public void paint(Graphics g) {
  g.setColor(Color.red);
  g.fillOval(10,10,50,50);
 }
}

class RightCanvas extends Canvas {
 public RightCanvas() {
  super();
 }
 public void paint(Graphics g) {
  g.setColor(Color.blue);
  g.fillRect(10,10,50,50);
 }
}

The GraphicsExample program declares two subclasses of the Canvas class: LeftCanvas and RightCanvas. An object from each of these classes is created and added to the main application window. The layout of the GraphicsExample window is set to a one-row by two-column GridLayout object. This accomplishes the same results as using multiple panels as you saw in the previous examples in this chapter. The paint() method of the GraphicsExample class is defined to invoke the repaint() methods of the LeftCanvas and RightCanvas objects, which causes these objects to update their respective screen areas.

The LeftCanvas class extends the Canvas class and uses the setColor() and fillOval()methods of the Graphics class to draw a red oval in the Graphics object associated with the canvas.

The RightCanvas class is defined in a manner similar to the LeftCanvas class. It draws a blue rectangle instead of a red oval.

Figure 11.11 shows the window initially displayed by the GraphicsExample program.

Figure 11.11 : The GraphicsExample program's initial display.

Geometrical Classes

The AWT provides the Point, Rectangle, Polygon, and Dimension classes to support geometrical operations. The Point class encapsulates a point in a two-dimensional plane. The Rectangle class represents a rectangle by its upper-left corner and its height and width dimensions. The Polygon class represents a polygon as an array of its x coordinates and an array of its y coordinates. The
Dimension class encapsulates the dimensions of a two-dimensional object. The program shown in Listing 11.12 illustrates the use of these classes.


Listing 11.12. The GeometryExample program.
import java.awt.*;

public class GeometryExample extends Frame {
 Point p1 = new Point(0,0);
 Point p2 = new Point(100,100);
 Dimension dim = new Dimension(50,50);
 Rectangle rect = new Rectangle(p2,dim);
 int xcoord[] = {150,275,300,350,290,250,200,150};
 int ycoord[] = {150,125,50,150,175,250,350,150};
 Polygon poly = new Polygon(xcoord,ycoord,xcoord.length);
 public static void main(String args[]){
  GeometryExample win = new GeometryExample();
 }
 public GeometryExample() {
  super("GeometryExample");
  addMenus();
  pack();
  resize(400,400);
  show();
 }
 void addMenus() {
  MenuBar menubar = new MenuBar();
  Menu file = new Menu("File");
  file.add("Quit");
  menubar.add(file);
  setMenuBar(menubar);
 }
 public void paint(Graphics g) {
  g.drawLine(p1.x,p1.y,p2.x,p2.y);
  g.drawRect(rect.x,rect.y,rect.width,rect.height);
  g.drawPolygon(poly);
 }
 public boolean handleEvent(Event event) {
  if(event.id==Event.WINDOW_DESTROY){
   System.exit(0);
   return true;
  }else if(event.id == Event.ACTION_EVENT &&
    event.target instanceof MenuItem){
   if("Quit".equals(event.arg)){
    System.exit(0);
    return true;
   }else{
    return false;
   }
  }else return false;
 }
}

The GeometryExample class creates several geometrical objects in the class declaration. Two Point objects are created and assigned to the p1 and p2 variables. A 50 pixel ¥ 50 pixel Dimension object is created and assigned to the dim variable. A Rectangle object is created using the Point object referenced by the p2 and dim variables and assigned to the rect variable. A Polygon object is then created with vertices at the points (150,150), (275,125), (300,50), (350,150), (290,175), (250,250), and (200,350).

The paint() method is overridden to draw the geometrical objects on the Graphics object of the application window's default canvas. It draws a line from p1 to p2, the Rectangle object specified by rect, and the Polygon object specified by poly.

Figure 11.12 shows the window initially displayed by the GeometryExample program.

Figure 11.12 : The GeometryExample program's initial display.

Using Fonts

The Font class encapsulates fonts in a system-independent manner by defining several system-independent fonts that are mapped to the fonts supported by the local operating and windowing system. This class also defines constants that allow a Font object to be displayed using a plain, bold, italic, or bold-italic style.

The FontMetrics class encapsulates the size parameters of a Font object. It provides several methods that return the pixel width of characters and character strings, as well as methods that return the height, ascent, descent, and leading pixel length of a Font object. The ascent and descent values measure the number of pixels that a Font object ascends above and descends below its baseline. The leading of a Font object is the minimum distance between the ascent of one line of text and ascent of the following line of text. The height of a Font object is the sum of its ascent, descent, and leading.

The program shown in Listing 11.13 shows how the Font and FontMetrics classes are used.


Listing 11.13. The FontExample program.
import java.awt.*;

public class FontExample extends Frame {
 public static void main(String args[]){
  FontExample win = new FontExample();
 }
 public FontExample() {
  super("FontExample");
  addMenus();
  pack();
  resize(150,400);
  show();
 }
 void addMenus() {
  MenuBar menubar = new MenuBar();
  Menu file = new Menu("File");
  file.add("Quit");
  menubar.add(file);
  setMenuBar(menubar);
 }
 public void paint(Graphics g) {
  Font font = new Font("Helvetica",Font.BOLD+Font.ITALIC,24);
  g.setFont(font);
  FontMetrics metrics = g.getFontMetrics(font);
  int ascent = metrics.getAscent();
  int height = metrics.getHeight();
  int leading = metrics.getLeading();
  int baseline = leading + ascent;
  for(int i=0;i<10;++i) {
   g.drawString("Line "+String.valueOf(i),10,baseline);
   baseline += height;
  }
 }
 public boolean handleEvent(Event event) {
  if(event.id==Event.WINDOW_DESTROY){
   System.exit(0);
   return true;
  }else if(event.id == Event.ACTION_EVENT &&
    event.target instanceof MenuItem){
   if("Quit".equals(event.arg)){
    System.exit(0);
    return true;
   }else{
    return false;
   }
  }else return false;
 }
}

The FontExample program creates a 24-point, bold, italic, Helvetica Font object and uses the FontMetrics object associated with this font to draw text on the window's default Graphics object.

Most of the processing is performed in the overridden paint() method. It creates the Font object and uses the getFontMetrics() method of the Graphics class to get the FontMetrics object associated with the font. It then retrieves the ascent, height, and leading parameters of the font via the FontMetrics object.

The baseline variable is used to keep track of the vertical coordinate of where a line of text should be displayed. The distance between subsequent baselines is the height metric of the font.

Ten lines of text are displayed to show how all of these methods come together to draw text on a Graphics object.

Figure 11.13 shows the window initially displayed by the FontExample program.

Figure 11.13 : The FontExample program's initial display.

Image-related Classes

The Image and Color classes encapsulate graphical images and colors in a format-independent manner. The classes and interfaces of the java.awt.image package are used to implement image processing applications. The ImageProducer interface defines the methods that are implemented by classes that produce image data. The ImageConsumer interface defines methods that are used by classes that use image data. The ImageObserver interface defines constants and methods that are used to monitor the loading of an image.

The ColorModel, DirectColorModel, and IndexColorModel classes are used to implement portable color models. The FilteredImageSource, ImageFilter, RGBImageFilter, and CropImageFilter classes provide the capability to implement image-filtering algorithms. The PixelGrabber and MemoryImageSource classes are used to capture an image to a memory array and to generate an image from a memory array. The MediaTracker class provides the capability to track the loading of a list of images.

The program shown in Listing 11.14 illustrates the use of some of the image-related classes introduced in this section.


Listing 11.14. The ImageExample program.
import java.awt.*;

public class ImageExample extends Frame {
 Image image;
 public static void main(String args[]){
  ImageExample win = new ImageExample();
 }
 public ImageExample() {
  super("ImageExample");
  addMenus();
  loadImage();
  pack();
  resize(400,400);
  show();
 }
 void addMenus() {
  MenuBar menubar = new MenuBar();
  Menu file = new Menu("File");
  file.add("Quit");
  menubar.add(file);
  setMenuBar(menubar);
 }
 void loadImage() {
  Toolkit toolkit = getToolkit();
  image = toolkit.getImage("test.gif");
 }
 public void paint(Graphics g) {
  g.drawImage(image,0,0,this);
 }
 public boolean handleEvent(Event event) {
  if(event.id==Event.WINDOW_DESTROY){
   System.exit(0);
   return true;
  }else if(event.id == Event.ACTION_EVENT &&
    event.target instanceof MenuItem){
   if("Quit".equals(event.arg)){
    System.exit(0);
    return true;
   }else{
    return false;
   }
  }else return false;
 }
}

The ImageExample program loads the test.gif file and displays it on the default Graphics object of the application window.

The loadImage() method gets the default Toolkit object of the application window and uses the getImage() method of the Tookit class to load the test.gif file into the Image object referenced by the image variable. The Toolkit class is covered in the section "The Toolkit Class and the Native Platform Window Implementation."

The paint() method performs the actual drawing of the image on the screen. You will probably notice some flickering of the image while it is being displayed. This occurs because the program is trying to display the image at the same time that it is loading it, much like the image display of a Web browser. The example in the next section shows you how to use the MediaTracker class to avoid this problem.

Figure 11.14 shows the window initially displayed by the ImageExample program.

Figure 11.14 : The ImageExample program's initial display.

Using Scrollbars

Scrollbars provide the capability to scroll an object that is too large to fit in a window. Both vertical and horizontal scrollbars are supported by the AWT. Vertical scrollbars scroll an object up and down in a window, and horizontal scrollbars scroll an object left and right. Both types of scrollbars are implemented via the Scrollbar class.

Scrollbars generate events based on user interaction. A user can click on the end of a scrollbar to generate a SCROLL_LINE_UP or SCROLL_LINE_DOWN event, click between the scrollbar's tab and the end of the scrollbar to generate a SCROLL_PAGE_UP or SCROLL_PAGE_DOWN event, or move the scrollbar's tab with the mouse to generate the SCROLL_ABSOLUTE event.

Scrollbars are defined by their orientation, value, visible, minimum, and maximum parameters. The orientation parameter specifies whether a scrollbar is horizontal or vertical. The minimum and
maximum parameters specify the minimum and maximum values associated with a scrollbar. The value parameter specifies the current value of a scrollbar. The visible parameter specifies the visible size of the area to be scrolled.

The program shown in Listing 11.15 illustrates the use of the Scrollbar class.


Listing 11.15. The ScrollbarExample program.
import java.awt.*;

public class ScrollbarExample extends Frame {
 Image image;
 Scrollbar horiz = new Scrollbar(Scrollbar.HORIZONTAL,0,400,0,500);
 Scrollbar vert = new Scrollbar(Scrollbar.VERTICAL,0,400,0,500);
 public static void main(String args[]){
  ScrollbarExample win = new ScrollbarExample();
 }
 public ScrollbarExample() {
  super("ScrollbarExample");
  addMenus();
  loadImage();
  add("South",horiz);
  add("East",vert);
  pack();
  resize(400,400);
  show();
 }
 void addMenus() {
  MenuBar menubar = new MenuBar();
  Menu file = new Menu("File");
  file.add("Quit");
  menubar.add(file);
  setMenuBar(menubar);
 }
 void loadImage() {
  Toolkit toolkit = getToolkit();
  image = toolkit.getImage("bigtest.gif");
  MediaTracker tracker = new MediaTracker(this);
  tracker.addImage(image,7);
  try {
   tracker.waitForID(7);
  } catch(InterruptedException ex) {
  }
 }
 public void paint(Graphics g) {
  g.drawImage(image,0-horiz.getValue(),0-vert.getValue(),this);
 }
 public boolean handleEvent(Event event) {
  if(event.id==Event.WINDOW_DESTROY){
   System.exit(0);
   return true;
  }else if(event.id == Event.ACTION_EVENT &&
    event.target instanceof MenuItem){
   if("Quit".equals(event.arg)){
    System.exit(0);
    return true;
   }else{
    return false;
   }
  }else if(event.target instanceof Scrollbar) {
    repaint();
    return true;
  }else return false;
 }
}

The ScrollbarExample program loads and displays a GIF image that is too large to fit in the application window. It uses scrollbars to allow the user to scroll through the image's display. The image is contained in the bigtest.gif file.

The horizontal and vertical scrollbars are created at the beginning of the class's declaration. These scrollbars are assigned to the horiz and vert variables. The handleEvent() method is updated to look for any scrollbar-related events and invokes the repaint() method to cause the screen to be redrawn in response to these events.

The paint()method is overridden to redisplay the loaded image based on the current values of the scrollbars. The getValue() method of the Scrollbar class is used to retrieve these values.

The loadImage()method uses a MediaTracker object to cause the program to wait for an image to be loaded before performing further processing.

Figure 11.15 shows the window initially displayed by the ScrollbarExample program.

Figure 11.15 : The ScrollbarExample program's initial display.

The Toolkit Class and the Native Platform Window Implementation

The Toolkit class provides access to the native platform window implementation via the peer interfaces of the java.awt.peer package. It also provides methods that return the parameters associated with the screen display.

The program shown in Listing 11.16 illustrates the use of the Toolkit class.


Listing 11.16. The ToolkitExample program.
import java.awt.*;

public class ToolkitExample extends Frame {
 public static void main(String args[]){
  ToolkitExample win = new ToolkitExample();
 }
 public ToolkitExample() {
  super("ToolkitExample");
  addMenus();
  TextField textfield = new TextField();
  add("South",textfield);
  Toolkit toolkit = getToolkit();
  int resolution = toolkit.getScreenResolution();
  Dimension dim = toolkit.getScreenSize();
  String text = "Screen Resolution (in dots per inch): "+
   String.valueOf(resolution);
  text += ", Screen Size: "+dim.width+"x"+dim.height;
  textfield.setText(text);
  pack();
  resize(400,200);
  show();
 }
 void addMenus() {
  MenuBar menubar = new MenuBar();
  Menu file = new Menu("File");
  file.add("Quit");
  menubar.add(file);
  setMenuBar(menubar);
 }
 public boolean handleEvent(Event event) {
  if(event.id==Event.WINDOW_DESTROY){
   System.exit(0);
   return true;
  }else if(event.id == Event.ACTION_EVENT &&
    event.target instanceof MenuItem){
   if("Quit".equals(event.arg)){
    System.exit(0);
    return true;
   }else{
    return false;
   }
  }else return false;
 }
}

The ToolkitExample program illustrates the use of the getScreenResolution() and getScreenSize() methods of the Toolkit class. The ToolkitExample constructor uses these methods to retrieve the dots-per-inch screen resolution and display size associated with your computer's display. These parameters are then displayed via a TextField object.

Figure 11.16 shows the window initially displayed by the ToolkitExample program.

Figure 11.16 : The ToolkitExample program's initial display.

Summary

In this chapter you have learned about the classes and interfaces of the Abstract Windowing Toolkit. You have learned how the AWT classes and interfaces are used in applets and stand-alone applications and have examined several programming examples. You should now be able to use the AWT classes and interfaces in your own Java applets and programs.