FileDocCategorySizeDatePackage
Smooth.javaAPI DocExample5041Sat Jun 02 03:12:36 BST 2001None

Smooth.java

// This example is from the book _Java in a Nutshell_ by David Flanagan.
// Written by David Flanagan.  Copyright (c) 1996 O'Reilly & Associates.
// You may study, use, modify, and distribute this example for any purpose.
// This example is provided WITHOUT WARRANTY either expressed or implied.

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

public class Smooth extends Applet implements Runnable {
    static final int deltax = 4;
    static final int deltay = 2;
    static final String message = "Smooth Animation";
    int x = 0; 
    int y = 0;
    Color c1 = new Color(0x0000ff);
    Color c2 = new Color(0xffffff);
    Font font = new Font("Helvetica", Font.BOLD, 24);
    Image offscreen;
    int imagewidth, imageheight;
    int stringwidth, stringheight, stringascent;
    Thread animator = null;
    boolean please_stop = false;

    // Measure the size of the text we'll be animating.  We need this
    // information later to do clipping.
    public void init() {
        FontMetrics fm = this.getFontMetrics(font);
        stringwidth = fm.stringWidth(message);
        stringheight = fm.getHeight();
        stringascent = fm.getAscent();
    }

    // Start the animation
    public void start() { 
        animator = new Thread(this);
        animator.start();
    }
    // Stop it.
    public void stop() { 
        if (animator != null) animator.stop();
        animator = null;
    }
    // Stop and start animating on mouse clicks.
    public boolean mouseDown(Event e, int x, int y) {
        // if running, stop it.  Otherwise, start it.
        if (animator != null) please_stop = true;
        else { please_stop = false; start(); } 
        return true;
    }

    // Draw a fancy background.  Because this background is time-consuming
    // to draw, our animation techniques must be efficient to avoid bad
    // flickering.
    void drawBackground(Graphics gr, Color c1, Color c2, int numsteps) {
        int r, g, b;
        int dr = (c2.getRed() - c1.getRed())/numsteps;
        int dg = (c2.getGreen() - c1.getGreen())/numsteps;
        int db = (c2.getBlue() - c1.getBlue())/numsteps;
        Dimension size = this.size();
        int w = size.width, h = size.height;
        int dw = size.width/numsteps;
        int dh = size.height/numsteps;

        gr.setColor(c1);
        gr.fillRect(0, 0, w, h);
        
        for(r = c1.getRed(), g = c1.getGreen(), b = c1.getBlue();
            h > 0;
            h -= dh, w -= dw, r += dr, g += dg, b += db) {
            gr.setColor(new Color(r, g, b));
            gr.fillArc(-w, -h, 2*w, 2*h, 0, -90);
        }
    }

    // This method draws the background and  text at its current position.
    public void paint(Graphics g) {
            drawBackground(g, c1, c2, 25);
            g.setColor(Color.black);
            g.setFont(font);
            g.drawString(message, x, y);
    }

    // The body of the animator thread.
    public void run() {
        while(!please_stop) {
            Dimension d = this.size();
            
            // Make sure the offscreen image is created and is the right size.
            if ((offscreen == null) ||
                ((imagewidth != d.width) || (imageheight != d.height))) {
                // if (offscreen != null) offscreen.flush();
                offscreen = this.createImage(d.width, d.height);
                imagewidth = d.width;
                imageheight = d.height;
            }
            
            // Set up clipping.  We only need to draw within the
            // old rectangle that needs to be cleared and the new
            // one that is being drawn.

            // the old rectangle
            Rectangle oldrect = new Rectangle(x, y-stringascent,
                              stringwidth, stringheight);
            // Update the coordinates for animation.
            x = ((x + deltax)%d.width);
            y = ((y + deltay)%d.height);

            // the new rectangle
            Rectangle newrect = new Rectangle(x, y-stringascent,
                              stringwidth, stringheight);
            // Compute the union of the rectangles
            Rectangle r = newrect.union(oldrect);
                
            // Use this rectangle as the clipping region when
            // drawing to the offscreen image, and when copying
            // from the offscreen image to the screen.
            Graphics g = offscreen.getGraphics();
            g.clipRect(r.x, r.y, r.width, r.height);
            // Draw into the off-screen image.
            paint(g);
            // Copy it all at once to the screen, using clipping.
            g = this.getGraphics();
            g.clipRect(r.x, r.y, r.width, r.height);
            g.drawImage(offscreen, 0, 0, this);

            // wait a tenth of a second, then draw it again!
            try { Thread.sleep(100); } catch (InterruptedException e) { ; }
        }
        animator = null;
    }
}