?
Solved

How does this double buffering code work....

Posted on 1999-07-05
3
Medium Priority
?
478 Views
Last Modified: 2006-11-17
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;
      }
   }
 
   
 
 
 
 
 
 
0
Comment
Question by:miredo
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 3
3 Comments
 
LVL 16

Expert Comment

by:heyhey_
ID: 1245310
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
 
LVL 16

Accepted Solution

by:
heyhey_ earned 400 total points
ID: 1245311
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
 
LVL 16

Expert Comment

by:heyhey_
ID: 1245312
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

Featured Post

[Webinar] Lessons on Recovering from Petya

Skyport is working hard to help customers recover from recent attacks, like the Petya worm. This work has brought to light some important lessons. New malware attacks like this can take down your entire environment. Learn from others mistakes on how to prevent Petya like worms.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

By the end of 1980s, object oriented programming using languages like C++, Simula69 and ObjectPascal gained momentum. It looked like programmers finally found the perfect language. C++ successfully combined the object oriented principles of Simula w…
Introduction This article is the second of three articles that explain why and how the Experts Exchange QA Team does test automation for our web site. This article covers the basic installation and configuration of the test automation tools used by…
This theoretical tutorial explains exceptions, reasons for exceptions, different categories of exception and exception hierarchy.
Viewers will learn how to properly install Eclipse with the necessary JDK, and will take a look at an introductory Java program. Download Eclipse installation zip file: Extract files from zip file: Download and install JDK 8: Open Eclipse and …
Suggested Courses

718 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question