The Source for Java Technology Collaboration
User: Password:
Register | Login help    

Search

Online Books:
java.net on MarkMail:


 E-mail  Print

Introducing JAXX: A New Way to Swing

Thu, 2006-03-30

{cs.r.title}



Swing can be an interesting beast to work with. On the one hand, it's a slick, fast, fantastically powerful component library that is flexible enough to do almost anything. On the other hand, its ease of use can best be summed up with one word: GridBagLayout. When this famously complex and difficult to use layout manager is actually the most useful one that Java includes, it's a sign that trouble lies ahead. In many ways Swing is a work of art, but unfortunately its beauty tends to get buried underneath a layer of too-complex layout managers, anonymous inner classes, and low-level tweaking. How do you manage this complexity? Enter JAXX.

JAXX is a free, open source XML user interface language for Java. Instead of writing .java files representing Swing components, you instead write XML-based .jaxx files. Just like .java files, .jaxx files compile into ordinary Java classes. So how does JAXX improve upon Java?

  • XML files are naturally tree-based. Tags contain other tags just like components contain other components.
  • JAXX manages event handling and data binding for you--no more having to manually create anonymous inner classes to handle events.
  • The <Table> tag provides GridBagLayout's power in an easier-to-use package.
  • Comprehensive CSS support allows you to separate style and content, and re-skin your programs just by switching stylesheets.
  • JAXX files are much shorter and easier to read than equivalent Java code.

Getting Started

Let's start with a simple example:

Hello.jaxx

<Application title='Hello'>
  <VBox horizontalAlignment='center' 
        margin='6, 6, 6, 6'>

    <JLabel text='Hello, World!' 
            foreground='red' 
            font-size='24'/>
            
    <JButton text='Close' 
             onActionPerformed='dispose()'/>

  </VBox>
</Application>

And then we can compile and run the example as follows:

> jaxxc examples\Hello.jaxx
> java -cp .;\jaxx\lib\jaxx-runtime.jar examples.Hello

You must include jaxx-runtime.jar on the class path, but otherwise run the example class normally. When run, it appears as shown in Figure 1.

Simple JAXX application
Figure 1. Simple JAXX application

This example is a complete, working JAXX application that shows off many of JAXX's basic features. Each of the four tags in the file is the name of a Java class--Application (a subclass of JFrame) and VBox (a vertical box) are bundled with JAXX, while JLabel and JButton are built-in Swing classes--and all of them mean the same thing: "create an instance of this class." You can specify the name of any Java class within a tag, and as long as it's on jaxxc's class path, JAXX will find it and use it. Package names are handled just like in Java: the <JLabel> tag could be fully qualified as <javax.swing.JLabel>, but javax.swing is imported by default so in this case it isn't necessary.

Once JAXX loads a class, it follows some basic rules to figure out how to use the class. If it's a component and it appears within a container, JAXX will automatically add it to its parent container. XML attributes like text='Hello, World! are automatically mapped to set methods like setText("Hello, World!"). JAXX follows standard JavaBeans rules for identifying properties and events, so it works best with classes that follow standard Java naming conventions. Other classes will still work, but may require a bit of help from scripting (more on this later).

