PhotoFramepublic class PhotoFrame extends Canvas implements RunnableThis PhotoFrame provides the picture frame and drives the animation
of the frames and the picture. It handles the starting and stopping
of the Animation and contains the Thread used to do
the timing and requests that the Canvas be repainted
periodically.
It controls the border style and animation speed. |
Fields Summary |
---|
private int | styleborder style | private int | speedanimation speed set | private Vector | imagesVector of images to display | private int | indexIndex of next image to display | private int | imageXX offset of image in frame | private int | imageYX offset of image in frame | private int | imageWidthWidth and height of image | private int | imageHeight | private Thread | threadThread used for triggering repaints | private Image | imagebuffer image of the screen | private Image | bimagePattern image used for border | private long | paintTimeTime of most recent paint | private long | statsTimeTime of most recent frame rate report | int | frameCountNumber of frames since last frame rate report | int | frameRateLast reported frame rate (for re-paint) | private static final int[] | speedsMapping of speed values to delays in ms.
Indices map to those in the speed ChoiceGroup in the options form.
The indices are: 0 = stop, 1 = slow, 2 = medium, 3 = fast. |
Constructors Summary |
---|
PhotoFrame()Create a new PhotoFrame.
Create an offscreen mutable image into which the border is drawn.
Border style is none (0).
Speed is stopped (0) until set.
image = Image.createImage(getWidth(), getHeight());
setStyle(0);
setSpeed(0);
|
Methods Summary |
---|
private Image | genBorder()Create an image for the border.
The border consists of a simple "+" drawn in a 5x5 image.
Fill the image with white and draw the "+" as magenta.
Image image = Image.createImage(5, 5);
Graphics g = image.getGraphics();
g.setColor(255, 255, 255);
g.fillRect(0, 0, 5, 5);
g.setColor(128, 0, 255);
g.drawLine(2, 1, 2, 3); // vertical
g.drawLine(1, 2, 3, 2); // horizontal
return image;
| private void | genFrame(int style, int x, int y, int width, int height)Paint the photo frame into the buffered screen image.
This will avoid drawing each of its parts on each repaint.
Paint will only need to put the image into the frame.
Graphics g = image.getGraphics();
// Clear the entire image to white
g.setColor(0xffffff);
g.fillRect(0, 0, image.getWidth()+1, image.getHeight()+1);
// Set the origin of the image and paint the border and image.
g.translate(x, y);
paintBorder(g, style, width, height);
| int | getSpeed()Get the speed at which animation occurs.
return speed;
| int | getStyle()Get the style being used for borders.
return style;
| protected void | hideNotify()Notified when the Canvas is no longer visible.
Signal the running Thread that it should stop.
thread = null;
| boolean | intersectsClip(Graphics g, int x, int y, int w, int h)Return true if the specified rectangle does not intersect
the clipping rectangle of the graphics object. If it returns
true then the object must be drawn otherwise it would be clipped
completely.
The checks are done
int cx = g.getClipX();
if (x + w <= cx)
return false;
int cw = g.getClipWidth();
if (x > cx + cw)
return false;
int cy = g.getClipY();
if (y + h <= cy)
return false;
int ch = g.getClipHeight();
if (y > cy + ch)
return false;
return true;
| protected void | keyPressed(int keyCode)Handle key events. FIRE events toggle between
running and stopped. LEFT and RIGHT key events
when stopped show the previous or next image.
int action = getGameAction(keyCode);
switch (action) {
case RIGHT:
if (thread == null) {
next();
repaint();
}
break;
case LEFT:
if (thread == null) {
previous();
repaint();
}
break;
case FIRE:
// Use FIRE to toggle the activity of the thread
if (thread == null) {
thread = new Thread(this);
thread.start();
} else {
synchronized (this) {
// Wake up the thread to change the timing
this.notify();
thread = null;
}
}
break;
}
| protected void | keyRepeated(int keyCode)Handle key repeat events as regular key events.
keyPressed(keyCode);
| void | next()Advance to the next image and wrap around if necessary.
if (images == null || ++index >= images.size()) {
index = 0;
}
| protected void | paint(Graphics g)Paint is called whenever the canvas should be redrawn.
It clears the canvas and draws the frame and the current
current frame from the animation.
paintTime = System.currentTimeMillis();
if (image != null) {
// Draw the frame unless only the picture is being re-drawn
// This is the inverse of the usual clip check.
int cx = 0, cy = 0, cw = 0, ch = 0;
if ((cx = g.getClipX()) < imageX ||
(cy = g.getClipY()) < imageY ||
(cx + (cw = g.getClipWidth())) > (imageX + imageWidth) ||
(cy + (ch = g.getClipHeight())) > (imageY + imageHeight)) {
g.drawImage(image, 0, 0, Graphics.LEFT|Graphics.TOP);
if (frameRate > 0) {
g.fillRect(0, getHeight(), 60, 20);
g.drawString("FPS = " + frameRate, 0, getHeight(),
Graphics.BOTTOM|Graphics.LEFT);
}
}
// Draw the image if it intersects the clipping region
if (images != null &&
index < images.size() &&
intersectsClip(g, imageX, imageY, imageWidth, imageHeight)) {
g.drawImage((Image)images.elementAt(index),
imageX, imageY, Graphics.LEFT|Graphics.TOP);
}
frameCount++;
// Update Frame rate
int delta = (int)(paintTime - statsTime);
if (delta > 1000 && delta < 10000) {
frameRate = ((frameCount * 1000 + 500) / delta);
frameCount = 0;
statsTime = paintTime;
repaint(); // queue full repaint to display frame rate
}
}
| private void | paintBorder(Graphics g, int style, int w, int h)Draw a border of the selected style.
if (style == 1) {
g.setGrayScale(128);
g.drawRect(-1, -1, w + 1, h + 1);
g.drawRect(-2, -2, w + 3, h + 3);
}
if (style == 2) {
// Draw fancy border with image between outer and inner rectangles
if (bimage == null)
bimage = genBorder(); // Generate the border image
int bw = bimage.getWidth();
int bh = bimage.getHeight();
int i;
// Draw the inner and outer solid border
g.setGrayScale(128);
g.drawRect(-1, -1, w + 1, h + 1);
g.drawRect(-bw - 2, -bh - 2, w + bw * 2 + 3, h + bh * 2 + 3);
// Draw it in each corner
g.drawImage(bimage, -1, -1, Graphics.BOTTOM|Graphics.RIGHT);
g.drawImage(bimage, -1, h + 1, Graphics.TOP|Graphics.RIGHT);
g.drawImage(bimage, w + 1, -1, Graphics.BOTTOM|Graphics.LEFT);
g.drawImage(bimage, w + 1, h + 1, Graphics.TOP|Graphics.LEFT);
// Draw the embedded image down left and right sides
for (i = ((h % bh) / 2); i < h - bh; i += bh) {
g.drawImage(bimage, -1, i, Graphics.RIGHT|Graphics.TOP);
g.drawImage(bimage, w + 1, i, Graphics.LEFT|Graphics.TOP);
}
// Draw the embedded image across the top and bottom
for (i = ((w % bw) / 2); i < w - bw; i += bw) {
g.drawImage(bimage, i, -1, Graphics.LEFT|Graphics.BOTTOM);
g.drawImage(bimage, i, h + 1, Graphics.LEFT|Graphics.TOP);
}
}
| void | previous()Back up to the previous image.
Wrap around to the end if at the beginning.
if (images != null && --index < 0) {
index = images.size()-1;
} else {
index = 0;
}
| void | reset()Reset the PhotoFrame so it holds minimal resources.
The animation thread is stopped.
images = null;
thread = null;
| public void | run()Runs the animation and makes the repaint requests.
The thread will exit when it is no longer the current
Animation thread.
Thread mythread = Thread.currentThread();
long scheduled = System.currentTimeMillis();
statsTime = scheduled;
paintTime = scheduled;
frameCount = 0;
frameRate = 0;
while (thread == mythread) {
synchronized (this) {
try {
// Update when the next frame should be drawn
// and compute the delta till then
scheduled += speeds[speed];
long delta = scheduled - paintTime;
if (delta > 0) {
this.wait(delta);
}
// Advance and repaint the screen
next();
repaint();
serviceRepaints();
} catch (InterruptedException e) {
}
}
}
| void | setImages(java.util.Vector images)Set the array of images to be displayed.
Update the width and height of the image and draw
the border to fit around it in the offscreen image.
this.images = images;
if (images.size() > 0) {
Image image = (Image)images.elementAt(0);
imageWidth = image.getWidth();
imageHeight = image.getHeight();
} else {
imageWidth = 0;
imageHeight = 0;
}
index = 0;
imageX = (getWidth() - imageWidth) / 2;
imageY = (getHeight() - imageHeight) / 2;
genFrame(style, imageX, imageY, imageWidth, imageHeight);
| void | setSpeed(int speed)Set the animation speed.
Speed:
- 0 = stop
- 1 = slow
- 2 = medium
- 3 = fast
- 4 = unlimited
this.speed = speed;
statsTime = 0;
| void | setStyle(int style)Set the frame style.
Recreate the photo frame image from the current style
and location and size
Style:
- Style 0: No border is drawn.
- Style 1: A simple border is drawn
- Style 2: The border is outlined and an image
is created to tile within the border.
this.style = style;
genFrame(style, imageX, imageY, imageWidth, imageHeight);
| protected void | showNotify()Notified when Canvas is made visible.
If there is more than one image to display
create the thread to run the animation timing.
if (images != null && images.size() > 1) {
thread = new Thread(this);
thread.start();
}
|
|