Java

The Bean Builder Tutorial

by Mark Davidson


This tutorial demonstrates the main features of building an application with the Bean Builder. The Bean Builder is a tool which allows the visual assembly of an application by instantiating and setting the properties of components based on the JavaBeansTM component architecture (beans). The dynamic behavior of the application is specified by "wiring" relationships that represent events handlers and method calls between the objects in an application. The state of this application is saved to and restored from an XML format. An application is constructed using the JavaTM API without having to write a line of source code.


The Demo Application

We will demonstrate the features of the Bean Builder by creating an application that builds a simple entry list. While trivial in functionality, this application touches upon most of the features in the Bean Builder.

Entering text and pressing return field appends the text to the list. The Remove All button removes all the items from the list.

When the enclosing frame is resized, the scrollable list, the text field and the button scale with the frame.

All dressed up and nowhere to go!
 

Creating the User Interface

Objects are retrieved from the Palette below the toolbar. The default palette is loaded with Swing components and containers arranged alphabetically from left to right. The Palette is specified as an external XML document and can be edited. The default palette is named palette.xml.


The Palette

A brief description of the individual Palette items appears in the Status Bar as you move the cursor over that item. For example, as shown in the figure to the left, if you hold the cursor over the button, the tooltip displays the text of the JButton.

The icons, tooltip text, and status bar description are retrieved from the BeanInfo class associated with each object.


The Designer is where the objects are instantiated, selected and connected. This Designer represents the root container of the object graph being assembled. The Designer wraps the live application that will be constructed.

Selecting an item from the Palette will change the cursor from a pointer to a crosshair. This indicates that the tool is in "instantiation mode". You can instantiate the selected Palette item by clicking in the frame of the Designer.


An important note about setting the preferred size of components

The size of the component depend on the how the component was instantiated.

It's very important to understand the distinction between setting the preferred size versus using the default preferred size. SpringLayout honors the preferred size of the component. The component scale correctly when its contents change if the preferred size of the component is left as its default. This is desirable for dynamic user interface elements and will easily allow the component to scale correctly when the application is localized.


Instantiating the First Component: The JScrollPane

  1. Select the JScrollPane on the Containers tab.
    Notice that the cursor changes to a crosshair

  2. Click and drag a rectangle onto the design panel.
    An empty JScrollPane should appear and the cursor returns to a pointer.

Nine blue and white resize handles appear around the new component. The center handle allows you to reposition the object. The handles on the edges and corners allow you to resize the component in the direction indicated by the cursor.

The four dark connection handles on the outside of the object act as "anchors" or "targets" for creating dynamic event adaptors or property associations between objects.

Fresh off the Palette!
 

Instantiating the Rest of the Components

  1. Instantiate the JLabel, JTextField and JButton components by selecting them from the Palette and then clicking in the Designer.
    Make sure that the components are sized according to their default preferred size.

    If the component appears to be very small then that indicates that you set the preferred size by clicking and dragging an instantiation rectangle. Delete the component by selecting it and pressing the Delete key and then try to instantiate the component again.

  2. Instantiate the JList inside the JScrollPane by clicking inside the JScrollPane in the Designer.

    It's very important for scrollable components like JList to adhere to its preferred size while in the JScrollPane.

Clicking on an object makes it the current object. The current object has blue resizing handles around it. These handles are used to resize and move the object. The properties of the current object are displayed in the properties panel. If this is a visual object, then it is selected in the Containment Hierarchy.

All the visual components

Setting Object Properties

The instantiated objects have the default properties when the default constructor on the Class is invoked. Properties that conform to the JavaBeans specification method signatures for getters and setters are exposed and may be set to give the object a distinct identity.

For example, some visual properties on Components that can be set include the font, colors, sizing and alignment characteristics.


The Property Inspector

As you can see to the image to the left, a tree is displayed that represents the Containment Hierarchy starting from the root object. Underneath is a Property Sheet of introspected properties from the current object. Each row represents a PropertyDescriptor. You can use the combo box above the Property Sheet to filter the type of properties which are made visible in the table.

As you can see, if you hold the mouse over an item in the Property column, a tooltip appears with a description of the property.

You can edit properties by entering new values in the Value column and pressing Enter to accept the new value.

Up - Loads the parent of the current object into the Property Panel
Down - Loads the selected property into the Property Panel. You can also double click on the selected property.
Add - Places the selected object into the Design Panel for interaction. This is useful for manipulating non-visual Beans.
Customizer - If enabled, this button brings up the associated customizer for the selected object.


  1. Select the JButton object as the current object and change the label property to "Remove All".

    When you press the Enter key, the text of the button changes to the new property value. Notice that the button resizes correctly to accommodate the wider text. If you don't see that behavior then the preferred size of the button was explicitly set. You may want to move the button to center it within the frame.

  2. Change the name of the JLabel object to "Add: " by changing its text property

  3. Increase the value of the JLabel object's font property to 18 point using the font PropertyEditor.

  4. Set the horizontalAlignment of the label to be right justified by selecting "RIGHT" using the alignment combo box.

  5. Finally, use the containment hierarchy to select the root JFrame and change the title property to be "Bean Builder Tutorial".