Because the root tag in Hello.jaxx is <Application>, the compiled class examples.Hello extends Application (and therefore Application's superclass, JFrame). In addition to the main() method that JAXX automatically gives to all Applications, it has all of the methods and fields one would expect of a JFrame, and can be used from Java code just like any other JFrame. You don't have to do anything special to use JAXX classes from within ordinary Java classes, as they are also Java classes.

While JAXX can load and use any Java class, it is primarily intended to create Swing user interfaces. The Swing components have all been carefully tested to ensure that they work well from within JAXX, and JAXX has special support for some of them so they are easier to work with. Full support for other component libraries (AWT and SWT) is planned for future versions of JAXX. Given that JAXX features no special support for AWT components, they work surprisingly well--but SWT users will have to wait for proper support.

Scripting

Notice the onActionPerformed='dispose()' in Hello.jaxx, which causes the Close button to dispose of the window when clicked. This is an example of scripting, the ability to directly include Java code in JAXX files. JAXX scripts use ordinary Java syntax and are fully compiled. Here is a more advanced example of scripting:

Greeter.jaxx

<Application title='Greeter'>
  <script>
    protected void showGreeting() {
        String name = nameField.getText();
        JOptionPane.showMessageDialog(this, 
                     "Hello, " + name + "!");
    }
  </script>
  
  <VBox margin='6, 6, 6, 6' spacing='6'
                 horizontalAlignment='center'>
    <HBox>
      <JLabel text='Your name:' 
              displayedMnemonic='Y'
              labelFor='{nameField}'/>

      <JTextField id='nameField'/>
    </HBox>

    <JPanel layout='{new GridLayout(1, 0, 6, 0)}'>
      <JButton text='Greet!' mnemonic='G'
           onActionPerformed='showGreeting()'/>

      <JButton text='Close' mnemonic='C'
        onActionPerformed='dispose()'/>
    </JPanel>
  </VBox>
</Application>

Figure 2 shows the result of compiling and running this class.

The Greeter example uses scripting to display a dialog
Figure 2. The Greeter example uses scripting to display a dialog box

This example makes much heavier use of scripting (highlighted in bold). In addition to onActionPerformed event handlers, there are two new kinds of scripting:

  • The <script> tag, which allows arbitrary Java code to be embedded. Methods and fields defined in <script> tags become "real" methods and fields of the compiled class, and can (unless private) be accessed by other Java classes.
  • Attributes can be assigned Java expressions escaped by curly braces, as in layout='{new GridLayout(1, 0, 6, 0)}'. This allows you to embed any type of data in an XML attribute, even complex types like LayoutManager.

Because JAXX uses Java as its "scripting" language, JAXX scripts can do anything normal Java code can do. And because they are fully compiled, they run as fast as any other Java code. With JAXX's ability to invoke any Java code using scripts, and the fact that .jaxx files compile into Java classes that can be used normally by Java code, integrating JAXX classes into Java applications is virtually effortless.

Data Binding

As you just saw, XML attributes can be assigned to Java expressions that are evaluated at run time. This makes perfect sense for static expressions like new GridLayout(1, 0, 6, 0), but what happens when you use an expression whose value can change?

DataBinding.jaxx

<Application title='Data Binding'>
  <Table anchor='west'>
    <row>
      <cell>
        <JLabel text='Red:' labelFor='{red}'
            displayedMnemonic='R'/>
      </cell>
      
      <cell>
        <JSlider id='red' maximum='255'/>
      </cell>
      
      <cell rows='3'>
        <JPanel width='64' height='64'
            border='{BorderFactory.
                        createEtchedBorder()}'
            background='{new Color(red.getValue(),
                            green.getValue(),
                            blue.getValue())}'/>
      </cell>
    </row>
    
    <row>
      <cell>
        <JLabel text='Green:' labelFor='{green}'
            displayedMnemonic='G'/>
      </cell>
      
      <cell>
        <JSlider id='green' maximum='255'/>
      </cell>
    </row>

    <row>
      <cell>
        <JLabel text='Blue:' labelFor='{blue}'
            displayedMnemonic='B'/>
      </cell>
      
      <cell>
        <JSlider id='blue' maximum='255'/>
      </cell>
    </row>
  </Table>
</Application>

Pay particular attention to the background attribute of the JPanel, which creates a Color based on the three sliders' values. Move your mouse over Figure 3 to see what happens when the sliders are manipulated (requires JavaScript).

Manipulating the sliders causes the color to change automatically
Figure 3. Manipulating the sliders causes the color to change automatically (mouse over to see animation)

This is called data binding. During compilation, JAXX parses the Java expression to find all of its dependencies (such as red.getValue()) and adds event listeners to detect when they change. When the expression's value changes, the new value is plugged in automatically. Almost any property of any tag can be computed in this fashion. Suppose we want to enhance the Greeter.jaxx example above so that it no longer allows you to greet a blank name ("Hello, !"). The best way to do this is to disable the "Greet!" button when there is no name entered:

<JButton text='Greet!' mnemonic='G'
   onActionPerformed='showGreeting()'
   enabled='{nameField.getText().length() != 0}'/>

This simple change automatically enables the "Greet!" button when the nameField field is not empty, and disables it otherwise. Other things you can do with data binding:

  • Display a detailed view of the selected item in a list.
  • Apply user preferences such as font size.
  • Automatically display a wait cursor whenever the application switches into a busy state.
  • Update the title bar to reflect the currently active file.
  • Automatically update progress bars.
  • Pre-fill form elements.

It's hard to overstate the value of data binding. Virtually anywhere that an event causes a property to change, you can replace Java's verbose event handling with a simpler, easier-to-read data binding expression. Of course, JAXX isn't psychic. Not only must the property to be tracked fire an event when modified, but JAXX must know which event that is so that it can add the appropriate listener. Fortunately, JAXX knows how to track almost every property of every Swing component, and can automatically track all bound properties (properties that fire PropertyChangeEvent when modified), even on classes it has never seen before. The JAXX website lists which properties can be tracked for each and every Swing component.

Stylesheets

JAXX allows you to separate content from appearance, much like HTML does, by using CSS stylesheets. JAXX's stylesheets can set any of an object's properties, and allow any number of objects to be styled at once using simple rules. Stylesheets also allow you to easily create dynamic behaviors. Let's take the DataBinding.jaxx example above and add a stylesheet to it:

DataBinding-stylesheet.jaxx

<Application title='Data Binding'>
  <style source='databinding.css'/>
  
  ...
</Application>

databinding.css

Application {
  lookAndFeel: system;
}

JSlider {
  paintTicks: true;
  minorTickSpacing: 10;
  majorTickSpacing: 50;
  border: {BorderFactory.createLineBorder(
                Color.black, 1)};
}

#red {
  background: red;
}

#green {
  background: green;
}

#blue {
  background: blue;
}

Compare the program's unstyled appearance in Figure 3 to its new look in Figure 4. Okay, it's a bit much, but it demonstrates how easily you can change a program's appearance by applying a stylesheet. Further, we were able to make all of these visual changes without having to modify the program itself (other than to add the <style> tag).

