Skip to main content

skip to main content

developerWorks  >  Java technology | XML | Web development  >

Introducing the Reflexive User Interface Builder

Build Java GUIs simply and quickly with new technology from alphaWorks

developerWorks
Document options

Document options requiring JavaScript are not displayed

Sample code


Rate this page

Help us improve this content


Level: Introductory

Barry Feigenbaum, Ph.D. (feigenba@us.ibm.com), Sr. Consulting IT Architect, IBM
Michael Squillace (masquill@us.ibm.com), Software Engineer, IBM

04 Aug 2004

The IBM Reflexive User Interface Builder (RIB), a new technology available from alphaWorks, is an application and toolkit for building and rendering Java AWT/Swing and Eclipse SWT GUIs. RIB specifies a flexible and easy-to-use XML markup language for describing Java GUIs and provides an engine for creating them. You can use RIB to test and evaluate basic GUI layout and functionality, or to create and render GUIs for an application.

Hand-coding a GUI in the Java language can be a tedious and error-prone process, regardless of the widget set you use. It's far easier to use a markup language to specify GUIs. The IBM Reflexive User Interface Builder (RIB) is an application that constructs and renders Java AWT/Swing and Eclipse SWT GUIs based upon a descriptive XML document, referred to as a script. RIB is both a specification for a markup language in which to describe Java GUIs and an engine for creating and rendering them. You can use RIB as a standalone application to test and evaluate basic GUI layout and functionality, or as a library within the context of a Java application to create and render GUIs for the application.

This article is a brief introduction to the RIB application. We'll explain RIB's features and use two example RIB scripts to illustrate them. The examples are based on the Java 2 Swing framework for building GUIs, and all the embedded code is in Jython, a Java application that allows you to use the syntax and most of the features of the Python programming language (see Resources). Currently, RIB supports JavaScript/Rhino, Jython, and JRuby as scripting languages.

The power of RIB

Other XML script-driven Java GUI engines exist, but the power of the RIB approach stems from its reliance on the Java Reflection API, which allows classes to be introspected in order to reveal their public fields, constructors, and methods (see Resources). RIB can create and render GUIs based solely on the information in an XML document that doesn't require any predefined Document Type Definition (DTD) or XML schema.

In addition to the engine for creating and rendering GUIs, RIB also provides a validation engine, a feature you can use to validate properties of, and relations between, components. You can describe a set of constraints on components and then ensure that the components' behavior adheres to the constraints. For instance, RIB is packaged with an accessibility-validation mechanism. Such mechanisms can enhance your ability to develop, test, and evaluate GUI-based applications rapidly.



Back to top


RIB basics

Our first example script creates a simple GUI with two text fields and two buttons in a frame, as shown in Figure 1:


Figure 1. A simple GUI built with RIB
Sample GUI showing a name and email entry field and a Clear and Exit button

Listing 1 contains the XML document the RIB application uses to produce the GUI in Figure 1:


Listing 1. RIB script for a simple GUI
<?xml version="1.0"?>

<rib:gui
  xmlns:rib="com.ibm.wac.rgb"
  xmlns="swing"
  rib:scriptlang="jython"
  rib:architecture="swing"