Editing the properties of the Objects

Creating a Non-visual Bean

The model view controller (MVC) architecture of the JFC components requires a model that acts as an intermediary between the user interaction and the data. For this example we set the model of the JList object to use a DefaultListModel.

The DefaultListModel is a non-visual bean - a bean that doesn't inherit from java.awt.Component


The Control Panel

The modes of the builder and designer are controlled with this interface. The combo box on the left toggles the designer between two modes:
  • Event Management allows editing of dynamic interactions between objects.
  • Layout Editing allows the editing of the resizing behavior between objects.
The check box on the right toggles the designer on or off. If the designer is off then the designed application is "live".

First we have to create a new instance of the DefaultListModel and place it on the design panel for manipulation.

  1. Put the cursor focus in the Instantiate Bean text field (try alt-b)

  2. Enter the following string: javax.swing.DefaultListModel.

  3. Press the Enter key to create a new instance

A visual proxy object that represents the non-visual bean appears in the upper left of the Designer and is the selected object. Notice that the containment hierarchy doesn't show the same selection. The hierarchy only displays containment relationships.

This visual proxy object is used to select and hookup the non-visual Object that it wraps. You can move the visual proxy object by dragging on the center handle but you cannot resize the visual proxy.

The Instantiate Bean field is used to instantiate any object from a class that is found in the classpath.

Instantiating the DefaultListModel


Setting an Object as a Property of Another Object

The newly instantiated DefaultListModel is in the design but is not associated with an object. This model should be associated with the JList object in the user interface. Use the Interaction Wizard to define the way that objects relate to each other. The interaction is going to take a source object and set it as a property value on the target object using a setter method from the target. This means that we want to call the JList.setModel(...) method with the list model as the argument.

  1. Click on any one of the four connection handles surrounding the DefaultListModel instance and drag the mouse over to a connection handle surrounding the JScrollPane object.
    Notice that a line is drawn between the list model and the JScrollPane object. The cursor changes to a crosshair when it is over the connection handle.

  2. Release the mouse over the JScrollPane connection handle.
    A popup menu appears that has all the components in the inheritance hierarchy of the JScrollPane.

  3. Select the JList from the popup menu and the Interaction Wizard appears

  4. Select the Set Property radio button and the Wizard reconfigures itself for property association.
    The items in the list are target object methods whose parameter matches the type of the source object or can be related by an isAssignableFrom inheritance relationship.

  5. Select the "model( ListModel )" list item and select the Finish button.
    The Interaction Wizard is dismissed and the DefaultListModel instance is used as the model for the JList object. You can verify this by selecting the JList object in the containment hierarchy and looking at the model property in the property sheet.

Creating Event Adapters

The traditional way of creating an event interaction between two objects was to create a small inner class and recompile it.

This builder uses the Dynamic Proxy API to create EventHandler objects that are event listeners. This API was added to release 1.3 and are used to synthesize listeners of arbitrary types at runtime. The advantage of using the Dynamic Proxy API is that it avoids costly inner classes and you can dynamically create these listener classes without having to recompile code.

We are now going to add two EventHandlers that implement the following behavior:

  1. Click on a JTextField connection handle and drag the cursor to a DefaultListModel connection handle. The Interaction Wizard appears.

  2. Select the Event Adapter radio button in the Interaction Wizard
    The Wizard reconfigures itself for generating an event adapter. Notice that the Finish button is disabled and the Next button is enabled. This indicates that there are more steps to create the adapter.

  3. Select the "action" item in the "Event Sets" list and select the Next button
    The page of the Wizard apears that allow the selection of a target method on the DefaultListModel instance. As a simplification, only target methods that require one or zero arguments are listed.

  4. Select the "addElement( Object )" item in the "Target Methods" list and select the Next button
    The third panel is a list of no argument methods retrieved from the source object that return the same type that the target method requires as an argument. This allows adapters that get generated that use target.setFoo(source.getBar);

  5. Select the "getText( )" item in the "Source Methods" list and select the Finish button.
    A new EventHandler is created that adds the string in the JTextField to the list as a result of the actionPerformed method when the Enter key is pressed. The EventHandler is created with the Dynamic Proxy APIs that were introduced in release 1.3.

Creating Another Event Adapter

Create a new event adapter for the JButton using the Interaction Wizard.

This interaction deletes all the items in the list when the "Remove All" button is pressed. Repeat the same steps using the wizard with the following values:


Testing the Runtime Application

The event adapters and property associations are created and linked for "live" objects. You may test the live object graph by taking the Bean Builder out of Design Mode and putting it into Runtime Mode. You can switch between these two states by selecting or de-selecting the Design Mode checkbox (alt-d). This Action is mirrored on the View menu.

In Runtime Mode, the objects on the design panel become "live". The application behaves the exactly the way that it was designed.

Type some values in the text field and press the Enter key at the end of each string. These values appear in the list. Pressing the "Remove All" button clears the list.


Using SpringLayout to Make the Frame Scale Correctly

