Java 1.2 Unleashed

Contents


- 9 -

Creating Window Applications


In Part II, "Applet Programming," you learned to write applets. While applets are Java's claim to fame, they are only one aspect of Java's software development capabilities. In this chapter, you'll learn to develop full-blown window applications using Java. You'll learn about the differences between applications and applets, how to open and organize windows, and how to work with menus and dialog boxes. You'll also learn how to use the new Accessibility API of JDK 1.2. When you have finished this chapter, you will know how to write platform-independent window programs using Java.

Differences Between Applications and Applets

Applets are Java programs that execute within the context of a Web page. They interact with the user while his Web page is active and stop their execution when his Web page is no longer active. Applets are valuable because they are simple to use. A user only needs to open an applet's Web page to download and execute an applet.

Most of the programs that we are accustomed to using are standalone or networked application programs. A standalone application is a program that executes using the resources of a single computer. A networked application is an application that uses resources that are available over a network. A distributed application is an application that consists of objects that execute across multiple computers. You'll learn how to develop networked applications in Part VIII, "Network Programming," and distributed applications in Part IX, "Developing Distributed Applications."

Standalone applications consist of window applications and console applications. Window applications are programs that make use of a windowing system, such as those supported by Microsoft Windows, the Macintosh OS, Motif, and OS/2. Console programs are character-based programs, such as those supported by DOS and UNIX shells.

Window applications are introduced in this chapter, and console applications are covered in the following chapter. However, you'll see examples of both types of applications throughout the remainder of this book. Window applications have an advantage over applets in that they are given more security privileges by default. Among other things, they are allowed to read and write to the local file system, establish network connections to multiple hosts, and launch other programs. Applets have an advantage over applications in their ease of installation and use. The great thing about both applications and applets is that they share the same GUI controls. This means that all the GUI programming skills that you learned for applets carry over to applications.

Because window applications execute separately from a Web page, they must perform additional functions like opening and closing windows, setting up and implementing menu bars, and working with dialog boxes. These are the skills that you'll learn in this chapter.


NOTE: The JDK 1.2 security model allows applications to be restricted in their behavior and applets to be given greater privileges. However, the model defaults to giving applications more privileges than applets. Refer to Chapter 3, "The Extended Java Security Model."

Designing Window Programs

The design of most window programs usually involves two basic steps: laying out the program's graphical user interface, and providing the functionality that implements the interface.

The first step addresses one of the most important features of window programs--their look and feel. Window programs are preferred to console programs when their look and feel are interesting, innovative, and help the user to accomplish a particular purpose.

A program's look consists of all those characteristics that determine its appearance, such as window size, layout, background and foreground colors, menus, and GUI controls. A program's feel is determined by the availability of easy-to-use GUI controls and the contribution of these controls to the program's ultimate intended use. It is the result of the designer's selection and implementation of GUI controls that enhance a program's capability to satisfy user expectations.

The window's GUI design begins by creating an application window, using the Frame class, and determining the basic characteristics of the window, such as its size, title, background and foreground colors, and general layout. Next, a menu bar is added to the window and the program's menus and menu items are added to the menu bar. The GUI controls that are to be used in the window are determined, designed, and attached to the window's panels and frame.

At this point, you know what your program will look like and you can concentrate on what it will do. The first step in bringing your program's user interface to life is to add the event-handling software required to respond to events that are generated through user interaction. The event-handling software will not immediately implement all user actions, but it should respond to them and provide hooks for the eventual implementation of all user interface actions. The event-handling software is then fleshed out to provide all the functionality required of the application program. The program's design and implementation reaches an Alpha stage when all required user-interface functions have been implemented.

The next stage of program development is to refine and test the program to make it more responsive to its intended purpose. A series of Beta versions of the program are developed that implement user feedback and fix any identified errors or deficiencies. Finally, the program is refined to handle unusual user inputs and to process errors and exceptions.

Figure 9.1 provides an overview of the process of designing and implementing window programs.

FIGURE 9.1. The process for window design and implementation.

Window Classes

The Window class provides an encapsulation of a generic Window object. It is subclassed by Frame and Dialog to provide the capabilities needed to support application main windows and dialog box support.

The Window class contains a single constructor that creates a window that has a frame window as its parent. The parent frame window is necessary because only objects of the Frame class or its subclasses contain the functionality needed to implement an independent application window.

The Window class implements important methods that are used by its Frame and Dialog subclasses. The pack() method is used to arrange the components contained in the window according to the window layout style. The show() method is used to display a window. Windows are hidden (invisible) by default, and are only displayed as a result of invoking their show() method. The toFront() and toBack()methods are used to position windows relative to their frame window. The dispose()method is used to release the resources associated with a window and delete the Window object. The getWarningString() method is used to retrieve the warning message associated with untrusted windows. Warning messages are associated with windows that are created by applets.