>

  <rib:scripts>
    import javax.accessibility.AccessibleRelation as AccRelation
  </rib:scripts>

  <rib:aliases>
    <rib:alias
      rib:name="BorderLayout"
      rib:value="java.awt.BorderLayout"
    />
    <rib:alias
      rib:name="acName"
      rib:value="!getAccessibleContext!setAccessibleName"
    />
  </rib:aliases>

  <rib:objects>
    <Dimension rib:id="screenDim">300, 150</Dimension>
    <Color rib:id="bkgdColor">224, 224, 255</Color>
  </rib:objects>

  <rib:components>
    <Frame rib:id="mainFrame"
      size="@screenDim"
      title="RGB -- Sample 1 fddlkjlkdlkdflkd"
      background="@bkgdColor"
    >

      <getRootPane>
        <defaultButton button="@clearButton"/>
      </getRootPane>

      <addWindowFocusListener><windowFocusGained>
        nameField.requestFocus()
      </windowFocusGained></addWindowFocusListener>

      <getContentPane>
        <Panel rib:id="infoPanel" rib:constraints="NORTH"
          layout="%BorderLayout"
        >
          <Box rib:constraints="NORTH">
            swing.BoxLayout.X_AXIS
            <horizontalGlue/>
            <Label rib:id="nameLabel"
              text="Name:"
              labelFor="@nameField"
              horizontalAlignment="RIGHT"
            />
            <horizontalStrut width="4"/>
            <TextField rib:id="nameField"
              columns="20"
              toolTipText="Enter your full name"
              focusAccelerator="n"
            >
              <acName name="name input field"/>
              <acRelation rel="{AccRelation(AccRelation.LABELED_BY, nameLabel)}"/>
            </TextField>
            <horizontalStrut width="8"/>

            <Label rib:id="emailLabel"
              text="Email:"
              labelFor="@emailField"
              horizontalAlignment="RIGHT"
            />
            <horizontalStrut width="4"/>
            <TextField rib:id="emailField"
              columns="20"
              toolTipText="Enter your email address"
            >
              <acName name='email input field'/>
              <acRelation rel="{AccRelation(AccRelation.LABELED_BY, emailLabel)}"/>
            </TextField>
            <horizontalGlue/>
          </Box>

          <Box rib:constraints="SOUTH">
            swing.BoxLayout.X_AXIS
            <horizontalGlue/>
            <Button rib:id="clearButton" text="Clear"
              toolTipText="Clear the form fields">
              <mnemonic>
                awt.event.KeyEvent.VK_R
              </mnemonic>
              <addActionListener>
                nameField.text = ""
                emailField.text = ""
              </addActionListener>
            </Button>

            <horizontalStrut width="6"/>
            <Button rib:id="exitButton" text="Exit"
              toolTipText="Exit the app">
              <mnemonic>
                awt.event.KeyEvent.VK_X
              </mnemonic>
              <addActionListener>
                confirm = \
                  swing.JOptionPane.showConfirmDialog(
                  mainFrame, 
                  "Confirm Exit",
                  "Confirm Exit Dialog",
                  swing.JOptionPane.YES_NO_OPTION
                  )
                if confirm == swing.JOptionPane.YES_OPTION:
                  lang.System.exit(0)
              </addActionListener>
            </Button>
            <horizontalGlue/>
          </Box>
        </Panel>

      </getContentPane>
    </Frame>
  </rib:components>
</rib:gui>

This example begins with the RIB root <rib:gui> tag, which can have four child elements: <rib:aliases>, <rib:objects>, <rib:components>, and <rib:scripts>.

Aliases

The <rib:aliases> tag group lists the aliases the XML document uses. Aliasing comes in two forms: standard aliasing and method aliasing. In standard aliasing, RIB substitutes the value of the alias for the name. This substitution can occur in tag names or in attribute values. For instance, consider this alias definition from Listing 1:

<rib:alias rib:name="BorderLayout" rib:value="java.awt.BorderLayout"/>

Given this alias definition, when RIB encounters an element with the name BorderLayout, it uses the alias value for that token, java.awt.BorderLayout. RIB defines many standard aliases so, for example, you can write Button instead of javax.swing.JButton without defining an alias.

In method aliasing, aliases have a value that begins with an exclamation point (!), as in the following alias definition from Listing 1:

<rib:alias rib:name="acName" value="!getAccessibleContext!setAccessibleName"/>

When RIB encounters the name of a method alias in the XML document, it calls each of the methods listed in the value of that alias. When RIB encounters acName in the document in Listing 1, it calls getAccessibleContext().setAccessibleName(...) on the containing element's object.

