A Tour of Button
Previous | TOC
The different GUI component classes like Button and List
that make up the java.awt API vary in complexity. To reduce memory
footprint and streamline their implementation, the Truffle graphical toolkit shares many features
between the various GUI component implementations. It's useful to understand
these shared features as a starting point for learning about the architecture
of the Truffle graphical toolkit. Therefore this chapter is organized around
a fairly simple component class, Button, to introduce the basics of
the Truffle Graphical Toolkit's architecture. Button is the simplest GUI component in
java.awt that can handle input events. But many other component
classes in the Truffle Graphical Toolkit are based on the same architectural features that
Button uses.
Because the classes in the the Truffle graphical toolkit can at first seem
complex, it helps to narrow your focus on a small subset and discover how
they interact to perform simple tasks like component object creation and
event handling. The sections below describe how the Truffle graphical
toolkit operates in some basic scenarios involving Button.
Figures 1 and 2 illustrate the call path that occurs during
the creation of a java.awt.Button component in a Java
application.
The steps below describe how the process of creating a Button
component object uses classes in the java.awt, sun.awt.otk
and sun.awt.touchable packages. Each of these packages performs a
different role:
Here is an overview of the process that the Java runtime goes through in
using the Truffle graphical toolkit to build a Button component
object:
Figure 1

- Create a Button object. First, a Java application class
calls the Button constructor:
Button b = new Button("My Label");
The Button constructor sets the button label
and then calls the Component superclass constructor
which performs the rest of the component initialization.
- Create a Button peer component. The processes of
creating a Button component object and creating a Button
peer object are separate. The constructors for Button and
Component don't immediately create a Button peer
component. Instead, they save the Button state information in the
Button object for later use by the Toolkit. The actual
creation of the Button peer component is deferred until the
Button.addNotify method is called by Component.setVisible.
A component object like Button actually creates a number of objects:
- The Java application keeps a reference to a Component object
while the object is in use. When the Component object
is no longer needed, it is made available for garbage collection.
- The AWT toolkit keeps a corresponding set of classes that implement the
java.awt.peer interface. These peer classes represent the inner
workings of a GUI component. Implementations of java.awt for
desktop platforms often use native GUI toolkit widgets to implement these
peer interfaces. In contrast, the Truffle graphical toolkit provides a Java implementation of
these peer classes.
- The top-level classes that implements the java.awt.peer interface
are the Model classes.
Each Model class has a View
and zero or more Controller classes associated with it.
Figure 2 [Click on image for larger view]

