FileDocCategorySizeDatePackage
PhotoFrame.javaAPI DocJ2ME MIDP 2.013193Thu Nov 07 12:02:18 GMT 2002example.photoalbum

PhotoFrame

public class PhotoFrame extends Canvas implements Runnable
This 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
style
border style
private int
speed
animation speed set
private Vector
images
Vector of images to display
private int
index
Index of next image to display
private int
imageX
X offset of image in frame
private int
imageY
X offset of image in frame
private int
imageWidth
Width and height of image
private int
imageHeight
private Thread
thread
Thread used for triggering repaints
private Image
image
buffer image of the screen
private Image
bimage
Pattern image used for border
private long
paintTime
Time of most recent paint
private long
statsTime
Time of most recent frame rate report
int
frameCount
Number of frames since last frame rate report
int
frameRate
Last reported frame rate (for re-paint)
private static final int[]
speeds
Mapping 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 ImagegenBorder()
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.

return
the image initialized with the pattern

        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 voidgenFrame(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.

param
style the style of frame to draw.
param
x the x offset of the image.
param
y the y offset of the image
param
width the width of the anmiation image
param
height the height of the animation image

        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);
    
intgetSpeed()
Get the speed at which animation occurs.

return
the current speed.
see
setSpeed

        return speed;
    
intgetStyle()
Get the style being used for borders.

return
the style.

        return style;
    
protected voidhideNotify()
Notified when the Canvas is no longer visible. Signal the running Thread that it should stop.

        thread = null;
    
booleanintersectsClip(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

param
g the Graphics context to check.
param
x the x value of the upper left corner of the rectange
param
y the y value of the upper left corner of the rectange
param
w the width of the rectangle
param
h the height of the rectangle
return
true if the rectangle intersects the clipping region

        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 voidkeyPressed(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.

param
keyCode of the key pressed

        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 voidkeyRepeated(int keyCode)
Handle key repeat events as regular key events.

param
keyCode of the key repeated

        keyPressed(keyCode);
    
voidnext()
Advance to the next image and wrap around if necessary.

        if (images == null || ++index >= images.size()) {
            index = 0;
        } 
    
protected voidpaint(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.

param
g the Graphics context to which to draw

	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 voidpaintBorder(Graphics g, int style, int w, int h)
Draw a border of the selected style.

param
g graphics context to which to draw.
param
style of the border to display
param
w the width reserved for the image
param
h the height reserved of the image
see
setStyle

	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);
	    }
	}
    
voidprevious()
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;
	}
    
voidreset()
Reset the PhotoFrame so it holds minimal resources. The animation thread is stopped.

        images = null;
        thread = null;
    
public voidrun()
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) {
                }
            }
        }
    
voidsetImages(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.

param
images a vector of images to be displayed.

        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);
    
voidsetSpeed(int speed)
Set the animation speed. Speed:
  1. 0 = stop
  2. 1 = slow
  3. 2 = medium
  4. 3 = fast
  5. 4 = unlimited

param
speed speedo of animation 0-3;

	this.speed = speed;
	statsTime = 0;
    
voidsetStyle(int style)
Set the frame style. Recreate the photo frame image from the current style and location and size

Style:

  1. Style 0: No border is drawn.
  2. Style 1: A simple border is drawn
  3. Style 2: The border is outlined and an image is created to tile within the border.

param
style the style of the border; 0 = none, 1 = simple, 2 = fancy.

	this.style = style;
        genFrame(style, imageX, imageY, imageWidth, imageHeight);
    
protected voidshowNotify()
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();
        }