Spring Semester 2003


Lab Notes Twelve: Double-buffering
We start from this code:

import java.applet.*; 
import java.awt.*; 
import java.awt.event.*; 

public class Example extends /*NoFlicker*/Applet {
    
    Circle[] circles; 
    public void init() { 
	
	
	circles = new Circle[100]; 
	
	for (int i = 0; i < circles.length; i++) {
	    circles[i] = 
		new Circle(
			   
			   (int) (Math.random() * (280 - 20) + 20), // x
			   (int) (Math.random() * (280 - 20) + 20), // y
			   (int) (Math.random() * ( 20 - 10) + 10), // radius
			   
			   new Color( (float)Math.random(),
				      (float)Math.random(),
				      (float)Math.random()
				      ) 
			       
			       ); 
	    
	} // end of for 
	
	Broker peterPan = new Broker(this); 
	
	addMouseListener(peterPan); 
	addMouseMotionListener(peterPan); 
	
    } // end of init
    
    public void paint(Graphics g) { 
	for (int i = 0; i < circles.length; i++) {
	    // System.out.println(circles[i]); 
	    circles[i].draw(g); 
	}
    }
    
}

class Broker implements MouseMotionListener, 
			MouseListener {
    
    Example customer; 
    Circle[] a; 
    Circle c;
    
    Broker(Example someone) {
	this.customer = someone;
	this.a = this.customer.circles;
	this.c = null; 
    }
    
    public void mouseDragged(MouseEvent e) { 
	int x = e.getX(), y = e.getY(); 
	if (c != null) {
	    c.move(x, y); 
	    customer.repaint(); 
	}
    } 
    public void mouseMoved(MouseEvent e) { } 
    
    public void mouseClicked(MouseEvent e) { } 
    public void mousePressed(MouseEvent e) { 
	
	int x = e.getX(), y = e.getY(); 
	System.out.println("Mouse pressed at (" + 
			   x + ", " + y +")"); 
	for (int i = a.length - 1; i >= 0; i--) {
	    if (a[i].contains(x, y)) {
		c = a[i];
		break; 
	    }      
	} 
	
	System.out.println("Currently on... " + c); 
	
    } 
    public void mouseReleased(MouseEvent e) { c = null; } 
    public void mouseEntered(MouseEvent e) { } 
    public void mouseExited(MouseEvent e) { } 
}

class Circle {
    int x; int y; // center, not top-left corner
    int radius; 
    Color c; 
    
    public void move(int x, int y) {
	this.x = x; this.y = y; 
    }
    
    Circle(int x, int y, int r, Color c) {
	this.x = x; 
	this.y = y; 
	this.radius = r; 
	this.c = c; 
    }
    
    public boolean contains(int x, int y) {
	
	double dX = this.x - x, 
	    dY = this.y - y; 
	
	if (Math.sqrt(dX * dX + dY * dY) <= this.radius) 
	    return true;
	else 
	    return false; 
	
    }
    
    public String toString() { 
	return "Circle at (" + this.x + ", " + this.y + ") " + 
	    " size " + this.radius + ", color " + this.c; 
    }
    
    public void draw(Graphics b) {
	
	b.setColor(this.c); 
	b.fillOval(this.x - this.radius, 
		   this.y - this.radius, 
		   2 * this.radius, 
		   2 * this.radius); 
	b.setColor(Color.black); 
	b.drawOval(this.x - this.radius, 
		   this.y - this.radius, 
		   2 * this.radius, 
		   2 * this.radius); 
	
    }
    
}
<html<
  <head<
    <title<Circles</title<
  </head<
  <body bgcolor=white<
    <applet code="Example.class" width=300 height=300<
    </applet<
  </body<
</html<
Question: Why the flicker?

The answer is: because of update(). (We inherit this method, and it is called by repaint()). Every time it's called it clears the screen and then calls paint(). To obtain flicker-free screen updates (which is essentially what we are trying to do here, as in any animation) we will need to override update() such that it creates the new image somewhere in the background (that is, in memory) and then updates the screen in one fell swoop. It is easy to implement this as an application of inheritance. Here's the new definition of update().

Here's how we remove the flicker:

import java.awt.*;
import java.applet.*;

class NoFlickerApplet extends Applet {
    
    private Image     offScreenImage;
    private Graphics  offScreenGraphics;
    private Dimension offScreenSize;
    
    public final void update(Graphics theGraphicsContext){
	
	Dimension dim = this.size();
	
	if( (offScreenImage == null) || 
	    (dim.width != offScreenSize.width) || 
	    (dim.height != offScreenSize.height)) {
	    
	    this.offScreenImage = this.createImage(dim.width, dim.height);
	    this.offScreenSize = dim;
	    this.offScreenGraphics = this.offScreenImage.getGraphics(); 
	}
	
	this.offScreenGraphics.clearRect(0, 
					 0, 
					 this.offScreenSize.width, 
					 this.offScreenSize.height); 
	
	this.paint(offScreenGraphics);
	
	theGraphicsContext.drawImage(this.offScreenImage,
				     0,
				     0,
				     null);
	
    }
}
Now your program needs to extend this class instead of Applet directly.

Here's some code I'd like you to look at:

/*static*/ void sort(int[] a) {
    boolean done; 
    do { 
        done = true;
        for (int i = 0; i < a.length - 1; i++) {
            if (a[i] > a[i + 1]) { // sort in ascending order 

                int temp = a[i];
                a[i] = a[i + 1];
                a[i + 1] = temp;
                done = false; 

            }
        }
    } while (! done); 
} 
You Lab Twelve assignment is going to be a set of quizzes.

What follows is

A201/A597 LAB ASSIGNMENT TWELVE (LAST!)

You need to:

Good luck with the quizzes.

The Final Exam is based on all of them.


Last updated: Apr 17, 2003 by Adrian German for A201