Customize SwingWorker to improve Swing GUIs

Discover techniques and best practices for robust user interface development

1 2 Page 2
Page 2 of 2

The intelligent-queue approach's main weakness is its implementation complexity. The thread limitation policy may require thread-pool usage, which is a complex concurrent construct to novice developers. The timestamp-based policy implementation needs to carefully consider the exception-handling strategies for cases when the SwingWorker task with the latest timestamp fails to complete, potentially locking up the UI indefinitely. Some kind of operation feedback to indicate the discarding of a SwingWorker event is also missing in this approach.

Is it possible to find an approach that meets the design criteria while keeping the UI code easy to maintain and develop? Let's find out in the next section.

Customized SwingWorker

The SwingWorker class in its original form suffers from lack of control on the number of threads. Instead of using conditional logic, a more elegant way to allow exactly one performing SwingWorker thread is to utilize the concept of GlassPane. Think of the GlassPane as an inactive and transparent layer between the mouse cursor and the user interface. Under special circumstances, the application can activate the GlassPane layer to intercept and consume mouse events. The application should also disable keyboard interactions when the GlassPane is active. One way to achieve that is to have the GlassPane implement the AWTEventListener interface and let it consume keyboard events. This technique alleviates the problems in the original SwingWorker class in two ways. First, the GlassPane allows at most one active SwingWorker thread by absorbing any subsequent user-initiated actions. Second, UI components do not visually respond to user actions, unlike the conditional-logic approach. As long as the GlassPane is active, any user action will not affect the UI components' appearance or state.

Implementing the GlassPane technique requires some additional background information. Each Swing component belongs to a component hierarchy that represents parent-child relationships. For example, a JButton's parent is the JPanel that contains that button. Likewise, the JPanel's parent may be a JFrame that contains that JPanel. The RootPaneContainer type resides at the top of this hierarchy either as a JFrame, JDialog, JApplet, JWindow, or JInternalFrame. To activate the GlassPane on a frame or a dialog, the developer needs to traverse through the component hierarchy and call the setGlassPane(Component) method on the instance that implements the RootPaneContainer interface. This method automatically sets the parameter component to cover the user interface and intercept events when the component is set to be visible.

Recall also that the original SwingWorker class is essentially an intermediary helper class that hides the multithreading complexities from UI developers. Nothing stops the SwingWorker from including the GlassPane technique as part of its responsibilities. The SwingWorker class can use the Gang of Four Template Method design pattern to predefine a sequence of execution that includes the GlassPane activation and the invocation of the methods implemented by anonymous subclasses. As seen in Figure 4's sequence diagram, the customized SwingWorker also renames the construct() and finish() methods to doNonUILogic() and doUIUpdateLogic() methods, respectively. This modification dissuades developers from mistakenly letting UI-related code execute on a separate thread.

Figure 4. A customized SwingWorker class's sequence diagram

Finally, the GlassPane-SwingWorker combination adds the finishing touch by changing the mouse cursor to the hourglass shape during the time-consuming task's execution. This form of operation feedback effectively indicates the application is in processing mode.

When running the demo application under the custom SwingWorker mode, it is apparent the user interface properly satisfies all three requirements defined earlier: the SwingWorker's multithreading capability ensures screen liveliness at all times; the GlassPane technique and the mouse cursor changes preserve presentation integrity and give users proper visual feedback; and furthermore, the customized SwingWorker class shields the complexities from UI developers by encapsulating its implementation details.

Room for improvement

Now that the three fundamental design criteria have been met, the SwingWorker customization's basic foundation is set in place. However, a different project's user interface design requirements may necessitate further modification of the SwingWorker component. Here are some possible considerations:

  • In applications that use modal dialogs, the user should not be able to close the dialog when the SwingWorker is operating in the background. Even when the GlassPane is active, it does not intercept mouse events on the dialog title bar. Therefore, the dialog default close operation should be set to do nothing when the SwingWorker is still running.
  • There can be some instances where users are allowed to interact with the UI components while the time-consuming task executes. For example, an intermediate message box may pop up to prompt for a user selection. In such cases, the GlassPane does not interfere with the user's mouse interaction because it masks the parent dialog, not the intermediate dialog. However, the GlassPane will absorb keyboard presses, disabling actions such as the mnemonic key or the tab key. To get around that, it may be desirable to improve the logic in the AWTEventListener so that certain key presses are allowed to pass through the GlassPane. For the sake of keeping GlassPane generic, each intermediate dialog should implement an interface that informs the GlassPane of the allowable keys.
  • In cases where a section of event-handling logic requires calling more than one SwingWorker thread, the application may need to serialize the thread initiation sequence. If developers are comfortable with multithreading programming, concurrent constructs such as latches and futures can be useful. Otherwise, it might be easier to avoid designing such requirements into the application.

Other scenarios than the three mentioned above may exist, but in general, developers should find it easy to add their own custom behavior into the SwingWorker class.

Swing away

Swing developers face increasingly demanding UI requirements, and this article presents some reusable components to ease their development efforts. This article lists three important UI design goals as the motivation for customizing the SwingWorker component, and also analyzes two alternative solutions that are less suitable. UI developers can certainly apply the proven techniques described here and take their next Swing-based project to a higher level.

While earning a master's of engineering at Cornell University, Yexin Chen cofounded a startup that offered portal services for college students. He is currently an IBM Global Services IT consultant, designing and developing enterprise applications. Some of his certifications include UML, XML, Sun Certified Java Developer, and jCert Enterprise Developer. Yexin thanks Brent Cooley, Tom Polk, Donna Cognon, and Thomas Callahan for numerous Swing design discussions while working together on a project in Albany, N.Y.

Learn more about this topic

This story, "Customize SwingWorker to improve Swing GUIs" was originally published by JavaWorld.

Copyright © 2003 IDG Communications, Inc.

1 2 Page 2
Page 2 of 2