Objects

You can use RIB's <rib:objects> tag to define objects that you use in multiple locations of the document. The simple script example in Listing 1 defines two objects, screenDim and bkgdColor:

<rib:objects>
    <Dimension rib:id="screenDim">300, 150</Dimension>
    <Color rib:id="bkgdColor">224, 224, 255</Color>
</rib:objects>

You can also define other objects as children in order to instantiate the object in question:

<Dimension rib:id="screenDim">
    <Point>300, 150</Point>
</Dimension>



Back to top


Creating a simple GUI

The example script in Listing 1 creates one GUI, defined by the <Frame> tag. Elements within the definition of a component perform one of the following two tasks (attempted in this order):

  1. They cause the instantiation of an object.
  2. They cause an invocation of a method of the object that is instantiated as a result of the parent element (or of an object returned by a method call initiated by the parent element).

This tag illustrates step 1 (creating objects):

<Frame rib:id="mainFrame" size="@screenDim"
   title="RGB -- Sample 1" background="@bkgdColor">

The tag creates a javax.swing.JFrame object. It is given an object ID of mainFrame, which you can use to refer to the JFrame in this XML document or to access the JFrame from within another Java class. The size, title, and background attributes are interpreted as properties of the JFrame object and cause RIB to invoke the setSize(Dimension), setTitle(String), and setBackground(Color) methods. Note the reference to the previously defined screenDim and bkgdColor objects.

This tag illustrates step 2 (initiating a method invocation):

<getContentPane>
   :
</getContentPane>

RIB invokes the getContentPane() method on the JFrame object that the parent element instantiates.

At this point, RIB continues to process the script, treating each element as an attempt either to instantiate an object or to invoke a method on an object. If instantiation is successful for some element, the newly formed object is "linked" to the parent element object. If the instantiation fails, the following algorithm is used to choose the method to invoke:

  1. Attempt to invoke the method with the exact name of the element.
  2. Attempt to invoke, in turn, methods with names based upon the element name.
  3. Attempt to set a public field with the given element name to the value specified in the single attribute or in the text content of the element.

Consider the next element in the document in Listing 1:

<Panel rib:id="infoPanel" rib:constraints="NORTH" 
       layout="%BorderLayout">

This element instantiates a javax.swing.JPanel object with a rib:id of infoPanel. You set the JPanel's layout by defining the attribute layout and setting its value to %BorderLayout, which RIB uses in turn to look up the alias you previously defined and obtain the value java.awt.BorderLayout. The rib:constraints attribute indicates where the newly formed JPanel should be placed within the context of the object generated by the parent element's layout. The JPanel's default LayoutManager is a java.awt.BorderLayout object that RIB uses to resolve the value of the rib:constraints attribute, java.awt.BorderLayout.NORTH.

Now examine another block of code from Listing 1:

<Box rib:constraints="NORTH">swing.BoxLayout.X_AXIS
    <horizontalGlue/>
    <Label rib:id="nameLabel" text="Name:"
       labelFor="@nameField" horizontalAlignment="RIGHT"/> 
    <horizontalStrut width="4"/>
    <TextField rib:id="nameField" columns="20"
      toolTipText="Enter your name" focusAccelerator="n">
       <acName name="name input field"/>
       <acRelation
          rel="{AccRelation(AccRelation.LABELED_BY, nameLabel)}"/>
    </TextField>
      :
</Box>

Several components are inside the <Box> tag:

  • The expression swing.BoxLayout.X_AXIS, which is used as a parameter to the Box constructor.

  • The <horizontalGlue/> tag, which initiates a call to the Box object's createHorizontalGlue() method, as step 2 of the preceding algorithm dictates.

  • The <Label> tag, which instantiates a javax.swing.JLabel object. The Label's text, horizontalAlignment and labelFor properties are set.

  • The next <horizontalStrut> tag, which causes RIB to invoke the createHorizontalStrut(int) method on the Box object with a parameter.

  • A JTextField object, which is instantiated and its properties set. Its rib:id permits the JLabel to refer to this JTextField. Notice the reference to method aliases in the child elements of the <TextField> element.