A Window object does not have a border or a menubar when it is created. In this state, it may be used to implement a pop-up window. The default layout for a Window object is BorderLayout.

Frame

The Frame class is used to provide the main window of an application. It is a subclass of Window that supports the capabilities to specify a window icon, cursor, menu bar, and title. Because it implements the MenuContainer interface, it is capable of working with MenuBar objects. You'll learn about menus later in this chapter in the section "Constructing Menus."

The Frame class defines several constants that are used to specify different types of cursors to be used within the frame. As of JDK 1.1, a separate Cursor class is available for working with cursors.

Frame provides two constructors: a default parameterless constructor that creates an untitled frame window, and a constructor that accepts a String argument to be used as the frame window's title. The second constructor is typically used.

Frame extends the set of access methods that it inherits from Window by adding methods to get and set the window title, icon image, and menu bar. Methods for removing the menu bar and specifying whether the window is resizable are also provided.

Dialog

The Dialog class is a subclass of the Window class that is used to implement dialog box windows. A dialog box is a window that takes input from the user. The Dialog class allows dialog boxes to be constructed that are modal. Modal dialog boxes must be closed before control returns to the window that launched them. The Dialog class also provides the capability to construct non-modal dialog boxes that do not need to be closed before other program windows can be accessed.

The Dialog class provides four constructors. These constructors allow the Window object containing the dialog box to be specified, as well as the modal flag and the dialog box's title.

The Dialog class provides only a handful of access methods. These methods are used to get and set the dialog box's title, determine whether it is modal, and get and set its resizable properties.

FileDialog

The FileDialog class is used to construct dialog boxes that support the selection of files for input and output operations. It is a subset of the Dialog class and provides three constructors. These constructors take as arguments the Frame window that contains the dialog box, the title to be used at the top of the dialog box, and a mode parameter that can be set to the LOAD or SAVE constants defined by FileDialog.

FileDialog provides methods that are used to access the directory and filename of the user-selected file and to specify an object that implements the FileNameFilter interface.

Opening and Closing Windows

The opening and closing of windows marks the beginning and end of any window program. The Frame class enables these fundamental window operations to be accomplished. A Frame object implements an application main window, inheriting many methods from the Window, Container, and Component classes.

To open an application window, a Frame object is created and its show() method is invoked. The show() method is inherited from the Window class. To close an application window, the window closing event must be handled. The window is disposed of by using the dispose() method of the Window class, or more commonly by invoking the System.exit() method after performing any necessary program-termination processing.

The Frame class and its ancestors provide a number of methods that control the way in which a window is displayed. The setBackground() and setForeground() methods inherited from the Component class are used to specify a window's background and foreground colors. The setFont() method, also inherited from Component, is used to specify the default font to be used with a window. The Frame class itself provides a number of methods that control a window's appearance. The setTitle() method allows a window's title to be changed, the setMenuBar() method enables a menu bar to be attached to a window, and the setResizable() method toggles whether a window can or cannot be resized. The setIconImage() method allows the window's minimized icon to be changed. This method is not supported by all Java implementations, and therefore should be avoided if cross-platform compatibility is a concern.

Hello Windows!

Now that you've covered the basic classes involved in opening and closing windows, we'll create a simple window application that illustrates the use of these classes.

Traditionally, the first program that programmers write when learning a new programming language is one that displays the text "Hello World!" to the console window. The main purpose of the program is to show you how to develop a simple program that actually produces some noticeable effect. The same rationale applies to the HelloWindows program, shown in Listing 9.1. This program shows you how to open an application window and write the text "Hello Windows!" to the window.

LISTING 9.1. THE HelloWindows PROGRAM.

import java.awt.*;

import java.awt.event.*;

public class HelloWindows extends Frame {

 public static void main(String args[]){

  HelloWindows app = new HelloWindows();

 }

 public HelloWindows() {



super("Hello Windows!");

  setSize(200,200);

  addWindowListener(new HelloWindows.WindowEventHandler());

  show();

 }

 public void paint(Graphics g) {

  g.drawString("Hello Windows!",50,90);

 }

 class WindowEventHandler extends WindowAdapter {

  public void windowClosing(WindowEvent e){

   System.exit(0);

  }

 }

}

When you compile and run the program, it opens a small window in the upper-left corner of your desktop and displays the text "Hello Windows!" in the middle of the window. Figure 9.2 shows the window displayed by the HelloWindows program.

FIGURE 9.2. The HelloWindows program display.

Let's take a look at HelloWindows to find out what makes it work. You should notice that we import classes from the java.awt and java.awt.event packages. The Frame, Graphics, and WindowAdapter classes are the primary classes that are imported. The Frame and Graphics classes are fundamental to developing window programs. The Frame class is used to create Frame objects that implement application main windows, and the Graphics class is used to update the screen display. The WindowAdapter class is used to process user-generated window events, such as closing the window.

