By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
440,665 Members | 1,952 Online
Bytes IT Community
Submit an Article
Got Smarts?
Share your bits of IT knowledge by writing an article on Bytes.

Doing Swing right

10K+
P: 13,264
I have put together this article to give people starting Swing an awareness of issues that need to be considered when creating a Swing application. Most of the Swing tutorials that I have seen just help people display some nice widgets quickly without explaining some issues that need to be tackled when a full application needs to be developed. This article does not go into full implementation details because those can be found by reading the relevant documentations and therefore there is no need to regurgitate them here. The reader is encouraged to look up any new terms encountered.

Swing programmers are faced with the same problems no matter the difference in the domain applications for their software. Thankfully these problems are so common that the giants on whose shoulders we stand have already thought out some generic ideas and solutions to them.


Do not disrespect the EDT

There are generally two types of toolkits, namely multi threaded toolkits and single threaded toolkits. It is currently believed that multi threaded graphical toolkits are either too difficult to implement or if implemented, less natural for programmers to use correctly without creating threading related bugs.

In single threaded GUI toolkits, all GUI activity is run on one thread, the Event Dispatch Thread. Any updates to the interface (including repaints) and reactions to those updates (event-handling) are run as discrete events queued on this E.D.T. This model is both simple to implement and easier for programmers to use correctly than the multi threaded model.

Swing uses a single threaded model. This is the first important thing to know about swing. There are many bugs in swing programs that are attributable to forgetting (or not knowing) this. There are generally two ways of disrespecting the E.D.T:

a) Running long tasks on the E.D.T.

As I mentioned above event-handling code is run on the EDT. Since the EDT runs its tasks one after the other (single threaded), any task running on it will block any other tasks (which run on the EDT) from doing anything. This means that when the event-handling code is running, no input can be accepted from the user and the interface freezes. Event-handling code thus needs to be very short, perhaps not longer than half a second. If the listener code needs to be longer then it needs to be kicked off in its own thread. Such threads are usually known as worker threads or background thread.

Considerations

• Sometimes you may actually want to stop users from doing anything until a certain task is completed. The correct way of doing this is to call a disableInput method somewhere, kick off the task in its own thread and display a progress bar.
• Some insight is required in deciding whether tasks are long or not because some tasks may appear short during testing but may become very long in production when real data is factored in. e.g. some database operations’ time is dependent on the size of the database.
• If the listener code is running in its own thread but needs to update the interface then we have a small problem because all interface updates need to be done on the EDT. A solution is simply to queue such updates on the EDT using either SwingUtilities.invokeLater or SwingUtilities.invokeAndWait as required which simply queues tasks in a Runnable’s run method onto the EDT.
• Another consideration with worker threads is allowing users to have control on how the background tasks are run. Typically it may be required that users be able to pause, cancel, restart or stop the background process. This requires special care because the task control should be made available on the EDT while the task being controlled is being run in a separate (worker) thread.
SwingWorker

It turns out though that it is possible to have a generic solution for the problems of updating the GUI from worker threads and giving users the ability to control the background tasks. The solution is the javax.swing.SwingWorker class. As of Java SE 6, this class is available as part of the JDK under the javax.swing package. Prior to that, programmers had to write their own SwingWorker class. Documentation for both these surprisingly quite different classes is readily available.
The SwingWorker class provides a means of returning intermediate results from the background task and also provides a method to use for updating the interface with those intermediate results. It also solves some possible memory inconsistency errors that may occur caused by the EDT thread and the worker thread accessing the same object.

b) Updating the GUI from other threads besides the EDT.


This has already been mentioned above. There is need for care when writing any code that updates the GUI to make sure that it is always run from the EDT because most of the swing methods are not thread safe. If you are not sure if certain code will run on the EDT, then you can use the SwingUtilities.isEventDispatchThread method before performing the GUI related tasks. If the call returns false then you need to use SwingUtilities.invokeLater to queue the GUI tasks on the EDT.

A small but useful exception to this rule is the setText method defined in javax.swing.text.JComponet which is specified as thread safe. A common error is to create the GUI elements from the initial thread i.e. from the main method. The code that runs in the main method is run by a special thread whose only special property for the purposes of this discussion is that it is not the same as the EDT. All the GUI initializing code should instead be bundled in a method which is called from the run method of a thread queued on the EDT. SwingUtilities’ invokeAndWait is the common method of doing this as explained in Sun’s Java tutorial.
Expand|Select|Wrap|Line Numbers
  1. SwingUtilities.invokeLater(new Runnable()) {
  2.             public void run() {
  3.  
  4.                 createAndShowGUI();
  5.             }
  6.     }
You will find that the main method usually has little else to do besides those lines of code above.

Never mix AWT and Swing.


Do not mix those two the same way you never put lemon in coffee with milk. AWT components are not implemented in Java but use native peer components. This means that the AWT components will look different on different platforms. Their reliance on the platform however, also means that they are faster than Swing albeit only fractionally and increasingly becoming less noticeable. By contrast, Swing components are written in Java (hence the J before the component names) and can be made to look the same on all platforms.
The small speed difference and different looks are not the main reasons you should never mix them. The z-ordering schemes of the two are different and so there are many painting problems that occur when their components are mixed. Basically things will not display where you expected them to display and some components will hide behind others for no immediately apparent reason. There is no need to use AWT components when using Swing anyway because Swing is a component wise superset of AWT.


Design with i18n and L10N in mind


Swing programs contain a lot of locale sensitive objects. Those objects need to be made localizable by separating them from the source code. Things like new JButton(“OK”) should not be used because the label “OK” can be required to be changed into another language (or another English word). Icons too may mean different things in different environments. Basically any text that is visible to the user must not be hard coded in code so as to be made changeable, perhaps even by the users themselves, without the need for the programmer or for a redeploy of the application. There are several classes in the Java SE which assist in internationalization and localization of programs.

