Second Summer 2002


Lecture Notes Twenty-Seven: Double-buffering and help with Homework Six
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.

The rest of the lecture will be spent on discussing Homework Six.

We want first to understand how we would be solving the problem ourselves.

Conceptualization is the first step.

If we can't teach someone else how to do it, we won't be able to teach the computer.

Once we come up with some sort of

we need to think if

We need to come up with a plan, and I will describe one such approach.

And here's a method that we looked at before that is close to the approach I will suggest.

/*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); 
} 
This method runs subsequent passes through the array, and so will we.


Last updated: Jul 25, 2002 by Adrian German for A201