GRAPHICAL USER INTERFACE DESIGN


Terms and conditions for using and even looking at this homepage
Homepage index | Programming | 3D Graphics | Music | My CV | WebLinks

Graphical User Interface design - contents


Introduction

This document describes some of the ideas that I have for designing a Graphical User Interface (GUI). The ideas concern the internal architecture and implementation design of the GUI.

In this text I often use the term GUI-Control. By this I mean a complete functioning entity within the userinterface that the user can interact with. This includes all of it's internal implementation details. Examples of GUI-Controls might be: Buttons, listboxes and textfields.


Description of the classical Model/View/Controller (MVC) architecture

Today many GUI-development tools and API's use the structure of the classic Model/View/Controller architecture or some derivative form of it. Other tools simply aren't using any particular structure. If there is no such structure all GUI-controls are rather independant objects with no common functionality. This usually means that there is less reuse of code and less consistency in the GUI both regarding look and feel.

I have included this description so that it can serve as background knowledge for presenting my ideas. There is a lot of information available about this classical MVC architecture so this is just a basic description.

In this acrhitecture the userinterface is split into a Model part, a View part and a Controller part. In this text I will assume that this split is done internally in each GUI-Control, so that a GUI-control can be considered as a single complete object.

The Model

This entity takes care of storing the data of a GUI-Control. In the example of a checkbox, the data to be stored might be the text of a label and an up/down state of the checkbox. One checkbox model might store this data in memory while another could store it in a database.

When the model part of a GUI-Control is separate it becomes possible to reuse the rest of the code in the GUI-Control whether the data of the GUI-control is stored in memory, in a database or somewhere else.

The View

The View entity defines how GUI-Controls look. It draws GUI-Controls on the screen and refreshes them as needed. It has to be able to both reflect changes in the Model and display user interactions.

A good reason to separate the View from the rest of a GUI-Control is to be able to define GUI-Controls which contains the same data, and works the same way as other GUI-Controls but looks different. An example could be to replace the view of a checkbox to make it look like a toggle button. They have similar data and functionality: They can both be toggled and usually have text-labels.

The Controller

The functionality of a GUI-Control is defined in the Controller entity. It represents all logic and userinteraction of a GUI-Control. It translates userinput into how and when the GUI-Control should change apperance and how the data in the Model is altered. In short it defines the "feel" of a GUI-Control.

By replacing a controller in a GUI-Control you can change the way it behaves, without changing it's look and how it stores data in the model. It would for instance be possible to replace the controller in a togglebutton, to change it to a pushbutton. It still looks the same and is still a button, but it behaves differently.


A modified MVC architecture: The Container/Model/Cell/Editor architecture

This architecture is an alternative to the classic MVC arhcitecture. The Container/Model/Cell/Editor architecture is derived from the Model/View/Controller architecture. The Model-part remains the same, but the View and Controller parts are arranged differently and everything has been wrapped inside a container. This design is mainly inspired from the OpenStep API, Delphi and the Swing API. My goal is to unify the best features of these development tools.

The Container

The Container is an entity that defines a complete GUI-control and the interface for manipulating it from within the program. Possible Containers could be: Pressables (i.e. Buttons, Checkboxes, Radiobuttons etc.), Listbox, Radiogroup, Textfield, TextGrid and Progressbar. An application developer who only uses default GUI-controls will only need to create and use containers. This simplifies the creation of GUIs from the programmer's point of view.

The Container contains a Cell, an Editor and a Model which are all described below.

Some Containers could be regarded as being almost the same from a programmers point of view. An example is PushButton, ToggleButton, Checkbox and Radiobutton which are just called Pressables above. They can all be clicked, they all have a text-label and perhaps an icon. They just look and behave differently. In this case you would just need one Container object with different Cells and/or Editors as described below. This simplifies the manipulation of the GUI even further.

It would be possible and relatively easy to wrap a container into using a standard interface like CORBA, JavaBeans, ActiveX etc. When using such a standard interface it is possible for a container to describe itself at runtime. This is required when building a GUI from a visual GUI-builder. If a standard interface is not used, then there should be some other way of describing the properties that can be manipulated in the container at runtime. The container could for instance provide a list of strings with a datatype and some functionpointers for each string in the list to describe all properties that can be modified.

The Cell