The HelloWindows class extends the Frame class. This is a typical approach to developing window programs. By subclassing Frame, your application class implements a main application window. You still use the same old main() method for implementing the entry point to your program. In HelloWindows, the main() method simply creates an object of class HelloWindows.

The HelloWindows constructor uses the super() constructor call statement to invoke the Frame constructor with the string "Hello Windows!". The Frame constructor creates a new application window frame with the specified text as its title. The setSize() method sets the size of the window to 200¥200 pixels. The setSize() method is inherited from the Component class by way of the Container, Window, and Frame classes. The addWindowListener() method is invoked to associate window-related events with a newly created object of class WindowEventHandler. Finally, the show() method causes the window to be displayed. It is inherited from the Window class.

When the window is initially displayed or redisplayed as the result of being uncovered or brought to the foreground, the paint() method is invoked. It paints the window according to the current application state.

The paint() method used by HelloWindows overrides the paint() method inherited from the Component class. It uses the drawString() method to display the text "Hello Windows!" at the screen coordinates (50,90) within the application window.

Window coordinates are organized in the same way they are for applets, with the upper-left corner of the window being (0,0). The coordinates of the upper-right corner of the window are (width,0), where width is the horizontal width of the window in pixels. The coordinates of the lower-left corner of the window are (0,height), where height is the vertical height of the window in pixels. Finally, the coordinates of the lower-right corner of the window are (width,height).

The WindowEventHandler class subclasses the WindowAdapter class of java.awt.event to handle the event associated with the window's closing. This event occurs when the user closes the main application window using the capabilities that are provided by the native windowing system. In Microsoft Windows 95 and 98, this occurs when you click on the little "`x"' in the upper-right corner of the window.

The window-closing event is handled by invoking the exit() method of the System class to terminate the program. You might be wondering what would happen if the windowClosing() method did not handle the window closing event. Try deleting the line with the System.exit(0) method invocation, recompiling, and rerunning HelloWindows to see what happens when you try to terminate the application. Your program will no longer terminate when you attempt to close it.

Constructing Menus

Java provides a rich set of menu-related classes for creating and interacting with pull-down menus. The MenuComponent class is the superclass of all menu-related classes. It extends the Object class. The getFont()and setFont()methods are the most useful methods provided by MenuComponent. Its two direct superclasses, MenuBar and MenuItem, provide most of the methods for creating and using menus. The CheckboxMenuItem class extends the MenuItem class and supports menu items that can be checked on or off. The Menu class extends the MenuItem class and implements a collection of MenuItem objects that can be assigned to a MenuBar object. The PopupMenu class extends the Menu class to provide a menu that can be popped up inside a component to enable user menu selections. Finally, the MenuShortcut class can be used to create a keyboard shortcut to a menu item.

A Frame object can have one and only one MenuBar object, which is set using the setMenuBar() method. A menu bar is a collection of menus, each one represented as a separate pull-down menu. Common examples are the File, Edit, and Help pull-down menus found in many window applications. The MenuBar class allows a special menu to be designated as a Help menu, but this feature is not implemented in Windows 95 or NT. It is implemented by Solaris and other flavors of UNIX, however.

A Menu object contains one or more MenuItem objects, which can be a normal user- selectable MenuItem object, a CheckboxMenuItem object, or another Menu object. Java supports tear-off menus, which are menus that can be removed from a menu bar. A tear-off menu is constructed in the same manner as a regular menu--you only need to set the Boolean tear-off value in the Menu() constructor. Tear-off menus are not implemented within Windows 95 or NT, but they are implemented in Solaris and other UNIX derivatives.

The MenuItem class is the superclass of the Menu class. This allows a menu to be a menu item and is used to construct cascading, multilevel menus. MenuItem is also the superclass of the CheckboxMenuItem class and provides the capability to implement menu items that can be checked or unchecked. If a MenuItem object is constructed directly with the MenuItem constructor, it becomes a normal menu item that is selected from a pull-down menu.

The MyMenu Class

The creation and organization of menu bars, menus, and menu items into a program's menu is a straightforward but tedious process. You have to create a menu bar, create and add menus to the menu bar, add menu items to the menus, and then add the menu bar to the program's application window. This usually involves the use of a large number of constructors and access methods. To illustrate the use of the menu-related classes and to simplify the menu-creation process, you'll create two classes, MyMenu and MyMenuBar, that can be used to quickly construct menus for Java programs. These classes implement multiple levels of menus, check box menu items, and menu-disabling options. The special Help menu and tear-off menus are not implemented, however, because they are transparent to Windows 95 and NT.


NOTE: In Chapter 13, "Working with Swing Components," you'll learn about the menu classes provided by Swing. Swing's menu classes, unlike the AWT menu classes, are subclasses of the java.awt.Component class. The MyMenu and MyMenuBar classes can be easily tailored to support Swing.

