My (mini) GUI framework proposal

Hello,

As a hobby I started a stand-alone java music application that allows to edit a music lead sheet (list of chords like "Cm F7"), select a rhythm and some instruments, and generate a MIDI accompaniment for that leadsheet (for those who know, it's a bit like the "Band In A Box" program). GUI is quite classical : JFrame with menubar, toolbars, status bar, main content pane being split in a "playback settings" pane (e.g. instruments) and a "music leadsheet editor" pane. There are also numerous Dialogs used for app configuration or controlling some special modes (record mode etc..).

The application getting bigger and bigger, I realized I had to review completly my GUI architecture, because it was more and more difficult to extend (though I always tried to separate views from application logic using kind of controllers).

After some search on the web (MVC/HMVC models, design patterns, UI frameworks etc...), I came up with a rough idea of an architecture that I hope would suit my needs (extendable but not too heavy). As I'm really not sure it's the right way to go, I thought I could expose my plans here and maybe get feedback from experienced people in java GUI development. Thanks in advance !

0) GUI is decomposed in GUI modules (I guess they are the "views" of the MVC model)

A GUI module is a high-level brick of the application GUI, e.g. a JDialog, the "leadsheet editor" panel, the "midi settings" panel.

1) Each GUI module has a Controller object and a model

Controller has a direct reference to its GUI module, but GUI module does not have a direct reference to its Controller.

Controller registers its GUI module to get change events due to user input.

Both Controller and GUI module have a direct reference to the model and register it to get model change events.

2) Actions, toolbars, menus are defined in an actions.xml file (see http://www.javadesktop.org/articles/actions/index.html)

Actions are loaded at runtime into a Singleton instance of an ActionManager.

When possible the Swing components that compose a GUI module are built from these actions (e.g. JMenu, JButton...). For Swing components that do not support Actions (e.g. JSpinner), the GUI module offers some "addChangeListener()" functions to allow the Controller to receive the JSpinner changes.

3) Using the ActionManager, the Controller registers each Action he's responsible for

The actionXXXPerformed() will:

IF action don't need to change the model (e.g. navigation event) THEN

- call GUI module functions to update the view (e.g. move the focus to the next "chord" in my leadsheet editor)

END IF

IF action needs to change the model (e.g. change the value of a chord)

- call the change_XXX() function in the Controller

- the GUI module will be automatically notified of the model changes as it registered the model to get change events

END IF

4) All changes to model are made thru Controller's change_XXX() functions

The change_XXX() function will:

- Start an undoable Coumpound Edit

- get some information from the GUI module (e.g. get the list of selected "chords" in my leadsheet editor)

- update the model (e.g. change the value of the selected "chords" in the leadsheet model)

- End the undoable Coupound Edit

- fire a UndoableEditHappened() (listened by a Singleton instance of an UndoManager used by all the application)

In the Controller, separating the actionXXXXperformed() from change_XXXX() allows that even if change_XXX() is called programmatically, it is still "undoable".

6) The Controller enables/disables the actions he's responsible for depending of the application state

I'm not sure for this : maybe it would be better to let the ActionManager do this in a centralized way (as the actions.xml file already centralizes all the actions of the application), but I feel it would be too much logic in one place, so I preferred to assign some Actions to each Controller and let the Controller manage its own actions only.

7) All Controllers register an "EventBus" (see http://projects.d-haven.org/modules/mydownloads/index.php)

In case an event managed by Controller X is also needed by other Controllers, Controller X will generate a PropertyChangeEvent on that bus. Controllers that have registered the bus for such events will receive it.

8) If we have Module GUI X-Controller X and Module GUI Y-Controller Y, Controller X can't directly get some information from Module GUI Y, he must get the information from Controller Y

This is because I believe a Controller is less likely to evolve than a Module GUI, so less maintenace problems.

However it can happen that due to a redesign the information hold by Controller Y will be now managed by Controller Z, and I'll have to update Controller X accordingly. To avoid this coupling, I would need a kind of protocol on the EventBus to send the request "GET_INFO(XXXX)", then a Controller I don't have to know could take the request and reply with a new message on the bus. But this solution seems too heavy for my problem.

[5220 byte] By [lelasseuxa] at [2007-10-1 20:58:31]
# 1

It sounds like you may be where I was three years ago, trying to cope with increasing GUI complexity as an application develops.

There is a surprising lack of standard solutions to this problem, possibly because of the huge variety of possible applications. However I have had a go at a general solution, demonstrated at http://superficial.sourceforge.net.

The demo is only an applet, but the general principle can easily be adapted for free-standing applications, even MDI.

Perhaps this will be of help to you.

dimwighta at 2007-7-13 2:55:27 > top of Java-index,Other Topics,Patterns & OO Design...