Building User Interfaces with Swing
By Mark J. Balbes, Ph.D., OCI Software Engineer
One of the powerful advantages of Java programming is the ability to easily create robust modern graphical user interfaces (GUI).
Sun's first attempt at a GUI toolkit was the Abstract Windowing Toolkit. Although a powerful concept, the AWT had significant drawbacks in terms of functionality and stability.
Recognizing these shortcomings, Sun has superseded the AWT with the Java Foundation Classes' Swing package. Swing offers a 100% pure Java toolkit for building most any kind of graphical interface.
In this article we shall learn about the different components supplied by the Swing package and discuss when to use Swing and when to use the AWT.
AWT vs. Swing
The AWT had behind it a very simple philosophy: A Java application should look like it is a native application on whatever platform it is run on. Thus, on a UNIX system, the application will look like it is a UNIX (Motif) application. Likewise, on a Macintosh, that same application will have the look and feel of any other Macintosh application.
This was accomplished through the use of peer components.
Each AWT component was actually a front end to a native peer component. Thus, an AWT button on a Windows system would display an actual Windows button.
The problem with this approach was that the capabilities of each AWT component were limited to the intersection of capabilities of all the supported operating systems. And there was no guarantee that any implementation of Java on a new platform would be able to support all the capabilities of the AWT.
Swing solves this problem by using a 100% pure Java implementation.
All components are created in Java and do not rely on services from the underlying operating systems. For example, when you display a Swing JButton (the equivalent of a Button in AWT), the button is drawn by the Java Virtual Machine and generates Java 1.1 events.
The beauty of this design is that the capabilities of the components are not restricted by the underlying operating systems. It also means that new components can be created that have no equivalent peer.
The notion that the components must have the look and feel of the underlying operating system has also been abandoned in favor of a pluggable look and feel.
Swing components can change the way they are displayed – and even the way they behave – based on the look and feel set by the programmer.
Swing ships with the default Java look and feel, as well as the Motif look and feel. In addition, a Windows and a Macintosh look and feel are available for their respective operating systems.
Note that the limitation of these latter look-and-feels is only due to licensing restrictions and not through any inherent restriction in the Swing architecture. If Microsoft or Apple ever acknowledges that its look-and-feels can be used on other platforms, Sun will open up the current restrictions.
Out-of-the-Box Swing Components
The components supplied in Swing can be broken down into two categories: those that replicate the functionality of the AWT and more advanced components that provide new features.
The basic components include a selection of:
- Containers (JFrame, JPanel, JApplet, and JDialog)
- Buttons and labels
- Combo boxes
One of the new components that would have been very difficult – if not impossible – to create using AWT is the JSplitPane, which places two components in a single container with the relative size of the components controlled by a separator which can be dragged to the desired position.
Two of the more powerful advanced components are a spreadsheet-like table and a collapsible multi-level tree for displaying hierarchically organized data.
Swing also provides powerful document manipulation and display capabilities, an undo facility, and an accessibility API.
For a comprehensive description of all the Swing components and capabilities, see the references listed at the end of this article.
Building Custom Components
Because of Swing's lightweight architecture, it is relatively simple to create custom components that exhibit functionality not available from the Swing components.
The easiest way to make a custom component is to aggregate existing Swing components into a container to make a new type of component. For example, a simple clock component could easily be built by placing a JLabel that displays the current time next to a JComboBox that allows the user to select the time zone.
Of course, this could also be built with the AWT.
However, you could use Swing to build a more sophisticated clock.
Say you want to build a clock capable of switching between a digital and an analog display, depending on the user's preference setting.
If we were to build these clocks using AWT, we would probably build two different components: one for the digital clock and one for the analog clock. However, with Swing we can build one component featuring two different user interfaces but sharing all the common functionality.
This is possible because Swing components are designed using the Model-View-Controller (MVC) design pattern. In MVC, the design of each component is separated into a model that describes the underlying functionality of the component, the view that displays the information in the model, and the controller used to change the model.
In Swing, the view and controller are bundled together into a UI delegate.
Although the digital display could have been created using a peer component in AWT, the analog display has no peer. It must be created as a custom component.
In Swing, the clock component is separated into a model to describe the functionality of the clock (e.g., provides a method to get the current time and sends out update events every second) and a UI delegate (display the current time).
In fact, two different UI delegates can be built: a digital delegate and an analog delegate. A toggle of the look and feel could then let the user switch between the two types of displays.
Although we could also use an MVC design for this AWT component, there is no built-in look-and-feel support to easily switch between clock styles.
Now that we understand how Swing uses MVC, we can understand how the pluggable look-and-feel works.
Each Swing component has (at least) one model associated with it, but there is a different UI delegate for every look and feel. Thus, the underlying functionality of the component as represented by the model stays the same, but the way the user interface portion looks and behaves can be quite different.
It is also possible to create a custom look and feel by either subclassing the UI delegates of an existing look and feel or, if you are ambitious, writing a completely new set of UI delegates.
For the clock example above, we could create a "Victorian" look and feel which would display our clock with an analog interface and a "Modern" look and feel that would display our clock with a digital interface.
When to use Swing
Choosing whether or not to use Swing for a project is not always an easy decision. There are many different criteria that must be taken into account.
Probably the biggest concern is that Swing is not currently installed on any major browser. This means that a Swing applet that is distributed over the Internet incurs a large download time simply to get Swing (about 2 MB in size) loaded onto the client system.
In a controlled environment, such as an intranet, this problem can be solved by using Sun's Java 2 Plug-In (currently available only for Windows and Solaris) or pre-installing the swing.jar file into every client's classpath. For an application that is installed on every client machine, it is not usually a hardship to include Swing in the distribution.
Once the major browsers support Swing, the need for using AWT for Internet applets will be severely reduced or eliminated.
Another concern is the performance of Swing.
In its current incarnation, Swing is noticeably slower than AWT on slower computers. This issue reinforces the notion that Swing is not yet ready for Internet applet deployment. In a controlled environment like a corporate intranet, performance may not be as much of an issue.
When making a decision based upon the above issues, it should be noted that Swing is getting faster and more prevalent every day.
For application or intranet applet development, Swing offers many advantages that outweigh its current drawbacks.
If you are starting a Java Internet applet project now, you must consider what the state of the art will be at deployment time. If you are looking to deploy in the next couple of months, you can bet that things won't have changed too much. However, if you won't be deploying for 6 months to a year, you may want to gamble that Swing will be available in at least one major browser and that its performance will be greatly improved.
Not using Swing, although definitely a less-risky solution, will mean creating an applet with fewer features and less room for enhancement.
Swing has many technical issues that new developers need to be aware of.
First, it is important when fine-tuning an application for performance and memory usage to know that current implementations of Swing are generally bad at releasing references to unused objects. Memory analysis tools such as the Heap Analysis Tool, JProbe, and JInsight can be useful in tracking down such anomalies.
It is also important to note that it is dangerous to use Swing and AWT components together. Because of implementation limitations, heavyweight AWT components are always drawn on top of lightweight Swing components. Mixing both types of component may have unexpected results in the display of your GUI.
The most important limitation to be aware of is the way Swing is designed to work in a multithreaded environment.
The Swing architects decided that creating a fast, robust, full-featured GUI toolkit would be compromised if they also tried to guarantee that every component was thread-safe. Therefore, it is important to do almost all work with Swing components using the event dispatch thread. Since only this thread is manipulating the components, synchronization and thread safety are assured.
For most of the basic components, multithreading is not an issue. However, for more complex components like the JTable and JTree, it is extremely important that modifications to the component and its underlying model are performed in the event dispatch thread.
Although it is important to modify Swing components in the event dispatch thread, it is equally important not to tie up this thread with activities that can be done in other threads.
Creating a Runnable for one of the above methods that gathers data, performs a calculation, and then updates the Swing component is often more work than is desirable for the dispatch thread.
The developers of Swing have created a convenient solution.
SwingWorker is a class that makes multithreaded programming easy in Swing. Unfortunately, this class is not part of the Swing release and must be downloaded separately from the Swing Connection.
In order to use SwingWorker, you subclass it and override the
finished() methods. The
construct() method is executed in a new thread. This is where all the code that doesn't affect the GUI, like gathering data from other objects and performing calculations, is put.
construct() has finished it returns an Object. SwingWorker then executes the
finished() method in the event dispatch thread.
finished() method, any updates of the Swing component (its model or UI delegate) are performed. If necessary, a call to
get() will return the object constructed by the
The Future of Swing
The next release of Java (code-named Kestrel) will feature an improved version of Swing which adds functionality to existing components, provides a new set of keyboard bindings, fixes many bugs, and improves performance (mainly by reducing the amount of painting).
JDK 1.3 is already available for download as a beta release.