Customize
SwingWorker to improve Swing GUIs
Tutorial Details:
Customize SwingWorker to improve Swing GUIs
Customize SwingWorker to improve Swing GUIs
By: By Yexin Chen
Discover techniques and best practices for robust user interface development
ince its inception in JDK 1.2, the maturing Swing toolkit has become an attractive alternative to thin-client presentation technologies such as JavaServer Pages (JSP), JavaScript, and HTML. Swing offers the benefits of portability, code reusability, and ease of maintenance, especially when the solution requires a rich user interface (UI) that is deployable in a controlled environment. For instance, Swing developers need not worry about browser compatibility issues; they can instead devote more time to improving component functionality and application usability.
Despite these favorable attributes, the Swing toolkit has weaknesses. Swing suffers from the inherent limitation of a larger resource footprint and dependencies on the Java runtime environment, thereby complicating its deployment process. The more important issue is that developers should be aware of the UI design goals and Swing's inner mechanics during a project's early phases. Doing so avoids costly redesigns in later development stages. It is good practice to keep in mind the following design criteria when putting together the application user interface:
Screen liveliness: The user interface should maximize its responsiveness to user interaction, especially when the application executes other processing-intensive tasks.
Presentation integrity: The user interaction with the application should always obtain consistent and predictable presentation results, unless nondeterminism is part of the application logic.
Operation feedback: The user interface should accurately inform users of the current application status through visual feedback. Some examples of basic feedback mechanisms are the progress meter and the mouse cursor change.
A great deal of effort may be necessary to factor out the complexities required to achieve these design requirements. This article eases that effort by illustrating best practices through a demo application.
Note: You can download this article's demo from Resources .
Basic Swing concepts review
Let's review the Swing event-dispatch concept, which is the foundation for other topics discussed later. First, when the user interacts with Swing components, whether it is clicking on a button or resizing a window, the Swing toolkit generates event objects that contain relevant event information, such as event source and event ID. The event objects are then placed onto a single event queue ordered by their entry time. While that happens, a separate thread, called the event-dispatch thread, regularly checks the event queue's state. As long as the event queue is not empty, the event-dispatch thread takes event objects from the queue one by one and sends them to the interested parties. Finally, the interested parties react to the event notification by processing logic such as event handling or component painting. Figure 1 illustrates how this works.
Figure 1. Swing event-dispatch model
Since the event-dispatch thread executes all event-processing logic sequentially, it avoids undesirable situations such as painting a component whose model state is partially updated. This is great news for Swing developers because they can assume that only one thread, the event-dispatch thread, will process the event-handling code. If two event-dispatch threads worked on the event queue, Swing developers would need to write additional code for thread safety. Similarly, executing user interface-related code in any thread other than the event-dispatch thread can lead to unexpected behaviors. If it is absolutely necessary to execute UI-related code from a separate thread, the developer should use the following code as a workaround:
Listing 1. An example of executing code on the event-dispatch thread
Runnable aRunnable = new Runnable()
{
public void run()
{
// UI related code
}
};
SwingUtilities.invokeLater(aRunnable);
The invokeLater() method creates a special event that wraps around the runnable object and places it on the event queue. When the event-dispatch thread processes that special event, it invokes the runnable object's run method in the same thread context, thus preserving thread safety.
Shortcomings of a single-threaded user interface
While it is possible to write a Swing application without any multithreading code, the resulting user interface often fails to meet the design criteria of screen liveliness. Here is an example to illustrate this point: Consider a simple user interface that includes a table and a text area. As the table's row selection changes through mouse clicks or arrow-key presses, the text area appends a new message to the existing text. Figure 2 shows the demo application screenshot.
Figure 2. Demo application screenshot
Under this normal mode of operation, the user interface is very responsive. The text area updates without any delay as the user makes new table selections. However, the screen liveliness quickly deteriorates if each row selection invokes a time-consuming task before updating the text area. The demo application implements the time-consuming task by simply making the current thread sleep for a random duration:
Listing 2. The code to simulate a time-consuming task
//Generate a random number of seconds between one to four seconds
int sleepTime = (new Random().nextInt(4) + 1) * 1000;
Thread.currentThread().sleep(sleepTime);
This artificial delay demonstrates the negative effect of executing a time-consuming task, which can be a complex SQL statement execution in a more realistic situation. Remember the thread that becomes dormant is the event-dispatch thread, which is also responsible for dispatching painting events. Therefore, when the user makes a new table selection, the user interface ceases to properly repaint itself during the delay. The application will display bizarre effects when the user resizes the window during the delay, as seen in Figure 3 below. During this problematic delay, the user can also queue up additional events by clicking on the unresponsive screen, potentially causing further unintended consequences. Feel free to verify these problems by running the demo application in delay mode.
Figure 3. Effect of time-consuming task clogging the event-dispatch thread
SwingWorker to the rescue
Multithreading code easily resolves the problem described above. If the time-consuming task executes on a separate thread, then the event-dispatch thread can dispatch events freely. In the context of our demo application, the event-handling logic should execute the delay in a new thread for each new table selection event. Any UI-related logic in that thread, such as updating the text area, should still call the SwingUtilities.invokeLater() method, as described in the earlier section:
Listing 3. Execute time-consuming task on a separate thread
Runnable timeConsumingRunnable = new Runnable()
{
public void run()
{
// Execute time-consuming task
...
// Execute UI updates on event-dispatch thread
SwingUtilities.invokeLater(
new Runnable()
{
public void run()
{
// Update UI
}
};);
}
};
new Thread(timeConsumingRunnable).start();
Although this is a viable approach, we need to take a step further by introducing a class named SwingWorker , which is downloadable from the Swing Connection . SwingWorker attempts to take the multithreading complexities out of UI-related classes. It provides two methods that developers can override, the construct() and the finished() methods. The SwingWorker class creates a new thread to run the code within the construct() method. The finished() method's code runs on the event-dispatch thread after the construct() method completes. In the event-handling logic, the developer can provide the implementation for these methods in an anonymous class that inherits from the SwingWorker class. Comparing Listing 3 and Listing 4 tells us that the SwingWorker solution is better because it keeps the UI class pure by not cluttering it with lower-level multithreading code such as Runnable and Thread . The demo application's SwingWorker mode shows that the user interface meets the screen liveliness design criteria even while the application executes time-consuming tasks:
Listing 4. Execute time-consuming task using SwingWorker
SwingWorker aWorker = new SwingWorker()
{
public Object construct()
{
// Execute time-consuming task
...
return null;
}
public void finished()
{
// Update UI
}
};
aWorker.start();
SwingWorker weaknesses
Designing applications for screen liveliness using SwingWorker unfortunately leads to undesirable behaviors that break other UI design goals. A meticulous user would have noticed a flaw in the demo application running under the SwingWorker mode. For example, when a user quickly taps the keyboard arrow buttons to select different table rows, there is a chance that the last message displayed in the console won't match the last row selected in the table. The reason is that each delay on the row selection is set to have a random duration. The task in the first row selected can have a longer delay than those of subsequent rows selected, causing the text area to display messages in a randomized sequence out of sync with the selection order.
Such nondeterministic presentation behavior violates the design goal of presentation integrity. Imagine the user's reaction if the application often displays results that don't match the latest request! This is likely to happen in most situations because it's hard to guarantee that all time-consuming tasks have the same execution time. In a database-driven application, SQL statements have different execution times. In a distributed application that sends data across different computers, the network latency can also add significant variance to the execution time. The random duration of task execution isn't a
Read
Tutorial at: Click here to view the tutorial
Rate Tutorial: Customize
SwingWorker to improve Swing GUIs
View Tutorial: Customize
SwingWorker to improve Swing GUIs
Related
Tutorials:
Enhance your Java application with Java Native Interface (JNI)
Enhance your Java application with Java Native Interface (JNI) |
Java Tip 90: Accelerate your GUIs -
JavaWorld
Java Tip 90: Accelerate your GUIs -
JavaWorld |
Become a programming Picasso with JHotDraw -
JavaWorld
February 2001
Become a programming Picasso with JHotDraw -
JavaWorld
February 2001 |
Performance books put to the test - JavaWorld March 2001
Performance books put to the test - JavaWorld March 2001 |
Embed Java code into your
native apps -
JavaWorld May 2001
Embed Java code into your
native apps -
JavaWorld May 2001 |
Create a scrollable virtual desktop
in Swing
Create a scrollable virtual desktop
in Swing |
Eclipse casts shadows
Eclipse casts shadows |
Customize
SwingWorker to improve Swing GUIs
Customize
SwingWorker to improve Swing GUIs |
Create client-side user interfaces in HTML, Part
2
Create client-side user interfaces in HTML, Part
2 |
Bug patrol
Bug patrol |
To my
mind, of few interest
To my
mind, of few interest |
Worth
reading
Worth
reading |
Interesting
...
Interesting
... |
SpeedJG - XML Builder
SpeedJG - XML based Java Swing GUI Builder |
Wi.Ser (WidgetServer) unified rich client framework
Wi.Ser is a Java/XML server-side GUI-framework which enables an application to run as either a monolithic Swing application, a thin-client/server Swing application, or as a Web application without any change!
|
Java Tech: Acquire Images with TWAIN and SANE, Part 1
Scanners, digital cameras, and other image-acquisition devices are part of the computing landscape. Despite their ubiquity, however, Java does not provide a standard API for interacting with these devices. And yet there certainly is a desire to have a sta |
What's New in Swing?
A new skinnable look and feel (Synth), printing support for |JTable| components, the ability to add components directly to a frame, these are a few of the new features in Swing for J2SE 5.0. |
Open Source Web Frameworks in Java
Open Source Web Frameworks in Java
Open Source Web Frameworks in Java
Struts
Struts Frame work is the implementation of Model-View-Controller (MVC) design pattern for the JSP. Struts is maintained as a part of Apache Jakarta project and is open |
Sanssouci is a Java framework for autogenerating fancy Swing-GUIs via introspection.
Sanssouci is a Java framework for autogenerating fancy Swing-GUIs via introspection which display objects directly to the user |
UltraLightClient Community Site
Community-driven Wiki site for UltraLightClient Code Snippets and Contributions
If you want to contribute, please go to Register as Committer. There is no support for the content on this site by Canoo. Committers agree that the code can be used free of c |
|
|
|