Performance Secrets in
Swing 1.1.1
By Steve Wilson
Performance
of Swing-based applications has always been a concern for the
Swing team, and each release continues to add performance enhancements.
During the transition from Swing 1.0.x to Swing 1.1, the team
did a tremendous amount of tuning, which mostly revolved around
creating fewer temporary objects during normal operations. The
Swing team has now started to turn its attention to reducing the
amount of unnecessary painting which occurs. Swing 1.1.1 introduces
some new options in the way that Swing handles scrolling and internal
frames. This article introduces you to those changes so you can
take full advantage of them in your applications.
Scrolling Changes
Under normal circumstances, when a JScrollPane is scrolled, the
entire visible contents of the scroll pane are redrawn. This is
fine for content that renders quickly, but in some cases it is just
too slow. In Swing, much of the work of scrolling is actually handled
by JViewport, which is a child of the JScrollPane. JScrollPane is
mostly responsible for managing the layout of the viewport and scroll
bars.
The Backing Store
Swing has always provided an option to help with this task. The
option is called a backing store. You can activate the backing
store by calling the method
setBackingStoreEnabled(boolean enabled)
on JViewport. This technique draws the visible contents of the
viewport to an offscreen bitmap and then "blits" part of this image
for small scrolls.
This is a very effective technique for small scrolls on complex
contents. It is so effective for many JTable tasks that it is automatically
activated when a JTable is placed inside a JScrollPane. However,
the feature has three major limitations:
First, it isn't as fast as it could be because, for many "normal"
operations, two image blits are required instead of one. That's
because the contents of the viewport need to be drawn to the backing
store, and then copied to Swing's global double buffer. Without
the backing store, we can draw directly to the double buffer, avoiding
a large amount of bit copying.
Second, because of the way JVieport is currently implemented, the
backing store doesn't work when scrollRectToVisible()
is called directly by the programmer, or during autoscrolling. This
limitation could be fixed with major changes to the internals of
JViewport, but the possiblity of causing instabilities outweighs
the benefit.
Lastly, it requires considerable extra RAM to maintain this backing
store image.
Window Blitting
Given the contraints of the backing store, we've developed another
technique that seems to provide better overall performance for most
typical applications. This technique is called window blitting.
Window blitting is typically used in native windowing systems, such
as Win32, MacOS, and X11 to directly move bits from the screen buffer
to their new location when scrolling, and to update only the newly
exposed region. The java.awt.Graphics class provides a method
named copyArea()
which is designed to provide this type of functionality. And code
has now been added to the JViewport class which can use this technique
to improve scrolling performance.
Because this feature is so new, we're currently only exposing it
as an option. However, if we don't find major problems, we're likely
to make this the default option in a future release. To access this
option, you should add the following line of code after you create
your JScrollPane:
scrollpane.getViewport().putClientProperty
("EnableWindowBlit", Boolean.TRUE);
This should improve scrolling performance in most common applications.
However, there are a couple things you might want to be aware of.
The most important thing to know is that the current implemenation
of Graphics.copyArea makes it difficult for this scheme to
work when the JScrollPane is partially obscured by another heavyweight
window (such as the Windows NT TaskManager). We currently have code
that indirectly detects that case and reverts to a slower algorithm.
However, we believe that in typical case when the user is scrolling,
the JScrollPane will be in the frontmost Window..
JDesktopPane Improvements
JInternalFrames inside a JDesktopPane have been a sore spot for
Swing performance, especially when there are many JInternalFrames,
or when they contain complex content such as JTables. To help solve
this problem, we've added some code to the DefaultDesktopManager
to allow you choose from two options to improve performance.
Outline Dragging
The first option is called outline dragging. This option
provides the user with a "ghost frame" when JInternalFrames, are
dragged, instead of displaying the full content of the frame being
dragged in real time. This alternative offers maximum performance;
users typically get a very fast response. To activate this
option, you can add the following line of code after you create
your JDesktopPane:
desktop.putClientProperty
("JDesktopPane.dragMode", "outline");
Another Dragging Option
Outline dragging has been available in previous versions of Swing,
and is popular with some users. But many users prefer to be able
to see the full content of the frame as they drag. Under the current
implemenation of DefaultDesktopManager, the dragging implementation
is fairly inefficient, but Swing 1.1.1 has added still another option
that can also be used to speed up dragging operations. This new
option uses technology similar to the JScrollPane "window blitting"
strategy. To activate it, just add the following line of code after
you create your JDesktopPane:
desktop.putClientProperty
("JDesktopPane.dragMode", "faster");
An Example: The Metalworks Demo
For a more complete example of how to use these option, take a
look at the Metalworks demo that ships with Swing 1.1.1. It provides
a menu which allows you to switch back-and-forth between these two
options. The "faster" drag mode approach suffers the same drawbacks
as the JScrollPane blitting option (it doesn't perform well when
it isn't the front Window), but we believe it is superior for normal
operations. This option will likely become the default option in
a future Swing release after it has gotten more testing.
A Note About ClientProperties
Since early versions of Swing, the JComponent "client properties"
mechanism has been used in places where more traditional API additions
might be used. The options referred to in this article are examples
of that. The main reason this is done is to avoid locking down a
specific API which might not be appropriate for all circumstances,
or because the criteria for a given release does not include "API
changes". As these "client property" style features are fleshed
out we will likely replace them with more traditional "beans-style"
properties in future releases.
Compatibility
The features described in this article will soon be available in
the "unbundled" Swing for JDK 1.1 release, and the full JDK release.
The following releases will include these features.
- Swing 1.1.1 (for JDK 1.1.x).
- JavaTM 2 Java Runtime Environment,
Standard Edition, version 1.2.2 (aka JDK 1.2.2).
Conclusion
We hope these improvements will be beneficial to most applications
which people are developing with Swing. As mentioned above, some
of these options could become the default options in a future Swing
release, so we're looking forward to hearing any feedback you have
(positive or negative) on these options.
Special Thanks
The Swing team thanks former team member Arnaud Weber for submitting
the original code on which the JViewport changes are based.
|