2007-10-26

Swing Tip: Heavy Paint Job...

Have you ever needed to make some heavy 2D rendering operation in Swing and you didn't want to block the Swing Thread? Well, I had to, several times and today I made a hack for a colleague that I would like to built upon here.

My first attempt to ensure that the Swing Thread wasn't blocked was to conduct all rendering on a background thread. This obviously violated all Swing and Java2D principles. If you don't know, just Google for it, but the fact is that all rendering should be done by the Event Dispatch Thread. So, all Swing activities should also be done in that same thread. What happens if the scene you are rendering is rather complex and you don't want to hog the Even Dispatch Thread?

A simple technique can be applied. The idea is to hold the context when the rendering is started. If the rendering has been going for quite some time, place an event in the Event Queue to resume it later. This allows the Event Dispatch Thread to process other events. When the rendering is resumed we can check if the context has changed. If it has we probably have to start the painting process all over. If it hasn't we can resume were we left of.

Here is a sample code for this. The rendering is completely stupid, but the idea is to emphasize that you can put any rendering code in it.

Of course that we will have to ask yourself what is better invokeLater, or invokeAndWait. Maybe even two utility methods.

The other way is to use the new SwingWorker class. It is available since Java 5 I believe, but you can find it for Java 1.4 on the web.The SwingWorker class accepts tasks that have a part that is executed outside the EDT and a part that runs on the EDT. You can even have interim results being pushed to the UI. It is a powerful API, if you use it right because the SwingWorker can use an ExecutorService of Java, from the concurrency utilities. This way you get a single Thread Pool for background tasks.