Java AWT/SWT/Swing: How to plan a GUI?

I’m not a big fan of GUI builders: They typically autogenerate bucket-loads of code that then locks in your whole development team to using one IDE. Also, this code is often unreadable (check the code generated when using Matisse under Netbeans).

My recommendations for GUI design / debugging would be:

  • Add a main method to each panel (or “top-level” component) implementation, allowing other developers to easily determine what a component looks like.
  • Favour the use of Actions over ActionListeners and register these actions with each JComponent‘s ActionMap. This allows them to be “extracted” and added to other parts of the UI (e.g. JToolBar) whilst still having their state controlled by the “owning” JComponent (i.e. loose coupling).
  • Use assert to ensure that all UI component modifications are occurring on the Event Dispatch thread; e.g. assert SwingUtilities.isEventDispatchThread().
  • To debug strange layout behaviour consider painting a component’s background in red!
  • Centralise the capturing and reporting of workflow events and exceptions. For example, I typically implement a TaskManager class that is registered with my UI’s status bar. Any background processing (performed within SwingWorkers) is passed a handle to a Task created by the TaskManager. Interracting with the Task (by calling setDescription(String), setThrowable(Throwable), cancel()) causes the status bar to be updated. It also causes the glass pane to be displayed for “global” tasks … but this is all decoupled / hidden from the individual SwingWorkers.
  • Do not use the Observer / Observable classes, but instead favour ChangeListener, PropertyChangeListener or your own custom listener implementation for propagating events. Observer passes an Object as it’s event, forcing client code to check the type using instanceof and to perform downcasts, making code unreadable and making relationships between classes less clear.
  • Favour the use of JTable over JList, even in situations where your table only has one column. JList has some nasty features in its API including the fact that you need to provide a prototype value for it to calculate its size correctly.
  • Never use DefaultTableModel as it typically results in you storing your “model” data in two places: In your actual business objects and also within the 2D array that DefaultTableModel sits on. Instead, simply subclass AbstractTableModel – It’s very easy to do this and means your implementation can simply delegate through to the data structure (e.g. List) storing your data.

Leave a Comment