Previous | Next | Trail Map | Creating a User Interface (with Swing) | Using Components, the GUI Building Blocks

Details of the Component Architecture

The AWT was designed from the start to have a platform-independent API and yet to preserve each platform's look and feel. For example, the AWT has just one API for buttons (provided by the Button class), but a button looks different on a Macintosh than on a PC running Windows 95.

The AWT achieves its seemingly contradictory goals by providing classes (components) that provide a platform-independent API but that make use of platform-specific implementations (peers). To be specific, every AWT component class (Component, MenuComponent, and their subclasses) has an equivalent peer class, and every component object has a peer object that controls the object's look and feel.

Below is a figure that illustrates how a typical AWT component (a Button) is mapped to a peer. Button peers are implemented in platform-specific classes that implement the java.awt.peer ButtonPeer interface. The java.awt Toolkit class defines methods that choose exactly which class to use for the peer implementation.

How Peers Are Created

Peers are created lazily, just before their corresponding component object is drawn for the first time. You might have noticed one side effect of this: the size of a component isn't valid until after the component has been shown for the first time.

When you add a component to a non-visible container (a container with no peer), then just before the container is shown for the first time, its peer -- and the peers of all components it contains -- is created.

However, if you add a component to a visible container, you need to explicitly tell the AWT to create a peer for the component. You do this by calling the validate() method. Although you can invoke validate() directly on the component you're adding, it's usually invoked on the container, instead. The reason is that invoking validate() on a container causes a chain reaction -- every component under the container gets validated, as well. For example, after you add components to an Applet object, you call validate() on the Applet, which creates peers for all the components in the Applet.

How Peers Handle Events

Peers implement the feel (and, indirectly, the look) of UI components by reacting to user input events. For example, when the user clicks a button, the peer reacts to the mouse down and mouse up events by causing the button's appearance to change and by forwarding an action event to the appropriate Button object.

In theory, peers are at the end of the event chain. When a raw event (such as a key press) occurs, the Component for which the event is intended gets to handle the event first, and then (if the Component's event handler returns false) the Component's Container sees the event, and so on. After all the Components in the hierarchy have had an opportunity to handle the event (and all their event handling methods have returned false), the peer gets to see and react to the event.

In the current implementation, the above scenario is true for key presses but not for mouse events. For mouse events, the peer is the first to see the event, and it doesn't necessarily pass all events on to the Component. We plan to make mouse events work like keyboard events in a future release.

From raw events such as key presses and mouse clicks, peers sometimes generate higher level events -- actions, focus changes, window iconifications, and so on. These higher level events are passed on to the relevant Component for handling.

Previous | Next | Trail Map | Creating a User Interface (with Swing) | Using Components, the GUI Building Blocks