Java tutorial
import java.awt.BorderLayout; import java.awt.Checkbox; import java.awt.Choice; import java.awt.Component; import java.awt.Dimension; import java.awt.Font; import java.awt.Frame; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.Label; import java.awt.MediaTracker; import java.awt.Panel; import java.awt.RenderingHints; import java.awt.Toolkit; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; import java.net.MalformedURLException; import java.net.URL; import java.text.NumberFormat; import java.util.Random; import javax.swing.JFrame; import javax.swing.JPanel; public class ImageBouncer extends JPanel implements Runnable { private boolean trucking = true; private long[] previousTimes; // milliseconds private int previousIndex; private boolean previousFilled; private double frameRate; // frames per second public static void main(String[] args) { String filename = "java2sLogo.png"; if (args.length > 0) filename = args[0]; Image image = null; try { image = blockingLoad(new URL(filename)); } catch (MalformedURLException e) { // TODO Auto-generated catch block e.printStackTrace(); } final ImageBouncer bouncer = new ImageBouncer(image); Frame f = new AnimationFrame(bouncer); f.setFont(new Font("Serif", Font.PLAIN, 12)); Panel controls = new Panel(); controls.add(bouncer.createCheckbox("Bilinear", ImageBouncer.BILINEAR)); controls.add(bouncer.createCheckbox("Transform", ImageBouncer.TRANSFORM)); final Choice typeChoice = new Choice(); typeChoice.add("TYPE_INT_RGB"); typeChoice.add("TYPE_INT_ARGB"); typeChoice.add("TYPE_INT_ARGB_PRE"); typeChoice.add("TYPE_3BYTE_BGR"); typeChoice.add("TYPE_BYTE_GRAY"); typeChoice.add("TYPE_USHORT_GRAY"); typeChoice.add("TYPE_USHORT_555_RGB"); typeChoice.add("TYPE_USHORT_565_RGB"); controls.add(typeChoice); f.add(controls, BorderLayout.NORTH); typeChoice.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent ie) { String type = typeChoice.getSelectedItem(); bouncer.setImageType(type); } }); f.setSize(200, 200); f.setVisible(true); } private boolean mBilinear = false; private boolean mTransform = false; public static final int BILINEAR = 1; public static final int TRANSFORM = 3; private float mDeltaX, mDeltaY; private float mX, mY, mWidth, mHeight; private float mTheta; private Image mOriginalImage; private Image image; public ImageBouncer(Image image) { previousTimes = new long[128]; previousTimes[0] = System.currentTimeMillis(); previousIndex = 1; previousFilled = false; mOriginalImage = image; setImageType("TYPE_INT_RGB"); Random random = new Random(); mX = random.nextFloat() * 500; mY = random.nextFloat() * 500; mWidth = image.getWidth(this); mHeight = image.getHeight(this); mDeltaX = random.nextFloat() * 3; mDeltaY = random.nextFloat() * 3; // Make sure points are within range. addComponentListener(new ComponentAdapter() { public void componentResized(ComponentEvent ce) { Dimension d = getSize(); if (mX < 0) mX = 0; else if (mX + mWidth >= d.width) mX = d.width - mWidth - 1; if (mY < 0) mY = 0; else if (mY + mHeight >= d.height) mY = d.height - mHeight - 1; } }); } public void setSwitch(int item, boolean value) { switch (item) { case BILINEAR: mBilinear = value; break; case TRANSFORM: mTransform = value; break; default: break; } } public void setImageType(String s) { int type = BufferedImage.TYPE_CUSTOM; if (s.equals("TYPE_INT_RGB")) type = BufferedImage.TYPE_INT_RGB; else if (s.equals("TYPE_INT_ARGB")) type = BufferedImage.TYPE_INT_ARGB; else if (s.equals("TYPE_INT_ARGB_PRE")) type = BufferedImage.TYPE_INT_ARGB_PRE; else if (s.equals("TYPE_3BYTE_BGR")) type = BufferedImage.TYPE_3BYTE_BGR; else if (s.equals("TYPE_BYTE_GRAY")) type = BufferedImage.TYPE_BYTE_GRAY; else if (s.equals("TYPE_USHORT_GRAY")) type = BufferedImage.TYPE_USHORT_GRAY; else if (s.equals("TYPE_USHORT_555_RGB")) type = BufferedImage.TYPE_USHORT_565_RGB; else if (s.equals("TYPE_USHORT_565_RGB")) type = BufferedImage.TYPE_USHORT_565_RGB; else { System.out.println("Unrecognized type."); return; } image = makeBufferedImage(mOriginalImage, type); } protected Checkbox createCheckbox(String label, final int item) { Checkbox check = new Checkbox(label); check.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent ie) { setSwitch(item, (ie.getStateChange() == ie.SELECTED)); } }); return check; } public void timeStep() { Dimension d = getSize(); if (mX + mDeltaX < 0) mDeltaX = -mDeltaX; else if (mX + mWidth + mDeltaX >= d.width) mDeltaX = -mDeltaX; if (mY + mDeltaY < 0) mDeltaY = -mDeltaY; else if (mY + mHeight + mDeltaY >= d.height) mDeltaY = -mDeltaY; mX += mDeltaX; mY += mDeltaY; mTheta += Math.PI / 192; if (mTheta > (2 * Math.PI)) mTheta -= (2 * Math.PI); } public void paint(Graphics g) { Graphics2D g2 = (Graphics2D) g; setTransform(g2); setBilinear(g2); // Draw the image. g2.drawImage(image, AffineTransform.getTranslateInstance(mX, mY), null); } protected void setTransform(Graphics2D g2) { if (mTransform == false) return; float cx = mX + mWidth / 2; float cy = mY + mHeight / 2; g2.rotate(mTheta, cx, cy); } protected void setBilinear(Graphics2D g2) { if (mBilinear == false) return; g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); } public void run() { while (trucking) { render(); timeStep(); calculateFrameRate(); } } protected void render() { Graphics g = getGraphics(); if (g != null) { Dimension d = getSize(); if (checkImage(d)) { Graphics imageGraphics = image.getGraphics(); // Clear the image background. imageGraphics.setColor(getBackground()); imageGraphics.fillRect(0, 0, d.width, d.height); imageGraphics.setColor(getForeground()); // Draw this component offscreen. paint(imageGraphics); // Now put the offscreen image on the screen. g.drawImage(image, 0, 0, null); // Clean up. imageGraphics.dispose(); } g.dispose(); } } // Offscreen image. protected boolean checkImage(Dimension d) { if (d.width == 0 || d.height == 0) return false; if (image == null || image.getWidth(null) != d.width || image.getHeight(null) != d.height) { image = createImage(d.width, d.height); } return true; } protected void calculateFrameRate() { // Measure the frame rate long now = System.currentTimeMillis(); int numberOfFrames = previousTimes.length; double newRate; // Use the more stable method if a history is available. if (previousFilled) newRate = (double) numberOfFrames / (double) (now - previousTimes[previousIndex]) * 1000.0; else newRate = 1000.0 / (double) (now - previousTimes[numberOfFrames - 1]); firePropertyChange("frameRate", frameRate, newRate); frameRate = newRate; // Update the history. previousTimes[previousIndex] = now; previousIndex++; if (previousIndex >= numberOfFrames) { previousIndex = 0; previousFilled = true; } } public double getFrameRate() { return frameRate; } // Property change support. private transient AnimationFrame mRateListener; public void setRateListener(AnimationFrame af) { mRateListener = af; } public void firePropertyChange(String name, double oldValue, double newValue) { mRateListener.rateChanged(newValue); } private static Component sComponent = new Component() { }; private static final MediaTracker sTracker = new MediaTracker(sComponent); private static int sID = 0; public static boolean waitForImage(Image image) { int id; synchronized (sComponent) { id = sID++; } sTracker.addImage(image, id); try { sTracker.waitForID(id); } catch (InterruptedException ie) { return false; } if (sTracker.isErrorID(id)) return false; return true; } public Image blockingLoad(String path) { Image image = Toolkit.getDefaultToolkit().getImage(path); if (waitForImage(image) == false) return null; return image; } public static Image blockingLoad(URL url) { Image image = Toolkit.getDefaultToolkit().getImage(url); if (waitForImage(image) == false) return null; return image; } public BufferedImage makeBufferedImage(Image image) { return makeBufferedImage(image, BufferedImage.TYPE_INT_RGB); } public BufferedImage makeBufferedImage(Image image, int imageType) { if (waitForImage(image) == false) return null; BufferedImage bufferedImage = new BufferedImage(image.getWidth(null), image.getHeight(null), imageType); Graphics2D g2 = bufferedImage.createGraphics(); g2.drawImage(image, null, null); return bufferedImage; } } class AnimationFrame extends JFrame { private Label mStatusLabel; private NumberFormat mFormat; public AnimationFrame(ImageBouncer ac) { super(); setLayout(new BorderLayout()); add(ac, BorderLayout.CENTER); add(mStatusLabel = new Label(), BorderLayout.SOUTH); // Create a number formatter. mFormat = NumberFormat.getInstance(); mFormat.setMaximumFractionDigits(1); // Listen for the frame rate changes. ac.setRateListener(this); // Kick off the animation. Thread t = new Thread(ac); t.start(); } public void rateChanged(double frameRate) { mStatusLabel.setText(mFormat.format(frameRate) + " fps"); } }