Java AWT/SWT/Swing: How to plan a GUI?
I've already realized some applications with a small graphical user interface. Nothing complex, but I've encountered several problems that components aren't displayed or just not behaving as expected.
Now my question:
How do you plan those user interfaces? What do you do when you need to make changes? How do you debug strange behaviours?!
This applies for nearly every type of gui-design. Sure, with Microsofts Visual Studio you have a big advantage because you nearly get what you see in the designer.
Does a good and open-source (or freeware) designer for AWT exist? Already looked around and didn't find anything really intelligent.
EDIT: Until now, I've also created all of my GUIs by hand. Sure it is cleaner code but sometimes it's very hard to find the layouting bugs. If Visual Studio by MS is able to create approximately clean code, why aren't the others?
I've heard about some Eclipse Visual designer. Is that one already production-ready?
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
Action
s overActionListener
s and register these actions with eachJComponent
'sActionMap
. 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 withinSwingWorker
s) is passed a handle to aTask
created by theTaskManager
. Interracting with the Task (by callingsetDescription(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 favourChangeListener
,PropertyChangeListener
or your own custom listener implementation for propagating events.Observer
passes anObject
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
overJList
, 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 thatDefaultTableModel
sits on. Instead, simply subclassAbstractTableModel
- 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.
I'm one of those archaic dudes who do GUI layout by hand. I'm also not afraid of the infamous GridBagLayout
!
I keep things simple for myself by emulating the coding standard used by Visual Age, years ago: I use a lot of JPanels to organize parts of the GUI, and each one gets its own makeXXX()
method to create it, lay it out and return it to a a parent panel or the constructor. That way, each makeXXX
only has to concentrate on a small part of the whole works.
Some components need to be accessible by various instance methods; I declare those as instance fields. The other stuff, that's just decoration or layout, need not be exposed outside the makeXXX
methods.
That's mostly it. Works for me.
Do it by hand. GUI builders aren't good unless you have the 'partial class' concept in C#, and even then they often cause more problems than they solve. Use the GUI builder tools to make a prototype - sure, but not for production code.
Also, another little trick I've used over the years to good effect when trying to debug layout or "which panel am I really seeing here" problems is to give each 'container' panel a really garish background color (yellow, blue, etc). Something obvious enough that you'll see it even if it's only one pixel wide.
And my favorite layout for simple dialogs is BoxLayout. It's not great, you have to write a lot of boilerplate, but at least it generally works the way you would expect it to in your head. Don't overthink layouts until you have to.
NetBeans might the best option for building GUI in WYSIWYG manner but many java developers write their GUI by hands, as it is not that difficult. Care about the thickness of your borders and gaps between your controls and you're ok :)