Sun Java Solaris Communities My SDN Account Join SDN
 
Archive - Java Technology Products Download

Truffle Graphical Toolkit Customization Guide: a Tour of Button

 

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.

Creation of a Button Component

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:

  • java.awt provides an API for applications.

  • sun.awt.otk provides a set of reusable classes for implementing look & feel designs. The major building blocks are:
    • Model classes represent the data state of components.

    • View classes represent the graphical appearance or look of components.

    • Controller classes manage the effects of events, in other words their feel.
    Note: While the sun.awt.otk source code is available for reference purposes, it cannot be modified for the purposes of building a new look & feel design.

  • sun.awt.touchable contains a set of classes that represent the Touchable look & feel design. The most important among these are the various Views, TouchableToolkit, Palette and DrawUtils.

    Note: The Touchable classes can be modified or configured to build new look & feel designs.

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

button 1

  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.

  2. 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]

    button 2

    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;
    }
    

  3. 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.

  4. 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).

  5. 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.

DrawUtils

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.

Palette

The Palette class defines the symbolic names for the palette entries used by Touchable.

Event Delivery to a Button Component

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]

button 3

  1. 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.

  2. 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);
    

  3. 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]

    button 4

  4. 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.

  5. 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.

  6. 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.

Gizmos and the EventDispatcherPolicy Class

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.

Models, Views & Controllers

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.

LabelledComponentModel

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.

ButtonView

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.

ArmOnPress

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.

Optimizations

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