The Command class for AWT objects
Version 2.0

Jan Newmarch, jan@newmarch.name


Abstract

The awtCommand library implements a different way of handling events to the mechanisms of the AWT toolkit, based on the Command class of the book "Design Patterns" by Gamma, Helm, Johnson and Vlissides. The library subclasses each of the AWT objects to add a Command object to carry application-specific code. The Command class is an interface class that must be implemented by application code. Command objects can be added to windows objects and their execute method is called each time an event is invoked within the windows object. An application will implement this class to provide application code separated from the GUI objects.

Changes from version 1.0


Availability

This software is available free of charge (and free of warranty) by anonymous ftp as a tar gzip file from ftp://ftp.canberra.edu.au/pub/motif/command/command.2.0.tar.gz or a zip file from ftp://ftp.canberra.edu.au/pub/motif/command/command.zip (No, this has nothing special to do with Motif - it is general Java software. I need a new ftp subdirectory called java.)

Version 1.0 works with the beta-one awt toolkit. Version 2.0 works with the JDK 1.0 toolkit (Sun changed the specification of postEvent between versions).


AWT event model

The AWT toolkit generates events in response to user actions. For example, selecting a Button generates an ACTION_EVENT. Applications or applets that use the AWT toolkit have to respond in an event driven manner to these events i.e. there must be a mechanism for catching these events and processing them.

GUI applications sit in an event loop to catch and dispatch events. The detailed mechanism of this varies between the different GUI toolkits. For example, Xlib allows one to catch each event and branch on event type. Then application-specific code is invoked. Windows acts in a similar way. This is a strictly procedural approach.

Motif and other Xt-based toolkits allow application-specific code to be attached to callback functions. This is more OO in approach in that it attaches application code to the applcation objects. However it does suffer flaws in that it tightly couples GUI objects to application code. This makes it harder to separate view from model. It also makes code organisation quite messy, with application code being easily mixed up with GUI code.

The AWT toolkit is an OO toolkit - how does it fare for event processing? While it is a superbly crafted toolkit in many ways, it seems to have adopted a weak OO approach in event processing. An object will generate an event using the postEvent() method. The default event processing is that each object ``passes the buck'' by ignoring the event and sending it to its parent in the window hierarchy. It does this in two different ways: a Component object gets the event by handleEvent() and passes it up explicitly; a MenuComponent object passes it up to a non-MenuComponent in postEvent() .

This leads to two common ways of handling events: leave them all to the top-level Frame or Applet to manage from handleEvent or some of the convenience methods, or to subclass each object that generates an event and let them manage their own events.

The first of these leads to application code lying in the Frame (or Applet), and the Frame (or Applet) must be aware of all the details (such as object names) for all of the GUI elements. This gives a very rigid and inflexible design.

The second method leads to a large number of classes each with a single member that carries the application code. While this is better OO, it still ties the application code fairly closely to the GUI objects.

The Command class model

The Command class model separates GUI objects from application behaviour by placing application behaviour in subclasses of Command objects. For example, when the application wishes a file to be saved it should call on the FileSaveCommand object to perform this action, instead of making GUI objects such as a Frame or a MenuItem do this.

Each Command object has a method execute that can be invoked to perform this application-specific code.

A GUI object does not perform application-specific code itself. What it does is to ``install'' a Command object. When an event of interest to the GUI object occurs it invokes the execute method on its Command object.

This allows Command objects to be written more or less independently of GUI objects. The implementation of both the GUI code and the application code can then be varied independently as long as they use the same Command objects.

Implementation of the Command class

The Command class defines one abstract method execute. This could be implemented either as an abstract class or as an interface. An application will be expected to have a fairly complex class structure of its own. An interface allows the Java ``multiple inheritance'' model to work well here, so Command is defined as an interface.

Each object has a set of events that it will handle. For example a List object will generate LIST_SELECT, LIST_DESELECT and ACTION_EVENT events. There will be a (possibly) different Command object used to handle each of these. The LIST_SELECT event will be handled by a selectCommand object, the EVENT_ACTION event will be handled by an actionCommand object, etc.

The awtCommand package subclasses all of the relevant awt classes. Each class is prefixed with `C' (really, the prefix should be `Command' but that is too verbose). So CList is a subclass of List, CFrame is a subclass of Frame etc. Each of these classes has additional methods over the parent class to allow a Command object to be attached. These methods have names based on the event-types that they handle.

