The main aim of this project was to provide a single intuitive interface for controlling the size and position of a fixed number of items within a container, without the need to build a multi-layered hierarchy of layout managers. In essence the GoLayout layout manager seeks to fulfil broadly similar requirements to the java.awt.GridBagLayout class but with a much simpler interface.
When attempting to solve the problem of correctly positioning items in a layout there are generally two differing schools of thought.
- Use lots of simple layout managers which can be embedded within one another
- Use a single complex layout manager
In this discussion about the pros and cons of these approaches I am deliberately ignoring the time taken for the layout manager(s) in question to position their items. This is not an unreasonable thing to do as layout operations themselves are rare compared to, say, the processing of incoming mouse events.
Divide and Conquer?
Whilst using lots of simple layout managers can sound very appealing, it carries with it some performance issues and architectural limitations. In order to implement complex layout regimes using only simple layout managers you have to introduce additional layers to the object hierarchy. By increasing the depth of the object hierarchy like this you introduce overheads to many common processing tasks. These include such things as:
- Processing incoming mouse events
- Rendering the object hierarchy
The extra layers of the hierarchy don't just add to the time taken to complete such tasks, they also increase the number of temporary object instances created during them. This includes things like instances of java.awt.Point or java.awt.Dimension created during the processing of mouse events or java.awt.Graphics instances created during the repaint cycle.
The other issue with the use of simple layout managers is that it introduces an artificial grouping of items in an interface which may not be reflective of the functionality which that interface seeks to present to the user. Some examples of these limitations are:
- An inability to define positional constraints between objects in different sub-hierarchies
- Constrained or non-intuitive focus traversal
Whilst these limitations can be overcome by the introduction of extra code outside the layout mechanism, it is often at the expense of simplicity and elegance.
One Layout Manager to Rule Them All?
By using a single complex layout manager the object hierarchy can be simplified, resulting in reduced overheads and more control over the relationships between objects. However to achieve this you either have to use an existing, general purpose layout manager or write one yourself.
Whilst writing your own layout manager will always give you the chance to control things exactly as you want, it can often result in an inflexible solution which do not cope well with changes to the number of objects being positioned or their positional constraints. So why not just use an existing general purpose layout manager?
The trouble with a general purpose layout manager is the fact that it is general purpose. The cost of being able to do almost anything with a layout manager is the requirement to have tell it what you actually want it to do.
Gridbags and Gladrags
The java.awt.GridBagLayout class is a good example of this. It is one of the most complex and least user friendly classes in the entire Sun JDK. It is insufficiently documented and suffers from some very fragile behaviour. Furthermore there are still relatively simple types of layout that it is incapable of achieving. I know this because I once had to implement a clean room version of it.
What limits the GridBagLayout class is that it is fundamentally still based on the idea of an underlying layout grid. This architectural issue means that if you want to position multiple rows, each with different numbers of items, which are not naturally aligned to some underlying grid, you run into trouble. More often than not you end up having to augment the use of GridBagLayout with additional embedded layout managers to achieve anything beyond grid based semantics.
The other issue with GridBagLayout is the amount of code which the definition of a complex layout requires. Any changes to an existing layout, such as the addition of a new component in the middle of the layout, can result in dozens of different lines of code needing to be modified. This makes it more difficult for people who are not experienced with it to get an intuitive idea of how it works.
Make Graphs Not Grids
The GoLayout class (net.goui.awt.GoLayout) was designed to tackle the limitations inherent to GridBagLayout while being easy to understand and intuitive to use. The main improvements it offers over GridBagLayout are:
- The use of a flexible graph-based layout mechanism.
- A simple and intuitive syntax.
Rather than using an underlying grid in which components are laid out, GoLayout uses a far more flexible graph based system in which to place components. This allows different rows to be laid out completely independently of each other if desired. Whilst GoLayout can provide grid based positioning, it is not fundamentally bound by this restriction and is far more flexible than any of the standard AWT layout manager classes.
An instance of GoLayout is constructed primarily on the basis of a format string. The formatting information is provided in the form of a simple layout syntax which attempts to provide a good visual clue as to the final appearance of the layout itself (essentially a form of ASCII art).
A example of a simple format string would be:
String layout = "[ < > ]" + "< [ ] < > [ ] >" + "[ < > ]";
which results in a layout with the same basic behaviour as the java.awt.BorderLayout class. As can be see from this example, and even without understanding the format syntax itself, the appearance of the format string provides an intuitive idea of the final layout itself. The fact that whitespace is not significant in the format string means that it can be formatted to match the actual layout being defined. For a full explanation of the layout syntax used in the format string, please see the class documentation.