// 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;
}
}
|