How does this double buffering code work....

I've been posting questions pertaining to this silly little applet for awhile now - finally it looks the way I want, but I have no idea why this double buffering code works.  I cut-and-pasted it from the Sun Microsystems site.

Questions:
1) I have a component (a CirGge) contained in an applet (a GgeApl) and both have a paint() method.  The container's paint method utilizes double buffering, the component's paint method draws the component.  I suppose both of these get called, but I don't see how the component somehow gets drawn in the offscreen buffer.  How does the container's paint() access the info in the components paint().  I hope my question is clear.

2) What's the reason for calling super.invalidate()?
(why call it on the parent?)

3) Is there a reason to not declare Graphics bufferGraphics (in applet's paint() method) at the beginning of the applet.   As it is the applet has to recreate that Graphics object over and over.



**************************************************
// GgeApl.java
// This applet displays a lightweight component gauge that is fed
// values by a random number generator.  The component is a black
// square with a white circle inside it.  The circle shrinks and
// swells in response to the values the generator feeds it.

/*
   <applet
   code="GgeApl" width=200 height=200>
      </applet>
*/
 

  import java.util.*;
  import java.text.*;
  import java.awt.*;
  import java.awt.event.*;
  import java.applet.*;
 
  // the applet
  public class GgeApl extends Applet
                      implements Runnable
  {  
     // Will be the width of the applet and lightweight
     // component (square shape).
     int siz = 200;
     
     // Width of applet.
     int aplWid;
     
     // Give applet a gauge.
     CirGge gge;
     
     // Give applet a value generator to pass values to the gauge.
     ValGen gen;
     
     // The value.
     int newVal;
     
     // Image buffer for double buffering.
     Image buffer;
     
     public void invalidate()
     {
        super.invalidate();
        buffer = null;
     }
     
     public void update(Graphics g)
     {
        paint(g);
     }
     
     public void paint (Graphics g)
     {
        if (buffer == null)
        {
           buffer = createImage(getSize().width, getSize().height);
        }
        Graphics bufferGraphics = buffer.getGraphics();
        bufferGraphics.setClip(0,0,getSize().width, getSize().height);
        super.paint(bufferGraphics);
        g.drawImage(buffer,0,0,null);
        bufferGraphics.dispose();
     }
     
                                                                 
     public void init()
     {
        aplWid = siz;
        resize(aplWid,aplWid);
        setLayout(new BorderLayout());
        gge = new CirGge(siz);
        add("Center", gge);
        gen = new ValGen();
     }
     
     public void start()
     {
       
       
        // Start a new thread for number generator to
        // send values to gauge.
        new Thread(this).start();
     }
     
     public void stop()
     {
     // suspend the thread here  
     }
     public void run()
     {
        while (true)
        {
           // Generate a new value.
           newVal = gen.genVal();
       
           // Change the size of the circle to
           // the new value.
           gge.chgPplSiz(newVal);
           try
           {  
              // Wait a second.
              Thread.sleep(1000);                    
           }
           catch (InterruptedException e)
           {
           }
        }    
       
     }      
  }
 
  // the lightweight component gauge
  class CirGge extends Component
  {
     // length of side of black backround box
     private int boxWid;
     
     // diameter of white circle
     private int pplSiz;    
     
     CirGge(int siz)
     {
        // Set size of black background box.
        boxWid = siz;
       
        // Set initial size of circle.
        pplSiz = 95;
     }
     public void paint(Graphics g)
     {
        // Draws the black background
        g.setColor(Color.black);
        g.drawRect(0,0,boxWid,boxWid);
        g.fillRect(0,0,boxWid,boxWid);
       
        // Draws the white circle
        g.setColor(Color.white);
        g.drawArc((boxWid - pplSiz)/2,(boxWid - pplSiz)/2,pplSiz,pplSiz,0,360);
        g.fillArc((boxWid - pplSiz)/2,(boxWid - pplSiz)/2,pplSiz,pplSiz,0,360);    
     }
     public void update (Graphics g)
     {
        // Don't erase, just paint.
        paint(g);
     }
     
     // Change the size of the circle.
     synchronized void chgPplSiz(int newPplSiz)
     {
        pplSiz = newPplSiz;
        repaint();
     }
  }
 
   // number generator
   class ValGen
   {
      Random numGen;
      int nxtVal;
     
      ValGen()
      {
         numGen = new Random();
      }
     
      // Generate a value between 90 and 99.
      synchronized int genVal()
      {
         nxtVal = numGen.nextInt();
         nxtVal = Math.abs((nxtVal % 10) + 90);
         return nxtVal;
      }
   }
 
   
 
 
 
 
 
 
miredoAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

heyhey_Commented:
I will post some 'try it yourself and you'll see why' notes :)
1. container paint() method will call the paint() method os all of its childs.
there is even special paintComponents(Graphics g) method
(put some System.out.println()'s in the paint() and update() methods and you'll see when each method is called :)
(btw. - you see the super.paint(bufferGraphics); ? :)
remove this line and test the code :)
CirGge is lightweight component (CirGge extends Component), so it does not have its own Graphics object. it transparently uses the same bufferGraphics object);

2. invalidate() is pretty important method. it is called whe the Component has changed (resized). you definitely has to call super.invalidate(), bucause it DOES all the dirty job.
and the author has overriden this method so that he can clear the buffer object when the component has been resized.
(remove super.invalidate() and test the code :)

3.
if (buffer == null)
{
buffer = createImage(getSize().width, getSize().height);
}
Graphics bufferGraphics = buffer.getGraphics();

as you can see the buffer object is recreated each time when it REALLY has to. but every Image object has its own Graphics objects - so you don't recreate the Graphics object each time.

of course you can use member variable if you want :)
0
heyhey_Commented:
it was quite a long post, so I'll lock the question.

btw. there is a very nice article about paint()-ing at the Javasoft Swing Connection (concerning both AWT and Swing)
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
heyhey_Commented:
here is another - slightly different d-b code

Image offscreen;
Dimension offscreensize;
Graphics offgraphics;

public synchronized void update(Graphics g) {
Dimension d = getSize();
if ((offscreen == null) || (d.width != offscreensize.width) || (d.height != offscreensize.height)) {
    offscreen = createImage(d.width, d.height);
    offscreensize = d;
    offgraphics = offscreen.getGraphics();
    offgraphics.setFont(getFont());
}

0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Java

From novice to tech pro — start learning today.