Designing a Smarter UI Action Framework

First of all let me apologize for the silence over Christmas(plus a bit) - a snowboarding accident, moving house, seeing family, its amazing how much time these things take!

In my previous post on designing a UI action framework we got started on a simple way to separate actions from the UI and put it all together. Brilliant, but you cant help but think we can make it better…

Lets say a user has a simple text editor, they may have kindly set up a save action that opens a file browser and puts the contents of the editor into a file, they may have a file menu with a save menu item and maybe a toolbar button that runs the same action, but what if the user hasn’t entered any text? You could disable the menu and toolbar button but that means our logic is getting mixed in with our interface, if you cant save then it makes sense that the save action cant be run not that the buttons are turned off.

So this is how we make our system smarter, now we will improve our tiny framework a bit so that actions can be turned on or off and the UI can reflect that. Please take care though, its easy to keep adding to a framework and end up with a huge load of classes that can do millions of things but make it very complicated, here were going for something small, compact and efficient.

First of all we need to modify our IAction class and its sub actions so they hold a state and also so we can manipulate that state to enable or disable them. Planning ahead we also then need to notify anything that’s interested about state changes, so we will provide a listener type system for this. Add these methods to your interface:

void setEnabled(boolean enabled);

void addActionStateListener(IActionStateListener listener);

Dont forget to knock up the interface for the listener too:

public interface IActionStateListener {
void stateChanged(String actionID, boolean enabled);
}

Not the most challenging code ever written but it does allow you to turn things on and off, and allows you to listen to that event (you can write methods to remove listeners etc easily)

Now that we can turn our actions on and off the next real task is to reflect this in the UI, there are 2 ways of doing this. First each UI component can be created, its action performed can call the action manager (as in the previous post on this topic) and it can also add and react to its listeners. Thats great if you building a tiny system, if your adding more than just a handful of buttons and menu items I would suggest you subclass that item and move this logic into that, making your UI code a lot neater and shirinking your codebase.

As the first option is easy i’m sure you can figure it out, so ill take the 2nd approach and subclass the UI objects just to demonstrate how this can be done, in this case ill hook up a menu item that can do all this reacting to the actions.

public class MyMenuItem extends JMenuItem {
    private static final long serialVersionUID = -2941768987720461279L;
private final String actionId;
    public MyMenuItem(final String label, final KeyStroke accelerator, final String actionId) {
super(label);
super.setAccelerator(accelerator);
this.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent e) {
ActionManager.getInstance().runAction(actionId);
}
});
        // save the action id for this button
this.actionId = actionId;
        // listen for action updates
hookActionListener(this);
}
    private void hookActionListener(MindMapMenuItem item) {
        ActionManager.getInstance().addActionStateListener(new IActionStateListener() {
public void stateChanged(String actionID, boolean enabled) {
// react to the changes if applicable
if (actionID.equals(MyMenuItem.this.actionId)) {
MyMenuItem.this.setEnabled(enabled);
}
            }
});
}
}

The final stage of this UI is to hook it all together, for this is just add a simple listener to my text area that forces me to check for data as the user types, I then go via the action manager to update the state of my action and watch the UI react to that change!

Ok now our UI is becoming smart, it reacts to the user and is really starting to look like a nice little application given the tiny amount of code we have written. It also scales up quite nicely for fairly meaningful peices of software.

In my final post ill show you how we can take this simple word editor and using some fantastic external libraries and coding tricks turn our smart UI into something smart AND beautiful.

I’ll also provide full source code so if your not able to follow this then you can just click run and see it in action.

Leave a Reply

You must be logged in to post a comment.