• Messages must always come from ResourceBundles. The ResourceBundles themselves need to be carefully designed so as not to duplicate entries unnecessarily.
• Avoid concatenating Strings intended for user display. Some languages are read from right to left while others are read left to right. You can easily see why concatenation presents a problem.
• Message processing operations must always be done using Collaters. If there are lots of comparisons to be made then CollationKeys should be used to improve performance.
• Formatting of displayable objects must always be done in a locale sensitive manner.
Design with Accessibility in mind

Accessibility should not be considered only with reference to people with disabilities. Physically disabled or not, people are just different. They have different color and font preferences and some prefer different input devices to others. To make matters worse, input interfaces to computers are increasingly becoming more and more exotic as computers are now being integrated into all sorts of gadgets. Writing a software program that satisfies all these different people and environments might sound like a daunting task. Two general principles will make your software very accessible.

• When writing support for a particular input device, try to make the support as complete as possible. E.g. Keyboard support should be so comprehensive that all the system functionality can be realized by using the keyboard only.
• Spend more time writing code for user configurable components rather than writing code to configure components.
Standard Java ships with a small accessibility API that you can use to make your software more accessible. The API generally allows you to program to some unknown input and output devices without assuming a particular implementation of those interfaces. That means your code will work on any exotic input devices that implement those interfaces.
Sun’s tutorial lists some rules for supporting accessibility. .

Data binding

You will typically need to make use of persistent data in your swing application. You may need to use data from files or (more commonly) databases. Database access can be done easily using the JDBC API. There is need for a clear separation between data access code and interface construction code. In particular, SQL statements should never be found in any classes that use swing components.
This separation of concerns is usually best achieved through implementing some pattern, or more realistically, combination of patterns. Some patterns make it possible to switch between different data source types e.g. different RDBMs like the DAO . Your DAO will typically be observable by your Swing components (observers) so that they can respond appropriately when the model changes. This scenario lends itself naturally to the popular Model View Controller architecture. Notice that Swing does not use pure MVC though it is strongly aligned with it and can be considered MVC for most practical purposes. Most Swing components have models where you can enforce pure MVC easily by setting data to those component models rather than to the components themselves, or better yet, implementing (or more commonly extending) those models yourself. All that is required is that you satisfy the contracts of those models' interfaces. This has the advantage of allowing different representations for the same model to be correctly updated when their (common) underlying model is changed.

Event handling

Favor the use of Actions and the AbstractAction class over having actionListeners all over the place. The advantage of using actions is that they allow a neat separation of functionality and state. Using actions also make it easy to enable/disable functionality without duplicating code for components which use that same action. Action classes are also visible to long term persistence mechanisms and so allow easier integration of persistence into your program. The slight drawback is that since the actions use the command pattern, you need a class for each action.

Construct the interface components in an intelligent way

Some things just require a bit of the thought process. Have a set of utility classes with methods that do common tasks for you. Sun used the same trick with the SwingUtilities class. Make good acquaintance with that class so that you don't have to keep reinventing the wheel. Avoid writing code to decorate each component, rather have decorators that decorate certain types of components.
Construct components only when absolutely necessary and be reluctant to completely destroy large components when a similar component may need to be displayed.

Nielsen’s heuristics

GUI development still has an artistic side that should not be overlooked. Regrettably, most programmers are not well gifted in artistic qualities. We are mostly fact driven geeks who don’t appreciate the difference between the Mona Lisa and our grandmother’s portrait hanging on the wall (no disrespect meant to our grandmothers of course, God bless their souls). If you were like me and spent most of your high school time fiddling around with bits when others were visiting art galleries, then you may not have that extra artistic edge required in GUI designing. I find Nielsen's heuristics particularly helpful as design guidelines. They are not hard and fast rules and indeed can be considered to be contradictory in some respects but they help avoid some elementary design blunders.

Conclusion

Some of the advice in this article may not be viable due to the nature of the application being created and you may wish to use an approach contrary to what has been suggested. The important thing is that at least you understand those suggestions and justify the need for an alternative approach. There are so many options available to Swing programmers, too many in my opinion because some of them just promote dirty solutions. I hope the article makes sense and is in some way useful to you.
Nov 12 '08 #1
Share this Article
Share on Google+
6 Comments


Nepomuk
Expert 2.5K+
P: 3,112
Wow, great article! You make some very interesting and useful points. I'll have to read it again when I have a bit more time, to be able to fully appreciate it. :-)

Greetings,
Nepomuk
Nov 12 '08 #2

Expert Mod 100+
P: 2,327
Great thorough article r0. I added it to featured reads.
Nov 12 '08 #3

Markus
Expert 5K+
P: 6,050
No word of a lie, when I saw this on Popular Articles, I thought 'Dancing? On Bytes..?'.

*embarrased*
Nov 15 '08 #4

10K+
P: 13,264
No word of a lie, when I saw this on Popular Articles, I thought 'Dancing? On Bytes..?'.

*embarrased*
If you are going to get those types of swing tips then it won't be a good idea to get them from me.
Nov 17 '08 #5

N002213F
P: 39
great article r0, thanks
Nov 24 '08 #6

P: 4
Thanks for this article, it is well thought out and unlike many "this is how you should do it" articles, you provide good reasons for why you should do it this way, which makes it much more helpful.

I'm a client side web developer and don't use swing (unless I absolutely have to) but many of your points also loosely apply to javascript app development, such as: not running long tasks on event listeners, separating data from the view code, i18n...
Jul 16 '09 #7