All of these objects are added, in order, to the Box object instantiated by the parent <Box> tag.



Back to top


Event handlers and executable code

The text content of any element in a script is treated by default as executable code written in a particular scripting language, such as Jython. Look at the code for the Clear button in Listing 1:

<Button rib:id="clearButton" text="Clear">
    <mnemonic>awt.event.KeyEvent.VK_R</mnemonic>
    <addActionListener>
      nameField.text = ""
      emailField.text = ""
    </addActionListener>
</Button>

The setMnemonic(int) method is invoked with the value returned by the Jython interpreter's evaluation of the expression awt.event.KeyEvent.VK_R. You can also treat the values of attributes as one-line expressions by including an opening and closing brace -- {...} -- in the attribute value. For instance, you can specify the layout of a JPanel like this:

<Panel ... layout="{awt.BorderLayout()}" ...>

More interestingly, you can attach an event handler to the Clear button by including the Jython code (some assignment statements in this case) in the <addActionListener> tag. Notice the ease of access to named tags (such as nameField) from code. Because an ActionListener implements only one method -- actionPerformed -- RIB uses the given code to implement this method. Note that all rib:id values, as well as many standard Jython and Java packages, are available to RIB scripts as predefined variables.

Now look at the following definition, which adds a java.awt.event.WindowListener to the root JFrame:

<addWindowListener>
   <windowClosing>lang.System.exit(0)</windowClosing>
</addWindowListener>

Unlike ActionListeners, WindowListeners must implement more than one method, as the interface dictates. Scripts distinguish between these methods by including elements with the name of the method being implemented.

After RIB builds the GUI that the script in Listing 1 defines, it can render the GUI in a number of ways. An application using the RIB library can call the show(String) method of the com.ibm.wac.rgb.engine.RgbEngine class to render the component with the given ID. If you execute the RGBuilder class from the command line, you can use the -show or -showAll switches to specify which GUIs are to be rendered.



Back to top


Building a more-complex GUI

Now you're ready to build a more-sophisticated GUI consisting of several panes in a javax.swing.JTabbedPane, a panel for buttons, and a menu bar with sample menus and menu items, as shown in the four parts of Figure 2:


Figure 2a. TabPane example showing a label
Sample TabPane GUI showing a label

Figure 2b. TabPane example showing an entry form
Sample TabPane GUI showing an entry form with name, address, city, state, and ZIP code

Figure 2c. TabPane example showing a table of names
Sample TabPane GUI showing a table of first, middle, and last names with three entries

Figure 2d. TabPane example showing a tree of nodes
Sample TabPane GUI showing a tree of nodes with several braches open

Although the GUI in Figure 2 exhibits quite limited functionality, it demonstrates the ease with which you can use RIB to produce and render more-sophisticated GUIs. Listing 2 contains the XML document for the GUI in Figure 2:


Listing 2. XML document for a sophisticated GUI
<?xml version="1.0"?>

<rib:gui
  xmlns:rib="com.ibm.wac.rgb"
  rib:scriptlang="jython"
  rib:architecture="swing"