Eventually, addNotify creates the Button peer:
ButtonPeer peer = getToolkit().createButton(this);
For each Button peer object,
TouchableToolkit.createButton creates a
LabelledComponentModel object,
a ButtonView object,
and any number of Controller objects associated
with the ButtonView object.
protected java.awt.peer.ButtonPeer
createButton(java.awt.Button target) {
LabelledComponentModel model =
(LabelledComponentModel)
makeLabelledComponentModel(target);
View view = new ButtonView(model,
this, getParentView(target),
Palette.BUTTON_COLORS);
ControllerManager mgr = (ControllerManager)view;
mgr.addController(mouseSound);
mgr.addController
(ArmableMouseController.consumingController);
model.setDefaultView(view);
((BasicView)view).acceptFocus();
Rectangle b = target.getBounds();
model.setBounds(b.x, b.y, b.width, b.height);
peerMap.put(target, model);
model.initComplete();
return (java.awt.peer.ButtonPeer) model;
}
|
-
Create a LabelledComponentModel object.
Model objects store a component's application state data.
The most important Button-specific state data in LabelledComponentModel
is label; the rest of the state data
(e.g. the foreground color) is inherited from BasicView.
LabelledComponentModel model =
(LabelledComponentModel)
makeLabelledComponentModel(target);
The LabelledComponentModel class is shared by
ButtonPeer and LabelPeer.
The main difference is that LabelPeer
doesn't have any controllers attached to it
while ButtonPeer has two
and LabelPeer does not capture the input focus.
-
Create a ButtonView object.
The createButton method then creates a
ButtonView object which manages the graphical
appearance of the button in both the default (unselected)
and triggered (selected) states.
View view = new ButtonView(model, this,
getParentView(target),
Palette.BUTTON_COLORS);
The actual drawing code for ButtonView
is in the DrawUtils.drawButton method (see
DrawUtils).
-
Add Controller objects
to the ButtonView object.
Controller objects handle events
that have been dispatched to a View object:
mgr.addController(mouseSound);
mgr.addController(ArmableMouseController.consumingController);
Controllers implement specific behavior
that can be reused in different components.
For example,
mouseSound can be used to provide audio feedback
to a number of different components.
A component peer object can have
any number of Controller objects associated with it.
These Controller objects form
a controller chain, which is described in
Event Delivery to a Button Component.
Remember that peer component creation is a staged process.
The application class creates a component object
and eventually the toolkit creates a peer object.
The Model class implements the java.awt.peer interface
and has a View and zero or more Controllers.
Many of the various View classes like ButtonView
keep their drawing code in a single utility class called DrawUtils.
This allows the drawing code for many of the
components to easily share functionality.
The most important method used by
ButtonView is drawButton.
The getMinimumSize, getPreferredSize
and boundsChanged methods in ComponentView are also important.
This is the starting point for many customizations
for a given look & feel design.
DrawUtils also contains code for the following:
-
Shared painting code for simple components and text.
-
Defaults for a look (heights, inter-component spacing, etc.)
-
Scaling factors
-
Initialization of the default palette.
The Palette class defines the symbolic names
for the palette entries used by Touchable.
Many GUI components in java.awt can handle events
that allow users to interact with them to change their state.
These events are initiated by the window system
as raw input events and then forwarded to specific components
by ObjectToolkit. Figures 3 and 4 illustrate
the call path that occurs during the delivery of an event
from the sun.awt.aw window system through
ObjectToolkit to a Button component.
Here is an overview of the event delivery process
for a Button component. More complex components
like List use a similar approach.
Figure 3 [Click on image for larger view]
-
The user interacts with an input device.
For example, when a user presses a location point
on an interactive LCD display, the display device driver
and RTOS cooperate to send a raw input data to the
Truffle window system.
-
The sun.awt.aw window system forwards the event
to ObjectToolkit.
When ObjectToolkit is instantiated, it registers
an event handler with the sun.awt.aw window system.
This provides a callback mechanism that allows the window system
to send events to ObjectToolkit. The main method
for doing this is WindowSystem.pointerEventOccurred.
At this stage, the event is unformatted and not yet associated
with a specific GUI component. The signature for the
pointerEventOccurred shows that the event only
contains time, location and device data:
void pointerEventOccurred(long when,int x, int y,
int ID, int number);
-
ObjectToolkit sends the event to a specific View.
When a component is instantiated, a View object is created
along with an associated Window. The View object
stores a reference to the Window object in its user data.
Since the Window object also keeps track of its parent
View object, this technique allows the two objects to keep track
of each other.
When ObjectToolkit receives notification of a raw pointer event
from the window system, it first determines the window in which
the event occurred and uses the reference to that window to look up
its associated View. ObjectToolkit then translates
the event into a java.awt.MouseEvent and delivers the event
to the associated View object by calling the postEvent
method. This method posts the event to the system event queue which eventually
delivers it to the View object through the
BasicView.handleAWTEvent method.
Figure 4 [Click on image for larger view]
-
The View object handles the event.
When the BasicView.handleAWTEvent is called
by the system event queue, it starts a View-specific event
handling mechanism. The first step is to filter the event through
the EventDispatcherPolicy class (see
Gizmos and the EventDispatcherPolicy Class)
which eventually sends the event to its Controller chain.
-
The event is processed by the Controller chain.
Since even a simple component like Button can have more
than one Controller associated with it, these Controllers
form a chain.
Events are handled by Controllers in the order
that the Controllers were added to the View.
Each Controller can ignore or handle the event.
When handling events, Controllers can choose to consume
the event completely or pass it on to the next Controller
in the chain. Controllers call methods in the View
and Model classes to implement the expected "feel"
of the particular event. The exact methods that can be called
are enforced by a shared interface that serves as a contract.
In this example, the interface is Armable and provides
methods to implement the behaviour of clicking a button.
-
The event is processed by the Java application.
Eventually,
the event may be forwarded to an application-level class
for event processing via the Listener interface.
Simple components like Button have View classes
that are based on Window.
But more complex component classes like List
need a mechanism for directing events to subregions
of the component. For example, when a user selects an item in a
List component, the component needs a dispatch mechanism
that allows the appropriate subregion to handle the selection event.
The Gizmo and EventDispatcherPolicy classes
provide a general mechanism for subregion event delivery.
The Gizmo class is like the View class
except that instead of having an associated Window class
it has a subregion of a Window.
The EventDispatcherPolicy class
allows fine-grain control of event dispatching
from the top-level View to the appropriate Gizmo.
Simple components like Button
have no need for Gizmos,
and their EventDispatcherPolicy object
forwards events directly to the first Controller
associated with the View.
More complex components are composed of several Gizmos
that are each capable of event handling.
For example, in the case of a List component,
each item in the list is represented by a Gizmo.
The ListView is associated with a single Window
but potentially several Gizmos,
each of which represents a subregion of the component.
Components like List
can extend EventDispatcherPolicy
to implement complex event dispatching techniques
that organize how events
are mapped to arbitrarily complex sets of Gizmos.
The following sections describe some of the major classes
that are used to implement Button
and provide an overview to implementing an alternate look & feel design.
Most of the Model implementations are in sun.awt.otk
and do not need additional modification
to support an alternate look & feel design.
LabelledComponentModel
is an excellent example of why this is the case.
Because it only needs to record the current state of the component
and the mechanism for displaying and interacting that component
is independent of how it is recorded,
it is unlikely that any additional modifications
will be needed for this class.
Of course,
LabelledComponentModel
can be extended if necessary.
The View classes are the most time-consuming part
of developing a new look & feel design.
Most of the View-specific classes
are in sun.awt.touchable
and can be modified or replaced.
The simplest approach to take is to concentrate
on the drawing code in DrawUtils.drawButton.
In some more complex cases,
it may be necessary to have View-specific drawing
code in a View class.
There are two ways to approach the issue of Controllers:
-
Use a different mixture of prebuilt Controller classes.
In this case, just clone TouchableToolkit.createButton
and use different Controller classes.
-
Write a new Controller class by extending SimpleController.
As with Models,
most of the Controller classes are in sun.awt.otk.
As a reference implementation, Touchable must serve certain goals
that a production implementation does not. The following list contains
some ideas for optimizing the Touchable implementation:
-
Get rid of extra Controllers.
-
Reduce object creation.
-
Remove some of the generality of Touchable
-
Get rid of runtime scaling.
-
Share a single DrawUtils instance between GUI classes.
-
Implement a single shared Controller class.
Previous | TOC
|