The Source for Java Technology Collaboration
User: Password:



Tom Ball

Tom Ball's Blog

Optimize a Swing App by Slowing It Down

Posted by tball on April 11, 2005 at 04:54 PM | Comments (4)

Swing is slow, right? That seems to be a common perception which fast Swing apps like LimeWire seem unable to shake. Even the Jackpot GUI app is sluggish these days, and we all know it cannot be that my code is at fault, right?

I think the real problem is that yours and my computers are too fast, or at least too fast relative to our customers' systems. Because software developers and quality testers tend to have very fast systems so they can multi-task effectively, an unfortunate side-effect is that they tend to run their applications faster than their customers do. As a result, it's easy to overlook inefficient and redundant GUI operations as long as the result looks and feels okay on a fast system. Slow your system down enough, however, and these problems leap out at you, demanding attention.

One easy way to slow down a Swing application is to turn on DebugGraphics functionality. Although DebugGraphics was designed to display potential problems with display painting and layout, it has a nice side-effect of pausing after each paint operation (otherwise you wouldn't be able to see it work). Here is an example of how one might use this:

    private static final boolean debugGraphics = true;
    ...
    if (debugGraphics) {
        DebugGraphics.setFlashTime(100);                 // 100 ms. pause
        DebugGraphics.setFlashCount(1);                  // only pause once per paint
        DebugGraphics.setFlashColor(new Color(0,0,0,0)); // no color

        // turn off double-buffering, or this gets optimized away!
        RepaintManager.currentManager(myComponent).setDoubleBufferingEnabled(false);
        myComponent.setDebugGraphicsOptions(DebugGraphics.FLASH_OPTION);
    }

The first time you run this code, do so in the debugger. If it appears to hang, suspend the app and see where it is stuck. When I first ran it on my app, I had turned DebugGraphics on for my whole component tree -- DebugGraphics was pausing after each bump was drawn on my JSplitPane slider! Not very useful...

Once I only turned debugging on for my main panes, it became painfully obvious that some operations of my apps GUI operations were redundant. My app has a JTable which is supposed to select a JTree node when a row is clicked, but selection was happening multiple times. Setting a breakpoint on my ListSelectionListener showed I needed to first check ListSelectionEvent.getValueIsAdjusting() and only handle the event if its false; failing to do so was causing a new list selection event to be fired for each entry in the tree path for that node (maybe Swing wasn't the problem after all!). These multiple selection events were not that noticeable on my fast system, but after fixing this and other similar problems, the GUI is much perkier.

I am going to leave this code enabled in my app for a few more days. The slow display will irritate me a lot, and so I'll just have to make it faster some other way. Wish me luck!

Bookmark blog post: del.icio.us del.icio.us Digg Digg DZone DZone Furl Furl Reddit Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment

  • DebugGraphics is useless for most purposes
    The thing is; just about all widgets I create use a Graphics2D. For things like anti-aliasing and various other stuff. This immidiately means I can't use DebugGraphics anymore since it extends Graphics, not Graphics2D.
    Another great flaw in the design of Swing..

    Posted by: zander on April 12, 2005 at 01:18 AM

  • Years ago when I was responsible for a 4GL client with its own widget set, I found disabling double buffering a great help in pin pointing problem areas. The fact that double buffering was implemented in order to cover up bugs, didn't help on the quality front. Together with a bit of help from a common or garden profiler, it ended up ten times as quick. Somewhat faster than the C++ version.

    In Swing "-Dawt.nativeDoubleBuffering=true" on the command line disables double buffering.

    Posted by: tackline on April 12, 2005 at 05:54 PM

  • Hum... is there a way to enable debug graphics on all componets with a single switch? It would be easier to apply, when you have several panels and still haven't deployed the application (meaning, the user are still not complaining about the slowness of a particular panel in the UI) ;-)

    Posted by: aaime on April 14, 2005 at 01:57 AM

  • A component's debugGraphics property is inherited from its parent unless explicitly set (a common Swing pattern), so you can start by setting it on your top-level frames. As I mentioned, you'll want to first run this in the debugger in case it appears to hang; interrupting operation to see what is taking so long will show you which (if any) components to exclude.

    Posted by: tball on April 15, 2005 at 03:08 PM





Powered by
Movable Type 3.01D
 Feed java.net RSS Feeds