SwingFast

SourceForge.net Logo

Large Swingfast update to come soon! Expecting alpha release Q1 2008.

When it comes to choosing a language/technology to create a GUI application, Swing is an increasingly good choice. First, it is based on Java, which adapts well to complex projects with multi-threading. Second, it is automatically portable: if done correctly, the same app will work in Windows, Linux, Mac (the Mac’s Swing is looks very neat!). It is often criticized for being slow (compared to eclipse’s SWT) and having “grey areas” refresh issues, but it has made a lot of progress. Just try Netbeans to see a fast and sleek Swing application!

SwingFast’s features include:

  • menus & forms creation through XML files
  • easy layout of components
  • load & save with XML files
  • access to resources (files, icons, …) is centralized and clean
  • handling of background threaded tasks, which can be one-time or repetitive.
  • logging using Log4j

Issues with Swing

The standard Swing library provides basic buttons & graphics to build GUI applications, as well as thread-safe methods to update components. And that’s about it. If you want to code “manually” you end up doing a lot of repetitive tasks: creating, placing, updating elements, etc. Just creating forms manually and coupling them with configuration files can be a very long task.

A second issue is the layout of the Swing components. You can choose between several layouts to organize your components: Border, Box, Grid, GridBag, etc. But in the end all of them have problems, are not consistent with sizing and alignment rules and don’t interact well when nested. Just creating nested components with proper alignment and sizing can be a major pain! (Ok it is still much better than CSS layout…)

Possible solutions

GUI Builder

Netbeans has a GUI builder, formerly known as Matisse. Basically you put together your application and forms graphically, by dropping and moving components. Pretty much the same way as you would do in Microsoft’s Visual Studio or certain VBA editors.

Advantages:

  • Easy to create forms and manipulate components to obtain the layout you want.
  • Makes use of a special layout manager GroupLayout which doesn’t exist in the standard JVM. Basically it enables to organize elements by horizontal and vertical groups, which is pretty flexible and powerful but more complex.

Disadvantages:

  • It does not simplify anything in the code! It only does components creation and layout.
  • It is easy to “break” the layout if you play too much with the editor, and get weird results.
  • The code to create the GUI is “dumped” in your source files, and you are not supposed to change it manually. The resulting code is very heavy & ugly, with hard-coded values everywhere. The GroupLayout complexity does not help either.
  • Since the layout is in the source files, you have to modify the code and recompile if you need to tweak it.
  • It is difficult to do batch changes to a group of components, for example if you decide that all the buttons should have a new width. Matisse does a god job at that, but it is not perfect.

XML based solutions

XML based solutions, like JFCML, revolve around a neat concept: you can specify your layout & forms in XML files and it will be interpreted by an introspective Java library or a compiler to create your GUI app.

Advantages:

  • A lot of the program is in configuration files, which means you can easily modify them as a batch without the need to recompile anything.
  • Your application becomes truly dynamic: you can update a lot of the program in real-time.
  • It standardizes the look and feel of your applications.

Disadvantages:

  • Entering the Java code in XML files is not appealing at all. Basically you end up loosing the IDE help and features, and your code is not compiled. A lot of errors can show up when you launch your application! You loose a lot of what makes Java strong.
  • It does not help you manipulate the components after the creation. With certain libraries you can access your elements using the String name you gave them in the XML files, which is error prone. A typo might not be discovered until demo day…

Introducing SwingFast

When I started working on swing applications, I immediately felt the need to create a library to help with the annoying and repetitive tasks. I did not like the solutions described before: one has too much code & too little data and the other one too little code & too much data. Consequently I decided to create my own solution.

When designing SwingFast, I tried to apply the following principles:

  • Make it easy and clean in the Java source code.
  • Make it easy not only for the GUI creation but all along the program.
  • Move as much as possible of the layout & forms in XML configuration files.
  • Use the same XML “engine” for the app creation, load and save.
  • Keep all the IDE (completion) and compiler (errors) help. After your program is compiled and started, you know that your app will not crash on a basic mistake.
  • Try to keep the application fast.

To achieve this result, I am using the following elements:

  • JASIX to tightly couple the object and its XML representation.
  • Enums: very clean & easy for the programmer, efficient for program speed, checked by compiler, completed by IDE.
  • Generics: make the code robust and clean.

How does it work?

Let’s take a look at 2 quick examples.

Buttons

Buttons can be a pain to layout in Swing. With SwingFast you first declare an enum:

    enum Buttons {
        Start,
        Stop,
        Pause,
        Forward,
        Back,
    }

Create a ButtonGroup with an axis and an alignment. Then add it to the panel you want.

        ...
        ButtonGroup bGroup = new ButtonGroup(Buttons.values(), Common.Axis.X, Common.Align.CENTER, this);
        panel.add(bGroup.getComponent());
        ...

Then you can define the behavior with a neat ActionPerformed function:

    public void actionPerformed(Buttons enm, AbstractButton src) {
        switch (enm){
            case Start:
                ...
            case Stop:
                ...
            case Pause:
                ...
            case Forward:
                ...
            case Back:
                ...
        }
    }

That’s about it! The code is clean, easy, and safe. The default is for the button to have the text of its enum. Don’t worry, there are methods to set a specific text or icon for a button. Also, enums can be modified project-wide in a blink through refactoring.

Menus

Let’s now think of a more complex example: you need a menu bar with menus for your application and you want to be able to save or load its complete state. First you define your menu bar with an XML file. Takes a minute:

<MenuBar>
    <Menu id="file">
        <MenuItem id="exit"/>
    </Menu>
    <Menu id="options">
        <MenuItem id="pref" label="Preferences"/>
        <MenuCheckBox id="log" label="Enable Logging"/>
        <Menu id="view">
            <MenuCheckBox id="grid"/>
            <MenuCheckBox id="ruler"/>
        </Menu>
    </Menu>
    <Menu id="help">
        <MenuItem id="about"/>
    </Menu>
</MenuBar>

Then create an enum with the items of the menu you want to control. The library will print a warning if one of the active menu items does not have an enum associated.

    enum Menus {
        exit,
        pref,
        log,
        grid,
        ruler,
        about
    }

Create a MenuBar and initialize it with the XML file. Then add it to the component you want.

    MenuBar bar = new MenuBar(null, Menus.values(), this);
    bar.xmlLoad(filename);
    frame.setJMenuBar(bar.getComponent());

Then you can define the behavior with a neat ActionPerformed function:

    public void actionPerformed(Buttons enm, AbstractButton src) {
        switch (enm){
            case exit:
                ...
            case pref:
                ...
            case grid:
                ...
            case about:
                ...
        }
    }

Last but not least, you can save or load the state of the whole menu structure with a simple method at any time. The corresponding action events will be automatically generated.

    // save
    bar.xmlSave(filename);
    // and load
    bar.xmlLoad(filename);

Work in progress!

I hope my quick summary and examples will make you want to know more about this library. It is not yet ready for a release but I am working on it!

Comments are closed.

Trackback this Post |