The MyMenu class is used to construct menus using an array of objects consisting of String objects that represent menu labels, or arrays of objects that represent submenus. Menu labels can be either check box menu items or normal menu items, and can be either initially enabled or disabled (grayed out). Check box menu items can be initially checked or unchecked. The first character of the label's text string is used to indicate which type of label it is. The character conventions are as follows:

+ A check box menu item that is initially checked and enabled.
# A check box menu item that is initially checked and disabled.
- A check box menu item that is initially unchecked and enabled. If the label consists of just -, it indicates a separator.
= A check box menu item that is initially unchecked and disabled.
~ A normal menu item that is initially disabled.

Any other character indicates a normal, enabled menu item. If the first character is !, it is ignored. This allows any menu item to begin with any character.

These conventions apply to menu options. Only the ~ and ! options are used with the menu's main label. Using these options greatly simplifies the process of creating a menu. The source code for the MyMenu class is shown in Listing 9.2.

LISTING 9.2. THE MyMenu CLASS.

package ju.ch09;

import java.awt.*;

import java.awt.event.*;

public class MyMenu extends Menu {

 public MyMenu(Object labels[],ActionListener al,ItemListener il) {

  super((String)labels[0]);

  String menuName = (String) labels[0];

  char firstMenuChar = menuName.charAt(0);

  if(firstMenuChar == `~' || firstMenuChar =='!'){

   setLabel(menuName.substring(1));

   if(firstMenuChar == `~') setEnabled(false);

  }

  for(int i=1;i<labels.length;++i) {

   if(labels[i] instanceof String){

if("-".equals(labels[i])) addSeparator();

    else{

     String label = (String)labels[i];

     char firstChar = label.charAt(0);

     switch(firstChar){

     case `+':

      CheckboxMenuItem checkboxItem = new CheckboxMenuItem(label.substring(1));

      checkboxItem.setState(true);

      add(checkboxItem);

      checkboxItem.addItemListener(il);

      break;

     case `#':

      checkboxItem = new CheckboxMenuItem(label.substring(1));

      checkboxItem.setState(true);

      checkboxItem.setEnabled(false);

      add(checkboxItem);

      checkboxItem.addItemListener(il);

      break;

     case `-': 

      checkboxItem = new CheckboxMenuItem(label.substring(1));

      checkboxItem.setState(false);

      add(checkboxItem); 

      checkboxItem.addItemListener(il);

      break;

     case `=':

      checkboxItem = new CheckboxMenuItem(label.substring(1));

      checkboxItem.setState(false);

      checkboxItem.setEnabled(false);

      add(checkboxItem); 

      checkboxItem.addItemListener(il);

      break;

     case `~':

      MenuItem menuItem = new MenuItem(label.substring(1));

      menuItem.setEnabled(false);

      add(menuItem);

      menuItem.addActionListener(al);

      break;

     case `!':

      menuItem = new MenuItem(label.substring(1));

      add(menuItem);

      menuItem.addActionListener(al);

      break;

     default:

      menuItem = new MenuItem(label);

      add(menuItem);

      menuItem.addActionListener(al);

     }

    }

   }else{

    add(new MyMenu((Object[])labels[i],al,il));

   }

  }

 }

 public MenuItem getItem(String menuItem) {

  int numItems = getItemCount();

  for(int i=0;i<numItems;++i)

   if(menuItem.equals(getItem(i).getLabel())) return getItem(i);

  return null;

 }

}

The MyMenu class specifies that it is in the package ju.ch09. Make sure that you place it in the ju/ch09 directory and compile it. You'll be using it in subsequent chapters.

MyMenu contains no field variables. It consists of a single constructor and the getItem()access method. The getItem() method retrieves a menu item that's contained in the menu and based on the menu item's label. It uses the getItemCount() and getItem() methods of the Menu class to retrieve the menu items contained in a menu, and the getLabel() method of the MenuItem class to match a menu item with the search string.

The MyMenu constructor constructs a menu from an array of menu labels and nested menu arrays (representing submenus). It also takes ActionListener and ItemListener objects as arguments. These objects are set up as the event handlers for the regular and check box items of the menu. For example, to construct a typical File menu, labeled File, with the New and Open menu items followed by a separator and an Exit menu item, you would use the following MyMenu constructor:

String fileMenuLabels[] = {"File","New","Open","-","Exit"};

// EventHandler must implement the ActionListener and ItemListener Âinterfaces.

EventHandler eh = new EventHandler();

MyMenu fileMenu = new MyMenu(fileLabelMenus,eh,eh);

The first object in the array must be a String object that is the main label associated with the menu. The following objects are String objects identifying the labels of the menu items contained in the menu, separators, or second-level arrays representing submenus. For example, the following creates a multilevel menu:

