Hi,
I fixed the Swing painting a little more. This finally removes the
flickers that have been visible from time to time (to be more precise:
when the AWT triggers repainting, which is entirely different from when
Swing triggers repainting).
Effectively, this adds a check in the paint() method if we are already
double-buffering (when we are called from AWT then we're not, that's
what caused the flickering) and if not, activate it by calling
paintDoubleBuffered. This looks a bit weird since paintDoubleBuffered
calls back into paint(), but that should actually work because the
isPaintingDoubleBuffered flag decides which branch in the if-else in
paint we go. When unwinding the call stack after painting, we go back
into paintDoubleBuffered and actually draw the buffer to screen. Maybe
meditate a little over this to understand...
You might ask why not do it like it has been done previously. The
double-buffering was always activated directly in paint() when double
buffering was enabled on the JComponent (and it was by default only
enabled on the JRootPane). This was not quite right for the following
reasons:
- in Sun's JDK, _all_ Swing components are doublebuffered-enabled by
default
- what if we want to have arbitrary Swing components displayed in an AWT
tree? With the old approach this was only possible with JRootPanes
So this hack improves the compatibility between AWT and Swing and also
removes some ugly screen flickering in one patch :-)
2005-09-24 Roman Kennke [EMAIL PROTECTED]
* javax/swing/JComponent.java
(paint): Activate double buffering if it is not already
activated.
(paintImmediately2): Prepare a component graphics object here
and
call paintDoubleBuffered with this.
(paintDoubleBuffered): Changed to work nicely with the new
paint()
and paintImmediately2() methods.
/Roman
Index: javax/swing/JComponent.java
===
RCS file: /cvsroot/classpath/classpath/javax/swing/JComponent.java,v
retrieving revision 1.59
diff -u -r1.59 JComponent.java
--- javax/swing/JComponent.java 22 Sep 2005 20:58:34 - 1.59
+++ javax/swing/JComponent.java 24 Sep 2005 20:36:46 -
@@ -341,6 +341,12 @@
boolean autoscrolls = false;
/**
+ * Indicates whether the current paint call is already double buffered or
+ * not.
+ */
+ static boolean isPaintingDoubleBuffered = false;
+
+ /**
* Listeners for events other than [EMAIL PROTECTED] PropertyChangeEvent} are
* handled by this listener list. PropertyChangeEvents are handled in
* [EMAIL PROTECTED] #changeSupport}.
@@ -1449,9 +1455,24 @@
*/
public void paint(Graphics g)
{
-paintComponent(g);
-paintBorder(g);
-paintChildren(g);
+RepaintManager rm = RepaintManager.currentManager(this);
+// We do a little stunt act here to switch on double buffering if it's
+// not already on. If we are not already doublebuffered, then we jump
+// into the method paintDoubleBuffered, which turns on the double buffer
+// and then calls paint(g) again. In the second call we go into the else
+// branch of this if statement and actually paint things to the double
+// buffer. When this method completes, the call stack unwinds back to
+// paintDoubleBuffered, where the buffer contents is finally drawn to the
+// screen.
+if (!isPaintingDoubleBuffered isDoubleBuffered()
+ rm.isDoubleBufferingEnabled())
+ paintDoubleBuffered(g);
+else
+ {
+paintComponent(g);
+paintBorder(g);
+paintChildren(g);
+ }
}
/**
@@ -1604,10 +1625,13 @@
void paintImmediately2(Rectangle r)
{
RepaintManager rm = RepaintManager.currentManager(this);
+Graphics g = getGraphics();
+g.setClip(r.x, r.y, r.width, r.height);
if (rm.isDoubleBufferingEnabled() isDoubleBuffered())
- paintDoubleBuffered(r);
+ paintDoubleBuffered(g);
else
- paintSimple(r);
+ paintSimple(g);
+g.dispose();
}
/**
@@ -1615,38 +1639,40 @@
*
* @param r the area to be repainted
*/
- void paintDoubleBuffered(Rectangle r)
+ void paintDoubleBuffered(Graphics g)
{
+
+Rectangle r = g.getClipBounds();
+if (r == null)
+ r = new Rectangle(0, 0, getWidth(), getHeight());
RepaintManager rm = RepaintManager.currentManager(this);
// Paint on the offscreen buffer.
-Image buffer = rm.getOffscreenBuffer(this, getWidth(), getHeight());
-Graphics g = buffer.getGraphics();
-Graphics g2 = getComponentGraphics(g);
-g2.setClip(r.x, r.y, r.width, r.height);
-paint(g2);
-g2.dispose();
-g.dispose();
+synchronized (paintLock)
+ {
+Image buffer = rm.getOffscreenBuffer(this, getWidth(), getHeight());
+Graphics g2 = buffer.getGraphics();
+g2 = getComponentGraphics(g2);
+g2.setClip(r.x, r.y, r.width, r.height);
+isPaintingDoubleBuffered = true;
+