Skip to main content

RepaintManager's side effect

Posted by alexfromsun on April 13, 2008 at 7:49 AM PDT

When I worked on the lightweight disabling of compound Swing components for my JXLayer project, I tried different approaches to workaround the problems with the custom painting of double-buffered components.

The last try was using the JComponent.print() method instead of JComponent.paint(), which effectively disables the double-buffering for the whole hierarchy of components. While it seems to be a good solution, it has a flaw: print methods may be overridden to provide a specific painting logic when a component is printed rather than painting on the screen.

(Thanks to David Browne and Kirill Grouchnikov for this information)

Finally I found a correct way of disabling swing containers without recursive disabling of double buffering for the subcomponents or using print() method. I'll describe it in my next blogs

(Some great news are coming)

Anyway, you may be surprised why I spent my time on that tricks when there is a much cleaner solution for disabling double buffering in Swing. I am talking about RepaintManager.setDoubleBufferingEnabled(boolean) method. At the beginning of painting you can switch the double buffering off and switch it on again at the end. Despite the fact that it changes the global setting for the whole Swing, no one will get hurt because Swing is a single-threaded library. It makes sense, doesn't it?

I must admit that I don't use RepaintManager in my java.net projects because I am aware of one side effect it causes.

Do you remember the famous GrayRect fix for JDK 6?

The main feature of this fix is the true per-window double buffer implementation, which eliminates unnecessary painting when a window of your java application is brought to the front after it was overlapped by another window. With JDK 5 you often see a gray rectangle when the damaged area is repainted, with JDK 6 the buffered image of the window's content is immediately copied to the screen so can't notice any traces of that.

RepaintManager.currentManager(null).setDoubleBufferingEnabled(false) disables the all Swing double buffering. Unfortunately, it is a one-way street for the gray rect fix, calling setDoubleBufferingEnabled(true) after that, enables Swing double buffering, but the gray rect fix is to be disabled forever.

The system RepaintManager is created by a private constructor with a special flag which enables the true double buffering.
Once you set your own implementation of RepaintManager, the gray rect fix is gone, because there is no public API to enable true double buffering for RepaintManager subclasses.

So there is the same problem when you install a custom implementation of the RepaintManager.

This demo demonstrates the effect (JDK 6 is required):

Each time the JFrame.paint() is called, the new line is added to the JTextArea. When the demo window is shown, the frame is painted once.
Check out the gray rect fix by moving another window on top of the demo's frame, you'll see that JFrame.paint() is not get called, because Swing uses the per-window buffer instead. This can also be checked without another application, just move the demo's frame partly outside the window back and forth, it will not trigger frame's repainting as well.

With the Options menu you can set a new RepaintManager or switch the double buffering off and on again, any of these action will disable the gray rect fix. Choose one of the actions and move the other window on top of the demo again, you'll see that the frame starts to repaint itself and the true double buffering is gone.

The source code for this demo is available.

That's all for today,

take care and see you soon


alexp

Related Topics >>

Comments

Ah, I was hoping latest versions of JRE (I have 1.6.0_13 right now) would have fixed that, but apparently not. I recall this article from when I collected information on disabling double buffering and just found it back (thanks to my RSS reader...). I still use the RepaintManager, by lack of good alternative (unless I missed it, I haven't seen the promised following article...). So disabling buffering to print or export the graphics is the way I went (restoring it after if it was set -- are they platforms where it is not set by default?), even at the cost of loosing this gray area fix. Maybe I should have used the print() method... I don't know if it uses by default the paint methods (the JavaDoc is elusive about that). I suppose so. I should experiment.

Hello Maxim

I am not aware of a bug filed on this issue
so it's a good idea to file one

No it's become clear why there is a caution in the javadoc for setDoubleBufferingEnabled():
* Enables or disables double buffering in this RepaintManager. * CAUTION: The default value for this property is set for optimal * paint performance on the given platform and it is not recommended * that programs modify this property directly.
Thanks
alexp

Hi Alex, Is there any bug record opened for this problem? Regards, Maxim