String goMenuLabels[] = {"Go","Beginning","End","Previous","Next"};

String editMenuLabels[] = {"Edit","Copy","Cut","-","Paste","-", ÂgoMenuLabels};

// EventHandler must implement the ActionListener and ItemListener Âinterfaces.

EventHandler eh = new EventHandler();

MyMenu editLabel = new MyMenu(editMenuLabels,eh,eh);

Using the MyMenu class is much easier than constructing each of the individual menu items and adding them to a menu.

Let's step through the MyMenu constructor to see how it works. It uses the super() class constructor call statement to construct a Menu object using the first label in the labels array. This label may contain either the ~ or ! character as the first character. MyMenu() checks for these characters and readjusts the menu's label accordingly. If the first character of the menu's label is ~, MyMenu() will disable the entire menu using the setEnabled() method of the MenuItem class.

After setting up the menu's main label, MyMenu() iterates through the list of objects contained in labels. If the object is an instance of the String class and is therefore a label, MyMenu() checks the first letter of the label and processes it accordingly. If the object is not an instance of the String class, MyMenu() calls itself again, passing the object to itself as another array of objects. It then adds the resulting MyMenu object to itself using the add() method of the Menu class. This allows submenus to be processed in a recursive fashion.

MyMenu() processes the menu item labels by using a switch statement to check the first character of the label to see if it matches the +, #, -, =, ~, or ! character. If it does not match any of these characters, the label is added as a normal menu item. If the label equals -, a separator is added.

If the first character is +, an enabled and checked CheckboxMenuItem object is added to the menu. The setState() method of the CheckboxMenuItem class is used to set the state of the menu item to be checked. If the first character is #, a checked, but disabled, CheckboxMenuItem object is added. The setEnabled() method of the MenuItem class is used to disable the menu item. The cases in which the first character of the label is - or = are processed in a similar manner, except that the CheckboxMenuItem object is initially unchecked.

When the first character of the label is ~, a normal MenuItem object is added to the menu. The menu item is disabled.

The ! character is an escape character that is used to create a normal menu item beginning with any of the special characters previously mentioned. When the first character of a label is !, the actual label generated begins with the subsequent character.

The MyMenuBar Class

The MyMenuBar class uses the MyMenu class presented in the previous section to quickly create an entire menu bar. Whereas the MyMenu class uses an array of labels and submenus to create a menu, the MyMenuBar class uses an array of these arrays to create the entire menu bar. For example, the following statements will construct a menu bar with File, Edit, and Help menus, each consisting of individual menu items:

String menuBarLabels[] = {

 {"File","New","Open","-","~Save As","-","Exit"};

 {"Edit","Copy","Cut","-","~Paste"};

 {"Help","Index"};

};

// EventHandler must implement the ActionListener and ItemListener Âinterfaces.

EventHandler eh = new EventHandler();

MyMenuBar menuBar = new MyMenuBar(menuBarLabels,eh,eh);

Note that the Save As and Paste menu items are initially disabled.

The source code of the MyMenuBar class is shown in Listing 9.3.

LISTING 9.3. THE MyMenuBar CLASS.

package ju.ch09;

import java.awt.*;

import java.awt.event.*;

public class MyMenuBar extends MenuBar {

 public MyMenuBar(Object labels[][],ActionListener al, 

   ItemListener il) {

  super();

  for(int i=0;i<labels.length;++i)

   add(new MyMenu(labels[i],al,il));

 }

 public MyMenu getMenu(String menuName) {

  int numMenus = getMenuCount();

  for(int i=0;i<numMenus;++i)

   if(menuName.equals(getMenu(i).getLabel())) return((MyMenu)getMenu(i));

  return null;

 }

}

The MyMenuBar constructor simply iterates through the outer array and passes the first-level elements (which are themselves Object arrays) to the MyMenu constructor. The MyMenu objects are then added to the MyMenuBar object being constructed using the add() method inherited from the MenuBar class.

The getMenu() method retrieves a MyMenu object from a MyMenuBar object based on the label associated with the MyMenu object. It uses the getMenuCount() and getMenu() methods of the MenuBar class to retrieve each MyMenu object contained in the menu bar. The getLabel() method of the MenuItem class is used to check the labels of the MyMenu objects against the search string.

The MenuApp Program

The MenuApp program illustrates the use of the MyMenuBar and MyMenu classes. Its source code is shown in Listing 9.4.

LISTING 9.4. THE MenuApp PROGRAM.

import java.awt.*;

import java.awt.event.*;

import ju.ch09.MyMenu;

import ju.ch09.MyMenuBar;

public class MenuApp extends Frame {

 MyMenuBar menuBar;

 MenuApp.EventHandler eh = new MenuApp.EventHandler();

 public static void main(String args[]){

  MenuApp app = new MenuApp();

 }