The SpringLayout layout manager was introduced in release 1.4. The main benefits of using SpringLayout is that it acts like null layout for the placement of components with the condition that it honors the preferred size of the components. Furthermore, dynamic resizing behavior can be added at any time in the design process by linking the edges of components to the dependent edges of other components. For example, when the frame gets larger, it is desirable for the scrollable list to also get larger.


Make sure that the Designer is in Layout Editing mode by selecting Layout Editing from the Control Panel combo box. Red handles should appear on all the components where edges can be linked.

The Basics of SpringLayout

The four edges of a component are described as as points on a compass. For example, the top edge is the north side, the right edge is the east side and so on.

Using SpringLayout, relationships between the components are expressed as a "link" between the edges that span a fixed distance from the dependent component and an anchor component.

When the edge of an anchor component moves, the linked edge of the dependent component also moves to maintain the fixed distance between the edges.

There is an order dependency when linking components. If at all possible, the east and south sides of the components should be linked first. The order dependence is a consequence of the related properties within the SpringLayout constraints. The properties change state as it becomes over-constrained. Please see the javadoc for javax.swing.SpringLayout.Constraints for more details about over-constraining.


Note: Sometimes, the blue selection handles conflict with the red edge linking handles. if this occurs, a single click on the background of the panel will make the selection handles go away.

  1. Place the cursor on the handle on the East edge of the JScrollPane (dependent edge). When it turns into a crosshair, click and drag the arrow to the East edge handle of the enclosing container (anchor edge).
    A grey arrow is drawn that leads to the East (right) handle of the JScrollPane to the East (right) handle of the enclosing container.

  2. Repeat the operation by linking the East edges of the JButton and the JTextField to the East edge of the container.
    The linked edges should look like the first picture to the right. You can test the dynamic resizing behavior by grabbing the right side of the frame and making it larger and then smaller. The three dependent components should follow the right edge.

  3. Continue by linking the South edges of the JButton and JScrollPane to to the South edge of the container.
    Test the behavior by resizing the frame. Alternating between linking and resizing is an excellent way of testing how the container lays out and helps to understand how linking edges affects the resizing of the components.

  4. Link the West (left) edges of the JButton and the JScrollPane to the West (left) edge of the container.

  5. Link the North edge of the JScrollPane to the North edge of the container.

  6. Finally, link the West edge of the JTextField to the East edge of the JLabel.

The linked edges should look like the second picture to the left.


Saving the Design

The Bean Builder uses the Long Term Persistence for JavaBeans components for storing the state of the object graph. This persistence mechanism is a new feature in JavaTM 2 Platform, Standard Edition, release 1.4. This new persistence mechanism writes all the public state of the object graph to a plain (and editable) XML text format.


Actions

The Bean Builder wide actions are implemented in the main toolbar and the main menu. Placing the cursor over the menu or toolbar item shows its description in the status bar.

New - Creates a new Design. This command clears the existing design and sets a new root object.
Open - Opens an existing design in the Long Term Persistence XML format.
Save - Saves the existing design to a file. A FileChooserDialog appears to prompt for a filename if it doesn't exist.

Press the Save button to save the design to disk. Select Save As from the File menu if you want to save the state of the application using a different filename.


Note: The data currently in the models and text fields are also saved. If you wish to save the application in a blank state then delete all the values.

The saved design should look like this: tutorial.xml


Reading the Design outside of the Builder

One of the goals of Bean Builder is to demonstrate a new portable persistence format. You can execute the Bean Builder in "interpret mode" that takes the name of the generated archive as an argument to the builder. The file is passed to a few lines of code that reads the persistence file and recreates the application.


Note: The code required to reconstruct an XML design is trivial.
        try {
	   InputStream is = new BufferedInputStream(
                                 new FileInputStream("tutorial.xml")); 
	   XMLDecoder d = new XMLDecoder(is);
	   Object o = d.readObject();
        } catch (IOException ex) {
	   System.out.println(ex.getMessage());
        }
      
A future application may create a stub "interpreter" that would take an xml design as an argument.

From the root of the distribution, use the "-i" flag and the name of the archive as the argument:

% run -i tutorial.xml

The application appears in a new frame. The tutorial direction also has an example of a simple web browser in an archive called Web_Browser.xml


Time to Experiment

The Bean Builder is a general application builder that uses dynamic component assembly. There are a lot of little features that you can discover. The Bean Builder only uses JavaBeans component architecture mechanisms like Introspection and the BeanInfo classes to interrogate the properties of the Beans.

There are several ways that you can experiment with your own beans. You can load the beans onto the palette by invoking the Load Jar File command. You can add the beans to the classpath and edit the palette.xml file. You can also instantiate any Object in the classpath with the Instantiate Bean field.

The source code to the Bean Builder was shipped with the distribution.

Drop us a line at java-beans@java.sun.com and let us know how much fun you're having.


The Bean Builder, is a product of Sun MicrosystemsTM, Inc.
For answers to common questions and further contact
information please see the java.sun.com Help Pages.
Sun Microsystems, Inc.
Copyright © 1997-2002 Sun Microsystems, Inc.
All Rights Reserved. Terms of Use. Privacy Policy.