In order to associate Command objects to be associated with awtCommand objects, there is a method to set the Command object for each event type. For example, CList has additional methods

    setSelectCommand(Command c)
    setDeselectCommand(Command c)
    setActionCommand(Command c)

When an event occurs for which a Command object has been registered, the awtCommand package invokes the method

    execute(Object target, Event evt, Object what)
of the Command object. The actual Command object will be an instance of a subclass which contains the application code in the execute method.

If there is no Command object registered for a particular type of event, then the original event processing is done i.e. for Component objects the method handleEvent will pass the event to its parent in the GUI tree, while for MenuComponent objects the method postEvent will pass the event to its parent. This allows the event-handling techniques of the awt tookit to be still used if needed. For example, an awt application will continue to work if all awt objects are changed to awtCommand objects without other changes.

This allows several ways of writing applications using Command objects:

Example 1

This is a trivial example that puts a CButton in a Frame (a CFrame would do just as well). When the CButton is activated, the execute method of the associated Command object is run. This justs prints some information.
    import java.awt.*;
    import java.awtCommand.*;

    public class HelloWorld extends Frame {

        public static void main(String argv[]) {
            new HelloWorld().show();
        }

        HelloWorld() {
            CButton b = new CButton("Hello World");
            b.setActionCommand(new HelloCommand());
            add("Center", b);
            resize(100, 100);
        }
    }

    class HelloCommand implements Command {
        public void execute(Object target, Event evt, Object what) {
            System.out.println(target + " " + evt);
        }
    }

execute parameters

The execute method is called with three parameters

Example 2

This example is a little less trivial, and shows how a single Command object can be used for two distinct user actions.

The application shows a list of colors next to a label. When one of the colors is selected the label's foreground is changed to that color.

Items in the list can be chosen in two ways: by selection with the left mouse button or by using the up/down keys to traverse the list with selection by pressing the Return key. These generate different events, a LIST_SELECT and an ACTION_EVENT. A single Command is used to handle both of these by using it as the actionCommand and as the selectCommand.

When the execute method runs, the what field is used to find the selected data. This may be of different types, though. From the ACTION_EVENT, the value is the item selected as a String. From the LIST_SELECT the value is the index of the item selected as an Integer. A runtime test distinguishes between them.

    import java.awt.*;
    import java.awtCommand.*;

    class ColorList extends CFrame {
	final Color colors[] = {Color.red, Color.blue, Color.green};
	final String colorLabels[] = {"red", "blue", "green"};
	Label label;

	public static void main(String argv[]) {
	    new ColorList().show();
	}

	ColorList() {
	    // a CList showing the color choices
	    CList list = new CList();
	    for (int n = 0; n < colors.length; n++)
		list.addItem(colorLabels[n]);

	// a Command invoked on button select and Return key
	ColorCommand command = new ColorCommand(this, colorLabels);
	list.setSelectCommand(command);
	list.setActionCommand(command);

	label = new Label("Hello World");

	// set geometry
	add("West", list);
	add("Center", label);
	resize(300, 100);
    }

    public void setColor(String color) {
	int n;

	// search for Color matching string 
	for (n = 0; n < colorLabels.length; n++) {
	    if (colorLabels[n].equals(color)) {
		break;
	    }
	}
        label.setForeground(colors[n]);
    }
}

class ColorCommand implements Command {
    ColorList app;
    String colorLabels[];

    // Constructor stores local info
    ColorCommand(ColorList app, String colorLabels[]) {
	this.app = app;
	this.colorLabels = colorLabels;
    }

    public void execute(Object target, Event evt, Object what) {

	if (what instanceof String) {
	    // got here as actionCommand
	    String color = (String) what;

	    app.setColor(color);
	} else {
	    // got here as selectCommand
	    int index = ((Integer) what).intValue();

	    app.setColor(colorLabels[index]);
	}
    }
}

Changes in AWT event model

In the AWT beta-one toolkit, event handling was simple: an event generated by a Component would intially be directed to handleEvent() for that component, and then successively to each parent (in the GUI tree). This chain would stop when either th chain ran out, or (more likely) a component would handle an event and then return true from handleEvent() to signal this. Clean, and simple.