 public MenuApp() {

  super("Menu Madness");

  setup();

  setSize(400,400);

  addWindowListener(eh);

  show();

 }

 void setup() {

  setBackground(Color.white);

  setupMenuBar();

 }

 void setupMenuBar(){

  String gotoMenu[] = {"Go To","Beginning","End","-","Line Number"};

  Object menuItems[][] = {

   {"File","New","Open","-","~Save","~Save As","-","Exit"},

   {"Edit","Copy","Cut","-","~Paste"},

   {"Search","Find","~Find Next","~Find Previous","-", gotoMenu},

   {"View","-Hex","+Line Number","+Column Number"},

   {"Help","About Menu Madness"},

  };

  menuBar = new MyMenuBar(menuItems,eh,eh);

  setMenuBar(menuBar);

 }

 class EventHandler extends WindowAdapter implements ActionListener,

   ItemListener {

  public void actionPerformed(ActionEvent e){

   String selection=e.getActionCommand();

if("Exit".equals(selection)){
    System.exit(0); 

   }else if("New".equals(selection) || "Open".equals(selection)){

    menuBar.getMenu("File").getItem("Save").setEnabled(true);

    menuBar.getMenu("File").getItem("Save As").setEnabled(true);

   }else if("Copy".equals(selection) || "Cut".equals(selection)){

    menuBar.getMenu("Edit").getItem("Paste").setEnabled(true);

   }else if("Find".equals(selection)){

    menuBar.getMenu("Search").getItem("Find Next").setEnabled(true);

    menuBar.getMenu("Search").getItem("Find Previous").setEnabled(true);

   }else if("About Menu Madness".equals(selection)){

    menuBar.getMenu("Help").setEnabled(false);

   }

  }

  public void itemStateChanged(ItemEvent e){

  }

  public void windowClosing(WindowEvent e){

   System.exit(0);

  }

 }

}

MenuApp shows how the MyMenuBar and MyMenu classes are used to easily create a menu bar and to support the processing of menu-related events. When the program is executed, it displays a blank opening screen and a menu bar with five pull-down menus, as shown in Figure 9.3.

FIGURE 9.3. The MenuApp opening window.

Click on the File menu and select New, as shown in Figure 9.4. This will cause the Save and Save As menu items to become enabled. You can verify this by clicking on the File menu once again.

Click on the Edit menu and select Copy, as shown in Figure 9.5. This results in the Paste menu item becoming enabled.

Click on the Search menu and then on Go To, as shown in Figure 9.6. The Go To menu item is a second-level menu that is attached to the Search menu.

FIGURE 9.4. The File menu.

FIGURE 9.5. The Edit menu.

FIGURE 9.6. The Search menu.

Click on the View menu and select Hex, as shown in Figure 9.7. Notice that the Hex check box becomes checked, as shown in Figure 9.8.

FIGURE 9.7. The View menu.

FIGURE 9.8. The View menu after checking Hex.

Click on the Help menu and select About Menu Madness, as shown in Figure 9.9. This Help menu isn't much help at all because it is programmed to disable itself, as shown in Figure 9.10.

FIGURE 9.9. The Help menu.

FIGURE 9.10. The Help menu disabled.

You've completed the tour of the MenuApp program. Select Exit from the File menu to terminate the program's operation.

Inside MenuApp

The MenuApp class consists of two variables, menuBar and eh. The menuBar variable is an object of class MyMenuBar that is used to hold the application's menu bar. The eh variable is assigned an object of the EventHandler class. This object is used to handle both window- and menu-related events. It is used to show how multiple event handlers can be combined into a single event handler.

The MenuApp constructor creates a 400¥400 frame window with the title "Menu Madness," and invokes the setup() method to set up the background color and the menu bar. The setup() method invokes setupMenuBar() to actually perform the menu bar setup.

The setupMenuBar() method creates a gotoMenu array as the labels of a submenu that will be attached to the Search menu. The menuItems array is used to define the labels associated with the menu bar and its first-level menus. The gotoMenu array is included as an object in this array. Notice the use of the first-character conventions for disabling menu items and specifying menu items that are check boxes. The menu bar is created, assigned to the menuBar variable, and set as the menu bar for the MenuApp frame.

Creating the menu bar with the MyMenuBar class was a snap. However, creating the menu bar is only half of the work. You also need to write event-handling code that acts on the menu items selected by the user. The EventHandler inner class illustrates the use of a single event handler to handle multiple types of events. EventHandler extends the WindowAdapter class. This allows it to handle window events, such as the window closing event. It handles this event in the standard way, by overriding the windowClosing()method.

EventHandler also implements the ActionListener and ItemListener interfaces, and therefore the actionPerformed() and itemStateChanged() methods. The actionPerformed() method is used to handle the events associated with the selection of normal menu items, and the itemStateChanged() method is used to handle events associated with check box menu items.

