FileDocCategorySizeDatePackage
SmoothCircle.javaAPI DocExample3775Sat Jun 02 02:43:52 BST 2001None

SmoothCircle.java

// This example is from _Java Examples in a Nutshell_. (http://www.oreilly.com)
// Copyright (c) 1997 by David Flanagan
// This example is provided WITHOUT ANY WARRANTY either expressed or implied.
// You may study, use, modify, and distribute it for non-commercial purposes.
// For any commercial use, see http://www.davidflanagan.com/javaexamples

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

/** 
 * An applet that displays a simple animation using double-buffering 
 * and clipping
 **/
public class SmoothCircle extends Applet implements Runnable {
  int x = 150, y = 100, r=50;      // Position and radius of the circle
  int dx = 8, dy = 5;              // Trajectory of circle
  Dimension size;                  // The size of the applet
  Image buffer;                    // The off-screen image for double-buffering
  Graphics bufferGraphics;         // A Graphics object for the buffer
  Thread animator;                 // Thread that performs the animation
  boolean please_stop;             // A flag asking animation thread to stop

  /** Set up an off-screen Image for double-buffering */
  public void init() {
    size = this.size();
    buffer = this.createImage(size.width, size.height);
    bufferGraphics = buffer.getGraphics();
  }

  /** Draw the circle at its current position, using double-buffering */
  public void paint(Graphics g) {
    // Draw into the off-screen buffer.
    // Note, we could do even better clipping by setting the clip rectangle
    // of bufferGraphics to be the same as that of g.
    // In Java 1.1:  bufferGraphics.setClip(g.getClip());
    bufferGraphics.setColor(this.getBackground());
    bufferGraphics.fillRect(0, 0, size.width, size.height); // clear the buffer
    bufferGraphics.setColor(Color.red);
    bufferGraphics.fillOval(x-r, y-r, r*2, r*2);            // draw the circle

    // Then copy the off-screen buffer onto the screen
    g.drawImage(buffer, 0, 0, this);
  }

  /** Don't clear the screen; just call paint() immediately
  *   It is important to override this method like this for double-buffering */
  public void update(Graphics g) { paint(g); }

  /** The body of the animation thread */
  public void run() {
    while(!please_stop) {
      // Bounce the circle if we've hit an edge.
      if ((x - r + dx < 0) || (x + r + dx > size.width)) dx = -dx;
      if ((y - r + dy < 0) || (y + r + dy > size.height)) dy = -dy;

      // Move the circle.
      x += dx;  y += dy;

      // Ask the browser to call our paint() method to redraw the circle
      // at its new position.  Tell repaint what portion of the applet needs
      // be redrawn: the rectangle containing the old circle and the
      // the rectangle containing the new circle.  These two redraw requests
      // will be merged into a single call to paint()
      repaint(x-r-dx, y-r-dy, 2*r, 2*r);   // repaint old position of circle
      repaint(x-r, y-r, 2*r, 2*r);         // repaint new position of circle

      // Now pause 1/10th of a second before drawing the circle again.
      try { Thread.sleep(100); } catch (InterruptedException e) { ; }
    }
    animator = null;
  }

  /** Start the animation thread */
  public void start() {
    if (animator == null) {
      please_stop = false;
      animator = new Thread(this);
      animator.start();
    }
  }

  /** Stop the animation thread */
  public void stop() { please_stop = true; }

  /** Allow the user to start and stop the animation by clicking */
  public boolean mouseDown(Event e, int x, int y) {
    if (animator != null) please_stop = true;  // if running request a stop
    else start();                              // otherwise start it.
    return true;
  }
}