>

  <rib:scripts>
    <rib:script
      rib:name="initScript"
      rib:file="examples/swing/tree.py"
      rib:exec="true"
    />
    <rib:script>
      def getCtrlKeyStroke (keyCode):
        return KeyStroke.getKeyStroke(
          keyCode, InputEvent.CTRL_MASK )
    </rib:script>
  </rib:scripts>

  <rib:aliases>
    <rib:alias
      rib:name="PVLayout"
      rib:value="com.ibm.wac.rgb.swing.PromptedValueLayout"
    />
  </rib:aliases>

  <rib:objects>
    <Dimension rib:id="screenDim">400, 300</Dimension>
    <Color rib:id="bkgdColor">224, 224, 255</Color>
    <Color rib:id="fgColor">255, 0, 255</Color>
    <PVLayout rib:id="pvLayout">
      [10, 10, 10], [5, 5, 5]
    </PVLayout>
  </rib:objects>

  <rib:components>
    <Frame rib:id="mainFrame"
      size="@screenDim"
      title="TabbedPane Sample"
      background="@bkgdColor"
      jMenuBar="{swing.JMenuBar()}"
    >
      <addWindowListener>
        <windowClosing>
        lang.System.exit(0)
        </windowClosing>
      </addWindowListener>

    <getJMenuBar>
      <Menu rib:id="fileMenu">"File"
      <mnemonic>KeyEvent.VK_F</mnemonic>
      <MenuItem
        accelerator="{getCtrlKeyStroke(KeyEvent.VK_N)}"
        text="new"
      />
      <MenuItem
        accelerator="{getCtrlKeyStroke(KeyEvent.VK_O)}"
        text="Open"
      />
      <MenuItem
        accelerator="{getCtrlKeyStroke(KeyEvent.VK_S)}"
        text="Save"
      />
      </Menu>
      <Menu rib:id="editMenu">"Edit"
      <mnemonic>KeyEvent.VK_E</mnemonic>
      <MenuItem
        accelerator="{getCtrlKeyStroke(KeyEvent.VK_X)}"
        text="Cut"
      />
      <MenuItem
        accelerator="{getCtrlKeyStroke(KeyEvent.VK_C)}"
        text="Copy"
      />
      <MenuItem
        accelerator="{getCtrlKeyStroke(KeyEvent.VK_V)}"
        text="Paste"
      />
      </Menu>
    </getJMenuBar>

      <getContentPane>
        <Panel rib:id="topPanel" rib:constraints="CENTER"
          layout="java.awt.BorderLayout"
        >
          <TabbedPane rib:id="tabPane" rib:constraints="CENTER">
          <addTab>
            <rib:arguments>
            <String>"Label"</String>
            <Label rib:id="testLabel"
              text="Label Text"
              horizontalAlignment="CENTER"
              foreground="@fgColor"
            />
            </rib:arguments>
          </addTab>

          <addTab>
            <rib:arguments>
            <String>"Form"</String>
            <Panel rib:id="addrPanel"
              rib:constraints="NORTH"
              layout="@pvLayout"
            >
              <Label rib:id="nameLabel"
                text="Full Name:"
                labelFor="@nameField"
                horizontalAlignment="RIGHT"
              />
              <TextField rib:id="nameField"
                columns="20"
                rib:constraints="@nameLabel"
              />

              <Label rib:id="addrLabel"
                text="Address:"
                labelFor="@addrField"
                horizontalAlignment="RIGHT"
              />
              <TextField rib:id="addrField"
                columns="20"
                rib:constraints="@addrLabel"
              />

              <Label rib:id="cityLabel"
                text="City:"
                labelFor="@cityField"
                horizontalAlignment="RIGHT"
              />
              <TextField rib:id="cityField"
                columns="15"
                rib:constraints="@cityLabel"
              />

              <Label rib:id="stateLabel"
                text="State:"
                labelFor="@stateField"
                horizontalAlignment="RIGHT"
              />
              <ComboBox
                rib:id="stateField"
                rib:constraints="@stateLabel"
              >
                ['AL', 'AR', 'CA', 'CO', 'MA', 'MI', 'TX', 'UT']
              </ComboBox>

              <Label rib:id="zipLabel"
                text="Zip/Postal Code:"
                labelFor="@zipField"
                horizontalAlignment="RIGHT"
              />
              <TextField rib:id="zipField"
                columns="10"
                rib:constraints="@zipLabel"
              />
            </Panel>
            </rib:arguments>
          </addTab>

          <addTab>
            <rib:arguments>
            <String>"Table"</String>
            <Panel rib:id="tablePanel"
              rib:constraints="CENTER"
             layout="java.awt.BorderLayout"
             >
              <ScrollPane rib:constraints="CENTER">
              swing.JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, \
              swing.JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS 
              <viewportView>
                <rib:arguments>
                <Table rib:id="dataTable">
                  [['Barry', 'A.', 'Feigenbaum'],
                  ['John', 'Q.', 'Public'],
                  ['John', '', 'Smith']
                  ], \
                  ['First', 'MI', 'Last']
                </Table>
                </rib:arguments>
              </viewportView>
              </ScrollPane>
            </Panel>
            </rib:arguments>
          </addTab>

          <addTab>
            <rib:arguments>
            <String>"Tree"</String>
            <Panel rib:id="treePanel"
              rib:constraints="CENTER"
              layout="java.awt.BorderLayout"
            >
              <ScrollPane rib:constraints="CENTER">
              swing.JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, \
              swing.JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS 
              <viewportView>
                <rib:arguments>
                <Tree rib:id="tree"
                  rib:constraints="CENTER"
                  showsRootHandles="true"
                >
                  <model mod="{defTreeModel}"/>
                </Tree>
                </rib:arguments>
              </viewportView>
              </ScrollPane>
            </Panel>
            </rib:arguments>
           </addTab>
          </TabbedPane>

          <Panel rib:id="buttonPanel" rib:constraints="SOUTH" 
                 layout="java.awt.BorderLayout">
            <Box rib:constraints="SOUTH">
            swing.BoxLayout.X_AXIS
              <horizontalGlue/>
              <Button rib:id="clearButton" text="Clear">
                <mnemonic>'r'</mnemonic>
                <addActionListener>
                   nameField.text = ""
                   addrField.text = ""
                   cityField.text = ""
                   stateField.selectedIndex = 0
                </addActionListener>
              </Button>

              <horizontalStrut>16</horizontalStrut>
              <Button rib:id="exitButton" text="Exit">
                <mnemonic>'x'</mnemonic>
                <addActionListener>
                   from javax.swing \
                   import JOptionPane
                   confirm = \
                   JOptionPane.showConfirmDialog(
                     mainFrame, 
                     "Confirm Exit",
                     "Confirm Exit Dialog",
                     JOptionPane.YES_NO_OPTION
                   )
                   if eq(confirm,
                   JOptionPane.YES_OPTION):
                     lang.System.exit(0)
                </addActionListener>
              </Button>
              <horizontalGlue/>
            </Box>
          </Panel>
        </Panel>
      </getContentPane>
    </Frame>
  </rib:components>