A stylesheet can completely change a program's appearance
Figure 4. A stylesheet can completely change a program's appearance

Each rule in a CSS stylesheet begins with one or more selectors, like JSlider or #red. The selector describes which components are affected by the rule. JAXX supports four different kinds of selectors:

Type Syntax Description
Java class classname Selects all instances of the specified class (or a subclass)
ID #id Selects components with the attribute id='<id>'
Style class #styleclass Selects components with the attribute styleClass='<styleClass>'
Pseudoclass :mouseover, :focused, and others Dynamically selects components based on their current state

A selector is a special kind of expression that evaluates to true or false for any given component. True means the component is affected by the rule, false means it isn't. The four basic kinds of selectors can be combined to form compound expressions:

  • JButton.cancel: Applies to instances of JButton (or a subclass) that have styleClass='cancel'.
  • #display:disabled: Applies to the component with the ID display whenever it is disabled.
  • AbstractButton.large:selected: Applies to all subclasses of AbstractButton with styleClass='large' when they are selected.

JAXX's stylesheet support is very similar to HTML's. The biggest difference is that instead of applying HTML-specific properties like padding and color, you apply JAXX-specific properties like border and foreground--the same properties you can specify directly on tags. JAXX also takes CSS pseudoclasses, an underutilized feature that allows you to dynamically style links, and extends them so that they work with every component and can respond to almost any event.

CSS Pseudoclasses

Let's use CSS pseudoclasses to make DataBinding-stylesheet.jaxx less visually overwhelming:

DataBinding-pseudoclass.jaxx

<Application title='Data Binding'>
  <style source='databinding-pseudoclass.css'/>
  
  ...
</Application>

databinding-pseudoclass.css

Application {
  lookAndFeel: system;
}

JSlider {
  paintTicks: true;
  minorTickSpacing: 10;
  majorTickSpacing: 50;
  border: {BorderFactory.createEmptyBorder(1, 1, 1, 1)};
}

JSlider:focused {
  border: {BorderFactory.createLineBorder(Color.black, 1)};
}

#red:focused {
  background: #E7ADAD;
}

#green:focused {
  background: #B2E7AD;
}

#blue:focused {
  background: #ADB2E7;
}

Notice that we have added the :focused pseudoclass to several of the rules. The selector #red:focused means "Components that have an ID of red and currently have focus," which causes the rule to be dynamically applied and unapplied as the focus changes. Mouse over Figure 5 to see this in action (requires JavaScript).

CSS stylesheets make dynamic behaviors easy
Figure 5. CSS stylesheets make dynamic behaviors easy (mouse over to see animation)

JAXX supports a number of different pseudoclasses:

  • mouseover
  • mouseout
  • mousedown
  • mouseup
  • enabled
  • disabled
  • focused
  • unfocused
  • selected
  • deselected
  • armed
  • unarmed
Each pseudoclass is, in some sense, a true/false decision. Is the mouse over the component, or isn't it? Is it focused, or not? In addition to all of these implied true/false values, JAXX enables you to specify an explicit true/false expression, like this:
<style>
    JSlider#powerLevel:{object.getValue() > 100} {
      background: red;
    }
 <style>

It appears in the same place a normal pseudoclass would, except that it is a Java expression escaped by curly braces. This causes the powerLevel slider to turn red if its value goes over 100. This sort of pseudoclass is called a programmatic pseudoclass, and it gives you ultimate flexibility in deciding whether a style should be applied to any given object. JAXX's data binding system is used to track changes to the expression, so programmatic pseudoclasses support exactly the same set of properties that data binding expressions do. Internally, most of JAXX's pseudoclasses are implemented as programmatic pseudoclasses--the focused pseudoclass, for instance, is exactly equivalent to {object.hasFocus()} (but easier to remember).

Conclusion

JAXX is designed to replace (or at least augment) hand-coded Swing components, with flexible, general-purpose capabilities like data binding and CSS stylesheets that are easy to learn and yet tremendously powerful. JAXX files are typically a fraction of the size of equivalent Java files, while being easier to read and maintain. As JAXX tags are for the most part just the names of Java classes, and its attributes are generally just the names of Java properties, there is very little new syntax to learn--if you know Swing, you already know most of JAXX's syntax.

You can think of JAXX as being, in a way, an alternative syntax for Java--one with a lot more power when it comes to creating user interface components. Despite the different syntax, JAXX files are still Java classes. They are fully compiled and run just as fast as normal Java code. Java classes can reference JAXX classes without any special effort (since compiled JAXX files are ordinary Java classes), and likewise, JAXX files can include any Java classes without any special effort. This means that JAXX classes can be seamlessly added to any application, in any role, from creating a single dialog box to handling the entire user interface.

Resources

Ethan Nicholas is the lead engineer for the Yahoo! Publishing Tools team, and was the original author of the Swing-based Yahoo! SiteBuilder web design application.
Related Topics >> GUI      
Comments
Comments are listed in date ascending order (oldest first)