A Cell is owned by a container and is tied closely to the Editor. The Cell defines the look and some of the feel/behaviour of a GUI-Control. The only behaviour it defines is what is not related to editing a GUI-Control. It could define behaviour for highlighting GUI-Controls as the mouse travels across it, but it should not control how text is edited in a textfield. Examples of cells could be: ButtonCell, CheckboxCell, RadiobuttonCell, TextFieldCell, LabelCell, TextListCell and ProgressbarCell. The Cell is what corresponds to the View plus some of the Controller-functionality in the Model/View/Controller architecture.

When modifying the look&feel of a GUI you will need to replace the Cells and the Editors in the GUI. Users should be allowed to replace the standard Cells and Editors to allow them to switch between multiple look&feels. Availble look&feels could be BeOS, Motif, Windows, AmigaOS, MacOS, OpenStep and other possibly new look&feels.

To enable Cells to define such things as gridareas and listareas in a particular implementation, all Cells will need an associated index when requested for information or when requested to perform an operation. This may not always be nessesary, but it will sometimes allow for more flexible or more efficient use of Cells.

A special Multiplexer Cell could also be created, to allow multiplexing of multiple look&feels. Such a cell would have a list of delegate Cells that it represents. This could be used for creating an audio-only look& feel which could be multiplexed with an existing look&feel. This would add audio to the exsisting look&feel.

The Editor

The Editor is owned by the container like Cells and is closely tied to Cells. It defines the behaviour of a GUI-control related to editing. It could for instance define how text is edited in a textfield or how a button reacts when it is clicked - like whether it should toggle or be a momentary push. The Editor should use as much information as possible from the Cell and the Model.

As mentioned, Editors should be replacable to allow for pluggable look&feel. See the description of "The Cell" above for more information.

To enable Editors to define such things as gridareas and listareas in a particular implementation, all Editors will need an associated Index when requested for information or when requested to perform an operation. This may not always be nessesary, but it will sometimes allow for more flexible or more efficient use of Editors.

When implementing a textgrid the Cell should possibly only be able to draw a grid of textcells. When editing a textcell a standard TextFieldEditor could be used to do the editing. This will allow for efficient display of the grid and still reuse the code for text-editing.

The Model

As mentioned above this entity has the same purpose in the Container/Model/Cell/Editor architecture as in the Model/View/Controller architecture.

Pseudo implementation example

This is some pseudo C++/Java/Delphi code to illustrate how the Container/Model/Cell/Editor architecture might be implementated in an API:

AbsContainer
{
  PluggableModules
    Cell (AbsCell interface)
    Editor (AbsEditor interface)
    Model (AbsModel interface)
  Properties
    Left (integer/real)
    Top (integer/real)
    Width (integer/real)
    Height (integer/real)
    Misc aligment-properties...
    Focused
    Highlighted (boolean)
      SetHighlighted(highlighted)
      {
        Model.SetHighlighted(this,0,highlighted); //Model should notify GUI-cell
      }
      GetHighlighted()
      {
        return Model.GetHighlighted(this,0);
      }
  Events
    MouseUp //Pass on to the Cell
    MouseDown //Pass on to the Cell
    MouseMove //Pass on to the Cell
    KeyUp //Pass on to the Cell
    KeyDown //Pass on to the Cell
    (KeyPress //Pass on to the Cell)
    ChangeFocus //Pass on to the Editor???
}

AbsListContainer : AbsContainer
{
  Properties
    HiglightedIndex
    FocusedIndex
    Elements //Number of elements in list
}

Abs2DGridContainer : AbsContainer
{
  Properties
    HiglightedRow
    HiglightedColumn
    FocusedRow
    FocusedColumn
    Rows // Number of row in 2DGrid
    Columns // Number of columns in 2DGrid
}

PressableConainer : AbsContainer
{
  PluggableModules
    Cell (PressableCell interface)
    Editor (PressableEditor interface)
    Model (PressableModel interface)
  Properties
    Label (string)
      SetLabel(newLabel)
      {
        Model.SetLabel(this,0,newLabel); //Model should notify GUI-cell of the change
      }
      GetLabel()
      {
        return Model.GetLabel(this,0);
      }
    Icon (image)
      SetIcon(newIcon)
      {
        Model.SetIcon(this,0,newIcon); //Model should notify GUI-cell
      }
      GetIcon()
      {
        return Model.GetIcon(this,0);
      }
    Pressed (boolean)
      SetPressed(pressed)
      {
        Model.SetPressed(this,0,pressed); //Model should notify GUI-cell
      }
      GetPressed()
      {
        return Model.GetPressed(this,0);
      }
  Functions/Methods
    PerformClick()
    {
      Editor.PerformClick(this,0);//Potentially trigger a PressableClicked event
    }
  Events
    PressableClicked //Passed on to the Editor
}

//These are the functions that might create some standard GUI-Controls

CreateButton()
{
  Create an instance of PressableContainer with these PluggableModules:
    Cell = ButtonCell
    Editor = MomentaryPushEditor
    Model = PressableModel
}

CreateToggleButton()
{
  Create an instance of PressableContainer with these PluggableModules:
    Cell = ButtonCell
    Editor = TogglePushEditor
    Model = PressableModel
}

CreateCheckBox()
{
  Create an instance of PressableContainer with these PluggableModules:
    Cell = CheckboxCell
    Editor = TogglePushEditor
    Model = PressableModel
}

CreateRadioButton()
{
  Create an instance of PressableContainer with these PluggableModules:
    Cell = RadiobuttonCell
    Model = PressableModel
    Editor = ToggleRadioEditor
      // The implementation of ToggleRadioEditor might be tricky,
      // as it will need access to the other radio-buttons in a radio-group.
      // It will be easier to implement a radio-group as a "PressableGrid"...
}

//This could create a button that stores it's data in a database:

CreateDBButton()
{
  Create an instance of PressableContainer with these PluggableModules:
    Cell = ButtonCell
    Editor = MomentaryPushEditor
    Model = PressableDBModel
  // No new interfaces, no change in the button code, just a new model - simple.
}

Final remarks on the Container/Model/Cell/Editor architecture

Due to the performance overhead that it might give to separate the Cell from the Editor, it could be better to just merge these two together as a single Cell-Editor (View-Controller). This is the approach of the Swing API. I still believe that it should all be put into a Container entity to define one interface to multiple implementations of GUI-Controls. This is the way it is done in the OpenStep API, except that OpenStep doesn't separate Model/View/Controller inside the container.

If the functionality of the Editor should be separated from the Cell in the Container/Model/Cell/Editor architecture, the Editor could problably be implemented as a primary eventhandler of the Cell. All it requires is that the Cell is flexible enough to acomplish this. The Editor is after all just added functionality to the Cell. The Editor could problably also be implemented with virtual functions in an objectoriented language or as function-bindings in functional languages.

There is one last important thing to note: If it should be possible for the user to change the look&feel of an application by replacing the Cells and the Editors in the userinterface, the Cell and the Editor will have to be external to the application while the Container and the Model must be internal. The interface between internal code and external code could be created by using CORBA to define an API for external libraries. Other APIs could also be developed for accessing libraries.


Additional GUI architecture ideas

Here I present a few other ideas that I have for implementing a GUI.

Atomic visual GUI elements

A possible way of enhancing the consistency of a GUI and reusing more code is to build the GUI from atomic visual GUI elements. Some examples of atomic visual GUI-elements could be: TextFrame (the frame around a text-editing field), TextBackground (the background of a textfield), ButtonFrame (the outline of a button), ButtonFace (the surface of a button), Checkmark checked, Checkmark unchecked, Scrollarrows up/down/left/right.

Textcursors, mousepointers and focusframes

Some special GUI-elements like the textcursor for editing text, the mousepointer, focusframes for focusing GUI-controls etc. should be treated separately. They could also have pluggable look&feel. For instance a textcursor could be made flashing, non-flashing, as a blockcursor, as a horizontal line-cursor or something else. If they are referenced as separate GUI-objects some code could possibly be saved while also allowing to change the look&feel of those objects.

Saving ressources in a GUI

To save ressources in a GUI, it would possibly be good if all Cells and Editors implement a flag, which tells whether that particular Cell or Editor can be reused. It would be possible to reuse a Cell or an Editor if they do not depend on any internal data within itself, but only operates from the parameters it gets from function calls and from the data that it can obtain from the Model or the Container.


- ÁNOQ of the Sun


Modified: 1999-04-14
E-mail:anoq@HardcoreProcessing.com