</rib:gui>

The model of the JTree (see Figure 2D) is set in the fourth <addTab> tag via the <model> tag. Notice that this value is interpreted because it is enclosed in braces. This is possible because the contents of the entire JTree are defined in the <rib:scripts> tag (and, in particular, in the tree.py file referenced by the <rib:script> child of the <rib:scripts> tag).



Back to top


Architectures and scripting languages

The rib:architecture and rib:scriptlang attributes of the root <rib:gui> tag embody two powerful features of RIB. One of RIB's most intriguing features is its support for multiple architectures for building GUIs. Put simply, an architecture is a framework for creating and rendering hierarchical structures such as GUIs. Currently RIB supports the AWT/Swing and SWT architectures. You can add other GUI architectures by implementing the com.ibm.wac.rgb.engine.arch.Architecture interface.

RIB supports the JavaScript/Rhino, Jython, and JRuby scripting languages. RIB uses the open source Apache Jakarta Bean Scripting Framework (BSF) to interpret script code, making it simple to add scripting-language support to RIB for BSF-supported languages. You can add BSF scripting languages by writing a class that extends com.ibm.wac.rgb.interp.CodeInterpreter and overwriting the appropriate methods.



Back to top


Validation with RIB

One of RIB's important and useful features is the ability to validate GUIs against user-specified sets of constraints. You can implement the com.ibm.wac.rgb.validate.Validator interface in order to verify that certain properties of, or relations between, a GUI's components conform to prespecified parameters. The validation mechanism gives you an evaluation and testing tool that can enhance rapid development and testing of GUIs.

