Copyright Chris Johnson, 1998.
This course must NOT be used for any commercial purposes without the express per mission of the author.

Human Computer Interface Design Using Java

Chris
USING THE ABSTRACT WINDOW TOOLKIT (Part 2)
by

Chris Johnson



Using the Abstract Window Toolkit

This section goes on to describe the key features of the Java AWT environment. The initial section describes how events are used to inform application programs about user input and for application programs to affect the display. This purely technical descriptions leads onto section that explore both the design and the programming aspects of various interface features including buttons, menus and forms.


The AWT Classes

There are four main classes in AWT:

The java.awt.Component class is, therefore, fundamental to the AWT in Java. The structure of this class can be illustrated as follows:
                                     Object
                                        |
                                    Component
                                        |
--------------------------------------------------------------------------------
Canvas  Scrollbar  Container  Button  Checkbox  TextComponent  Label  List  Choice
                       |                             |
                  -----------                   -----------
              Panel         Window       TextArea        TextField
                              |
                          ----------
                     Dialog       Frame
                        |
                     FileDialog
The only exception to the classes shown in this diagram are for Menus and Menu items. This difference can be explained by again looking at Word running under
WindowsNT and a Macintosh. There are pronounced differences in the ways that different native platforms implement menus. In some systems it is possible to set the background colour of a menu, in other it is not. Menus, therfore, form part of java.awt.MenuComponent rather than java.awt.Component:

              Object
                 |
           MenuComponent
                 |
            ------------
           |            |
        MenuItem     MenuBar
           |
          ----
         |    |
       Menu CheckboxMenuItem

Each component has a corresponding native peer so that it can be implemented on particular platforms. They also have a number of attributes that can be summarised as follows:

As the names suggests, the container class provides a means of "grouping" multiple components. For instance, an applet may contain a number of buttons. Components can be added to a container. This can be thought of as a list. The order of the list determine the front to back order in which the components are presented on the screen. This is important is one component is not to obscure another. If no index is specified when adding a component to a container, it will be added to the end of the list which represents the bottom of the stacking order. There are a number of different subclasses to Container.

        Container
            |
        --------------------------------------------
     Window           Applet         Panel     Scrollpane
	|
  -------------
Frame       Dialog
               |
           FileDialog
Note that a Frame can have a menubar but that an Applet may not. A window can have no menu or border and so Frames and Dialogs are used more frequently. For instance, the following code creates a Frame with the title "Warning". The size of the frame is defined in terms of two constants (width and height), these can be thought of as pixels.
/*
* A frame 
*
* Author: Chris Johnson (johnson@dcs.gla.ac.uk)
* Last revision date: 11/10/98
*
* Produces a warning window on the screen
*
* Beware - there is no way of closing the frame!
* see later section on event handling...
*/
 
import java.awt.*;
 
public class SimpleWarningFrame extends Frame {
 
static private final int frame_height = 150;
static private final int frame_width = 250;
 
public SimpleWarningFrame () {
        setBackground(Color.red);
        setForeground(Color.black);
}
 
   public static void main (String[] args){
 
        Frame f= new SimpleWarning();
        f.setTitle("Warning");
        f.resize(frame_width, frame_height);
        f.show();
   }
}

Containers simply provide a grouping mechanism for interface objects. LayoutManagers provide means of positioning and sizing these objects. This class will be discussed in later sections.


Event Handling

Look at the screen in front of you. What is happening? Not much, probably. Your browser is sitting there waiting for you to click on an icon or for you to type something. In other words, it is waiting for an input event to take place. In pseudo-code you could think of a browser in the following terms:

while Input_Event != Quit loop
	
	read(Input_Event);            -- user types or click something
	perform_command(Input_Event); -- system executes corresponding command

end loop;
Of course, if you think about all of the things that a browser might do then this event loop will get quite complex. Here is some more detailed pseudo code:
while Input_Event != Quit loop
        
        read(Input_Event);            -- user types or click something

	switch Input_Event
	
		case Home_Icon: load_URL(Home); break;  -- click on the home icon

		case Back_Icon: load_URL(Previous_Page); break; -- click to go back

		case File_Menu: display(File_Menu.Options); break; -- display file options
			 
	/* etc etc etc */
 
end loop;
Where do these events come from? These events are passed to the AWT environment from the native peers, mentioned earlier. For instance, if the Java interface were running on a Macintosh then the event handling system within MacOS would first capture the event and then pass it on to AWT for further processing. Similarly, if the applet executed on a UNIX system running Motif then the X windows event handler would pass the event to AWT. All of this fits in with the
diagram shown earlier.

It is important that all event handler methods execute as quickly as possible. Otherwise the system may appear to hang - any subsequent input by the user may have no effect as the system handles previous events. Eventually, the relevant methods will complete and the system will appear to "catch up" in an extremely unpredictable manner.

Word of warning - the event model was one of the major changes that occured between AWT version 1.0 and 1.1. Although the fundamental concepts remain the same, the detailed implementation of these systems is different (1.0 uses an inheritance-based approach to event handling, 1.1 uses a cleaner delegation approach). We will focus on the 1.1 event mechanisms, full details about the 1.0 system are provided here.

Each event results in the creation of an Event object. These have the following attributes:

For example, the following code was taken from the button applet that we met earlier.
 public void actionPerformed(ActionEvent e) {
        String command = e.getActionCommand();
         
        if (command == DISABLE) { //They clicked "Disable middle button"
            b2.setEnabled(false);
            b1.setEnabled(false);
            b3.setEnabled(true);
        } else { //They clicked "Enable middle button"
            b2.setEnabled(true);
            b1.setEnabled(true);
            b3.setEnabled(false);
        }
    }
The development of a graphical user interface in AWT, typically, depends upon the programmer overriding methods associated with particular components when an event occurs. For instance, the setSize method is invoked in response to resize events for particular components. These events are generated whenever the user attempts to resize that component. A programmer might override this method, for instance to warn the user that it is not possible to resize that particular component.

Each event is first passed to the handleEvent method. This, in turn, calls the associated methods from the previous list. The Component class provides a number of methods, such as setSize in the previous example, that are called in response to particular events. The associated events appear in parentheses after the method:

As we shall see, many interface components can be operated by either the mouse or the keyboard. For example, an OK button on a dialogue box can be selected or the user may simply press RETURN to confirm. In order for such keyboard input to be successful, the component must have the focus. In other words, the RETURN should not be sent to some other text component on the screen. Only one window and one component in that window can have the keyboard focus. Once a window has the focus, Component requestFocus() requests that a particular component gets the focus.

Only Button, Checkbox,Choice, List, MenuItem, and TextField produce action() events. They do so when the user indicates somehow that the control should perform an action. For example, when the user clicks a button, an action event is generated. By implementing the action() method, you can react to user actions on controls without worrying about the low-level events, such as key presses and mouse clicks, that caused the action. Here is an example from a simple program:

public boolean action(Event e, Object what){
/*
*   The what parameter varies depending on the object associated with
*   the event, in the case of a button it provides the textual label (String)
*   that is displayed on the button. 
*/
        if (e.target == quitButton)
        {
                        System.exit(0);
        }
        return true;
}

Each of the previous methods returns a Boolean value to indicate whether or not the method successfully handled the event. If False is returned then the event is handed up to components higher in the hierarchy. Again, this was illustrated in the previous example.

The following example shows how the handleEvent method can be overridden in order to close the warning window that was generated in the Frame example from the previous section. Here is the output from this application viewed on a Macintosh. What are the problems with the design of this warning?


/*
* Simple warning program 
*
* Author: Chris Johnson (johnson@dcs.gla.ac.uk)
* Last revision date: 11/10/98
*
* Produces a simple warning on the screen.   Illustrates the
* use of a frame and of a simple event handler in AWT 1.0
* Based on an example by Judy Bishop, JavaGentely,
* Addison Wesley 1998, p. 310
 */
/*
 * 1.0 version.
 */
 
import java.awt.*;
public class SimpleWarning extends Frame {
 
static private final int horigap = 15;
static private final int vertigap = 10;
 
public SimpleWarning (String[] message, int n) {
        setBackground(Color.red);
        setForeground(Color.black);
 
        setLayout(new FlowLayout(FlowLayout.CENTER, horigap, vertigap));
        for (int i=0; n>i; i++)
                        add (new Label(message[i]));
}
 
public boolean handleEvent(Event e){
 
        if (e.id == Event.WINDOW_DESTROY)
        {
                        System.exit(0);
        }
        return super.handleEvent(e);
}
 
   public static void main (String[] args){
 
        String[] message = {
                "WARNING",
                "Something has gone badly wrong",
                "I'd go home..."
        };
 
        Frame f= new SimpleWarning(message, 3);
 
 
        f.setTitle("Warning");
        f.resize(240, 100);
    f.show(true);
   }
}
The following example extends this to include a quit button. Here we respond to any events involving the quitButton within the handleEvent method. This could also have been done by overriding the action() method mentioned above.
/*
* Warning program with a Cancel button
*
* Author: Chris Johnson (johnson@dcs.gla.ac.uk)
* Last revision date: 11/10/98
*
* Produces a simple warning on the screen.   Illustrates the
* use of a frame and of a simple event handler in AWT 1.0
* Based on an example by Judy Bishop
 */
/*
 * 1.0 version.
 */
 
import java.awt.*;
public class ButtonWarning extends Frame {
 
static private final int horigap = 15;
static private final int vertigap = 10;
private Button quitButton;
 
public ButtonWarning (String[] message, int n) {
        setBackground(Color.white);
        setForeground(Color.black);
 
        setLayout(new FlowLayout(FlowLayout.CENTER, horigap, vertigap));
        for (int i=0; n>i; i++)
                        add (new Label(message[i]));
        quitButton = new Button("Quit");
        add(quitButton);
}
 
public boolean handleEvent(Event e){
 
        if (e.id == Event.WINDOW_DESTROY || e.target == quitButtton)
        {
                        System.exit(0);
        }
        return super.handleEvent(e);
}
 
   public static void main (String[] args){
 
        String[] message = {
                "WARNING",
                "Something has gone badly wrong",
                "I'd go home..."
        };
 
        Frame f= new ButtonWarning(message, 3);
        f.setTitle("Warning");
        f.resize(240, 100);
        f.show(true);
   }
}
If you run this program you should notice that the handleEvent() method now exits the system when any event is received on the quitButton. This is not exactly what is required because an event will be generated whenever the mouse moves over this button and not only when the button is selected. A useful exercise would be to write a handler so that the system only quits when the user releases the mouse over the quitButton. Have a go and then look at this
solution to the problem.

And now on to part three...


Copyright Chris Johnson, 1998.