The Exit menu item is handled by terminating the program's execution. The New and Open menu items cause the Save and Save As menu items to be enabled. The getMenu() method of MyMenuBar and the getItem() method of MyMenu are used to retrieve the Save and Save As MenuItem objects. The setEnabled() method of the MenuItem class is used to enable these menu items. Note that the Save and Save As menu items, as well as some other menu items, are not handled. Selecting these menu items does not cause any action to be performed.

The Copy and Cut menu items are processed in a similar manner as the New and Open menu items. Selecting Copy or Cut enables the Paste menu item.

The Find menu item enables the Find Next and Find Previous menu items.

The handling of the About Menu Madness menu item shows how an entire menu can be disabled.

Popup Menus

In addition to the traditional menus that are pulled down from a menu bar, Java provides support for popup menus, which are menus that appear when you perform a mouse action that triggers them. In Windows 95 platforms, this is the right-button click. Try right-clicking on your Windows 95 desktop. This should cause a popup menu to be displayed.

Popup menus are supported via the PopupMenu class, which is a subclass of the Menu class. This class provides two constructors--a default parameterless constructor, and a constructor that takes a String parameter. The String parameter is used as the popup menu's title. In Windows 95, the title is not displayed.

The show() method of the PopupMenu class causes a popup menu to be displayed. Its arguments are the Component object in which the menu is to be popped up and the x- and y-coordinates where the menu is to be placed (relative to the component).

Additional support for popup menus is provided in the MouseEvent and ComponentEvent classes of the java.awt.event package. The isPopupTrigger() method of MouseEvent is used to determine whether a mouse event is the native window event associated with popup menus. The getComponent() method of ComponentEvent returns the component in which a mouse event takes place.

Using Dialog Boxes

The Dialog class is used to construct a window that is displayed separately from the application menu. The window associated with a Dialog object is not allowed to contain a menu bar. It may be specified as being modal, meaning that it is displayed on top of the main application window until it is hidden or disposed of using the show()and dispose()methods. Most dialog boxes are used to display information to the user and get the user's response via a button click.

The MessageDialog Class

The MessageDialog class provides a custom component that implements the most common types of dialog boxes. Its source code is shown in Listing 9.5.

LISTING 9.5. THE MessageDialog CLASS.

package ju.ch09;

import java.awt.*;

import java.awt.event.*;

public class MessageDialog extends Dialog {

 public MessageDialog(Frame parent,String title,boolean modal,String text[],

  String buttons[], WindowListener wh, ActionListener bh) {

  super(parent,title,modal);

  int textLines = text.length;

  int numButtons = buttons.length;

  Panel textPanel = new Panel();

  Panel buttonPanel = new Panel();

  textPanel.setLayout(new GridLayout(textLines,1));

  for(int i=0;i<textLines;++i) textPanel.add(new Label(text[i]));

  for(int i=0;i<numButtons;++i){

   Button b = new Button(buttons[i]);

   b.addActionListener(bh);

   buttonPanel.add(b);

  }

  add("North",textPanel);

  add("South",buttonPanel);

  setBackground(Color.lightGray);

  setForeground(Color.black);

  pack();

  addWindowListener(wh);

 }

}

The MessageDialog constructor uses the parent, title, modal, text, buttons, wh, and bh parameters. The parent, title, and modal parameters are passed to the Dialog constructor of its parent class. Two Panel objects are created and assigned to textPanel and buttonPanel. The textPanel layout is specified as a GridLayout object, and the buttonPanel layout is the default FlowLayout object. The text lines are arranged in a vertical grid in the textPanel. The buttons are laid out in a centered horizontal fashion within the buttonPanel. The layout for the MessageDialog object is BorderLayout by default. The ActionListener object passed via bh is set up as the event handler for each button. The textPanel is added to the top of the dialog box, and the buttonPanel is added to the bottom. The foreground and background colors are set to light gray and black. The dialog box is packed, and the WindowListener object passed via wh is set up as the event handler for the dialog box.

The MessageApp Program

The MessageApp program shows how the MessageDialog class can be used to implement traditional dialog box functions found in typical window programs. Its source code is shown in Listing 9.6.

LISTING 9.6. THE MessageApp PROGRAM.

import java.awt.*;

import java.awt.event.*;

import ju.ch09.MyMenu;

import ju.ch09.MyMenuBar;

import ju.ch09.MessageDialog;

public class MessageApp extends Frame {

 MyMenuBar menuBar;

 MessageDialog dialog;

 DialogHandler dh = new DialogHandler();

 public static void main(String args[]){

  MessageApp app = new MessageApp();

 }

 public MessageApp() {

  super("MessageApp");

  setup();

  setSize(400,400);

  addWindowListener(new WindowEventHandler());

  show();

 }