You can use RIB to validate GUIs that it constructed via a script or GUIs constructed by some other means (such as custom code). You should use the com.ibm.wac.rgb.validate.ValidationEngine class for validation of GUIs not created by RIB.

The validation document

The basis for any validation process using RIB is an auxiliary XML document specifying the types of objects to be checked and the constraints according to which these objects are to be verified. The XML validation document follows the same conventions and uses much of the same language as a GUI-description document in RIB. For example, the validation document in Listing 3 specifies a constraint for a java.util.List:


Listing 3. Specifying a validation constraint
<?xml version="1.0"?>
<rib:validate>
  <rib:components>
    <java.util.List>
      <size rib:eq="5">
      <get rib:index="0">
      <get rib:index="4" rib:instanceof="java.lang.String">
    </java.util.List>
  <rib:components>
</rib:validate>

This simple (and atypical) example asks RIB to verify that the list has five elements, that the first element isn't null, that the last element is a String object.

You can specify other relations that can be tested by using the attributes rib:min and rib:max to specify a range, or the rib:regexp attribute, which takes a regular expression as a value against which to match the text of the property being tested.

A validation document's overall structure is quite similar to that of a script describing a GUI. You can validate properties of a particular component by including a rib:id attribute specifying the ID of a particular component in the element naming the class of that component.

Validating GUIs for accessibility

One subclass of the JavaGuiValidator that's packaged with RIB is com.ibm.wac.rgb.validate.AccessibilityJavaGuiValidator, which validates GUIs with components that implement the javax.accessibility.Accessible interface. This includes all Swing components (that is, those that are subclasses of javax.swing.JComponent).

The com/ibm/wac/rgb/validate/swing_accessibility.xml validation document included with the RIB package contains constraints for some of the more fundamental properties of and relations between components that must hold if a GUI is to be successfully rendered using assistive technologies.

When you run RIB from the command line, RIB invokes the validation mechanism after constructing and rendering the GUI. RIB generates messages that state when a component fails to meet the constraints you set for it in the validation document. For example, take the following script excerpt, which includes properties that aid assistive technologies in rendering text fields:

<TextField rib:id="nameField" columns="20"
  rib:constraints="@nameLabel" focusAccelerator="n">
  <acName name="name input field"/>
  <toolTipText tip="Enter your full name"/>
  <acRel>
    AccessibleRelation(AccessibleRelation.LABELED_BY,nameLabel)
  </acRel>
</TextField>

Then, remove the accessibility features (to cause validation errors and warnings deliberately):

<TextField rib:id="nameField" columns="20"
  rib:constraints="@nameLabel">
</TextField>

If you run the application now, the default accessibility validator generates the following output:

level.INFO: Beginning validation...
level.WARNING: [nameField] No value returned for property/method toolTipText
level.ERROR: [nameField] All text components should hold the LABELED_BY 
  relation to a javax.swing.JLabel
level.WARNING: [nameField] The first text component of any container can be 
  given a focus accelerator via setFocusAccelerator to aid in navigation
level.INFO: Validation complete.

The validator indicates the severity of the failure, followed by the name (object ID, in this case) of the component being validated in square brackets. The validator points out that the tooltip text of the component has not been set, that the text field doesn't hold the LABELED_BY relation to any other component, and that, as a first component in a group of components, it doesn't have a focus accelerator assigned to it. More information about these properties and how assistive technologies use them is available from the IBM Accessibility Center (see Resources).

If you restore the script to its original form, the validator produces this output:

level.INFO: Beginning validation...
level.INFO: Validation complete.

You receive no errors or warnings, which is precisely what you want and expect.



Back to top


Conclusion

RIB offers a powerful application for quickly creating, testing, debugging, and evaluating Java GUIs. Given its features, including the ability to support many scripting languages and a variety of architectures, RIB should prove a highly useful tool for developing and deploying GUI-based applications in the Java language. It can also enhance efforts to produce GUIs that assistive technologies can render effectively. We encourage you to download RIB (see Resources) and give it a try. Included with the download are more sample programs, including ones that use AWT and SWT, and a user's guide with installation and usage instructions.




Back to top


Download

NameSizeDownload method
j-ribsamples.zipHTTP
Information about download methods


Resources

  • Click on the Code icon at the top or bottom of this article to download the sample code for this article. In addition to the two GUI-building scripts, you'll find an XML document that specifies the criteria for determining the accessibility of a Java Swing GUI.

  • Download the latest version of the IBM Reflexive User Interface Builder (RIB) from IBM alphaWorks.

  • See the Java Tutorial's pages on the Reflection API for more information on the java.lang.Class and package java.lang.reflect classes.

  • "Introduction to Jython, Part 1: Java programming made easier" (developerWorks, April 2004) and "Introduction to Jython, Part 2: Programming essentials" (developerWorks, April 2004) introduce you to the Jython scripting language and provide you with enough knowledge to begin developing your own Jython-based applications.

  • The Jython Home Page is the official source for Jython downloads and documentation.

  • "alt.lang.jre: Get to know Jython" (developerWorks, July 2004) is the first article in a series introducing alternate languages for the Java Runtime Environment.

  • The IBM Accessibility Center's IBM Guidelines for Writing Accessible Applications Using 100% Pure Java provides information on properties that aid assistive technologies in rendering text fields.

  • "Enhance the accessibility of your GUIs" (developerWorks, July 2003) shows how to modify J2SE's Metal look and feel to accommodate special user needs, such as high-contrast or large fonts for the visually impaired.

  • "Coding for accessibility" (developerWorks, October 2002) demonstrates how to achieve a maximum level of accessibility with minimal effort, using a JFC/Swing-based accessibility toolkit.

  • "Get started with the AUIML Toolkit" (developerWorks, July 2004) introduces a rapid-development tool from alphaWorks that assists developers in writing GUIs to run as either Swing applications or on the Web, without any changes.

  • Find hundreds more Java technology resources on the developerWorks Java technology zone.

  • Browse for books on these and other technical topics.

  • Interested in test driving IBM products without the typical high-cost entry point or short-term evaluation license? The developerWorks Subscription provides a low-cost, 12-month, single-user license for WebSphere®, DB2®, Lotus®, Rational®, and Tivoli® products -- including the Eclipse-based WebSphere Studio® IDE -- to develop, test, evaluate, and demonstrate your applications.


About the authors

Author photo

Dr. Barry Feigenbaum is a member of the IBM Worldwide Accessibility Center, where he serves as a member of a team that helps IBM make its products accessible to people with disabilities. Dr. Feigenbaum has published several books and articles, holds several patents, and has spoken at industry conferences such as JavaOne. He serves as an Adjunct Assistant Professor of Computer Science at the University of Texas, Austin. You can contact Dr. Feigenbaum at feigenba@us.ibm.com.


Author photo

Dr. Michael Squillace is a member of the IBM Worldwide Accessibility Center, where he develops tools for enabling IBM's software products for accessibility. He holds a Ph.D. in philosophy and is currently a student at the University of Texas, majoring in computer science. He is also a professional pianist and is blind. You can contact Dr. Squillace at masquill@us.ibm.com.




Rate this page


Please take a moment to complete this form to help us better serve you.



YesNoDon't know
 


 


12345
Not
useful
Extremely
useful
 


Back to top