JDK 1.0 really muddied this, for a reason.

In a TextComponent, what was typed may not be what the application wants to see appear in the TextComponent. For example the application may want to convert all characters typed to lower-case. Or it may want to change all characters to an asterix for password entry (TextField has a method just for this - too specialised). Or it may want to discard characters, or replace them by a sequence as in macro expansion. These are examples of why an application may want to change the event presented to a different one.

Events are passed to the Component that generated them, and up through the widget tree. If they pop out of the top of this, then they are fed back into the object via its peer (the peer allows platform-specific code to execute). Right now, this only tries to do things with key events: trap them before they get to the native GUI object, send them through the application code and then feed the (possibly modified) event back into the native GUI object. (This solves the first two example uses, not the third or fourth.)

Several points

Version 2.0 of the awtCommand package accomodates this new model by always returning false from handleEvent(). The examples above are unchanged between version 1.0 and 2.0. However, version 2.0 now allows a sequence of objects to handle the event: any of the objects in the GUI tree can handle the event, but can't stop others from handling it too. This is like the "Chain of Responsibility" pattern in Gamma, et al, but without the stopping possibility. I am not sure I like this change, but the new event model forces it.

Comments on code reuse

The Java design allows single inheritance but not multiple inheritance. The interface mechanism does not allow code reuse but instead enforces specification implementation.

There are several instances of code duplication in the awtCommand caused by these mechanisms, which are very definitively not code reuse. These occur in the common code used in CCanvas, CDialog, CFrame, CPanel and CWindow. They all handle a large common set of events.

The awt toolkit does not use code duplication. How this is done is intriguing: (under X) they all create their native window windows by calling a C function awt_canvas_create that creates a DrawingArea and installs event handlers for events. Code is shared by calling a shared function that lives in its own file, canvas.c. Code sharing is performed at the native level by calling a common global function.

In the awtCommand toolkit, CCanvas is a subclass of Canvas, CDialog is a subclass of Dialog, etc. They can only inherit methods from their superclasses. But they all need to implement a large number of methods such as mouseUp, scrollAbsolute, action, etc, as well as the corresponding methods to set these command objects.

Multiple inheritance would certainly be a means of sharing code. This is a rather heavyweight mechanism, though. A simple #include mechanism would be more than adequate to solve the code sharing problems encountered in building this toolkit.

An alternative way is to use an associated object, much like the AWT toolkit uses peer objects. Jean-Michel Leon sent me code to do this, and I would have used it apart from one factor: it places the documentation in the peer object, and this would make it hard to find using the automatic documenting system used for Java libraries. This points to another small problem with Java: the documentation system is unable to track through optimisation patterns.

Status

This library is version 2.0, released in March 1996. It uses the AWT JDK 1.0 release. Version 1.0 of the library used the beta-one version of the AWT release.

Bugs

The AWT beta toolkits do weird things like generate key up/down and mouse motion events for Label objects. Some of these weird behaviours are different under X and Windows95. Other odd behaviour includes no key event generation for TextArea or TextField (under X). I don't know what the intent really is for some of the event generation in the toolkit. There does not appear to be an implementation-independent specification of intended behaviour that is sufficiently detailed to work out what should happen.

So what I do now is to implement the event handling that the Motif version implements, except when it seems odd. So the toolkit doesn't handle key events for TextArea (although Windows95 seems to generate them) because Motif doesn't. On the other hand, all mouse and key events can only be handled by Frame, Canvas, Dialog and Window because I don't know where they should be handled.

So there are discrepancies in event handling on different platforms for the awt toolkit, and discrepancies between when the awt toolkit handles events and when this toolkit does. I guess that amounts to at least one bug. I will fix things in the awtCommand library when I know what the official line is.

Acknowledgments

The idea for this comes straight from the book ``Design Patterns'' by Gamma, Helm, Johnson and Vlissides published by Addison-Wesley, ISBN 0-201-63361-2. They discuss the Command pattern to manage user actions. This book is well worth reading.

What started me thinking about this was the awtExt package of Sal Cataudella (http://www.panix.com/~rangerx/) This implements an Xt callback model for event handling.

Much of the detail of event handling comes from an article I have written for publication in the Internet journal, the X Advisor to appear in the March, 1996 edition.