 void setup() {

Object menuItems[][] = {
   {"File","Exit"},

   {"View","Information","Confirmation","Selection"},

  };

  MenuItemHandler mih = new MenuItemHandler();

  menuBar = new MyMenuBar(menuItems,mih,mih);

  setMenuBar(menuBar);

 }

 class MenuItemHandler implements ActionListener, ItemListener {

  public void actionPerformed(ActionEvent ev){

   String s=ev.getActionCommand();

   if(s=="Exit"){

    System.exit(0);

   }else if(s=="Information"){

    String text[] = {"Don't look now, but your shoelace is untied."};

    String buttons[] = {"OK"};

    dialog = new MessageDialog(MessageApp.this,"Information",false,

    text,buttons,dh,dh); 

    dialog.setLocation(75,75);

    dialog.show();

   }else if(s=="Confirmation"){

    String text[] = {"Do you really want to do this?"};

    String buttons[] = {"Yes","No","Cancel"};

    dialog = new MessageDialog(MessageApp.this,"Confirmation",false,

    text,buttons,dh,dh);

    dialog.setLocation(75,75);

    dialog.show();

   }else if(s=="Selection"){

    String text[] = {"What direction do you want to go?",

     "North: cold", "South: warm", "East: humid", "West: arid"};

    String buttons[] = {"North","South","East","West"};

    dialog = new MessageDialog(MessageApp.this,"Selection",false,

    text,buttons,dh,dh);

    dialog.setLocation(75,75);

    dialog.show();

   }

  }

  public void itemStateChanged(ItemEvent e){

  }

 }

 class WindowEventHandler extends WindowAdapter {

  public void windowClosing(WindowEvent e){

   System.exit(0);

  }

 }

 class DialogHandler extends WindowAdapter implements ActionListener {

  public void windowClosing(WindowEvent e){

   MessageApp.this.show();

   dialog.dispose();

  }

  public void actionPerformed(ActionEvent e){

   MessageApp.this.show();

   dialog.dispose();

  }

 }

}

The MessageApp opening window is shown in Figure 9.11. It supports the File and View pull-down menus.

FIGURE 9.11. The MessageApp opening window.

Select the Information menu item from the View pull-down menu, as shown in Figure 9.12.

A helpful Information dialog box is displayed, as shown in Figure 9.13. This type of dialog box is typically used to provide information to the user. When the dialog box is displayed, the user acknowledges the information by clicking on the OK button.

FIGURE 9.12. Selecting Information from the View menu.

FIGURE 9.13. The Information dialog box.

Selecting Confirmation from the View menu results in a Confirmation dialog box being displayed to the user, as shown in Figure 9.14. This type of dialog box requests confirmation from the user before attempting to perform an operation that may require the user's approval. If the user clicks the Yes button, the action is performed. If the user clicks No, the operation is not performed. If the user clicks Cancel, an entire series of actions leading up to the confirmation dialog box is aborted.

FIGURE 9.14. The Confirmation dialog box.

Choosing the Selection menu item from the View menu results in a multiple-choice Selection dialog box displayed to the user. The user is allowed to pick from one of several alternative paths of program execution. (See Figure 9.15.)

FIGURE 9.15. The Selection dialog box.

The MessageApp constructor creates a 400¥400 window titled "MessageApp." It uses the MyMenuBar class to construct the program's menu bar. No special processing of note is performed in the application window's construction. The dialog boxes, previously shown, are created by the program's event-handling software.

The MenuItemHandler class handles the events associated with the program's menu bar. The Exit menu item is handled by terminating the program. If the Information menu item is selected, a new MessageDialog object is created with the information shown in Figure 9.13, and the dialog box is displayed to the user using the show() method. The setLocation() method is used to move the dialog box to an offset within the main application window. The dialog box is not modal. The Confirmation and Selection menu items are handled in a similar manner. They create the dialog boxes shown in Figures 9.14 and 9.15 using the MessageDialog() constructor.

The event handling for each dialog box is performed by the methods of the DialogHandler class. These methods display the main application window and then dispose of the dialog box.

The Accessibility API

The Accessibility API provides the capability to use assistive technologies, such as screen magnifiers and speech recognition, within window applications and applets. These technologies can be used by disabled and non-disabled users to simplify their interaction with GUI components. The Accessibility API consists of the classes and interfaces of the com.sun.java.accessibility package. These classes and interfaces provide "hooks" for the incorporation of assistive technologies.

Unfortunately, no assistive technologies are currently available to take advantage of the hooks offered by the com.sun.java.accessibility package. However, it is anticipated that these technologies will be available in the near future.

Summary

In this chapter, you learned how to develop window applications using Java. You learned about the differences between applications and applets, how to open and organize windows, and how to work with menus and dialog boxes. You also learned about the Accessibility API of JDK 1.2. In the next chapter, you'll learn how to write console programs using Java.


Contents

© Copyright, Macmillan Computer Publishing. All rights reserved.