Animated JLabel

Simple animations can be achieved by using a JLabel, series of images and setIcon(). You can create a panel with a overridden paint() (or paintComponent()) - and call repaint from a Timer, but then you have to get much more involved in the Swing Painting Model. Theoretically, this would also skip wrapping images into ImageIcons and then extracting images to paint them, and also save some memory and gain performance. But, if you need advanced animations with exact timing or performance, use Java Media Framework. If you need just a simple1) animation, use this wrapper. JMF also requires you to package the JMF libraries with your application, that may be a bit too much if you are just writing an applet.

Objects of this class are for one-time usage2). To prevent memory leaks, they release all image resources when being removed from the screen or panel (in removeNotify). They also automatically take care about starting and stopping animations when added and removed from the screen.

 
 
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import javax.swing.*;
import javax.swing.JLabel;
 
 

public class AnimatedLabel extends JLabel {
	public ImageIcon[] icons;
	private volatile boolean animationsRunning=false;
	int delay; int pauseBetween;
	private int currentIndex=0;
	private boolean runOnce;
	private boolean disposed=false;
	public AnimatedLabel(
			String imageResourcePrefix, String imageResourceSuffix, 
			int startIndex, 
			int delay, int pauseBetweenAnimations, boolean runOnce){
		
		ArrayList iconsList=new ArrayList();
		boolean hasMore=true;
		for (int i=0; hasMore; i++){
			try{
				String file=imageResourcePrefix+(i+startIndex)+imageResourceSuffix;
                                // ImageHelper is a utility class that loads images 
                                //using the current classloader
				iconsList.add(ImageHelper.getImageIcon(file));
			}
			catch (IllegalArgumentException nex){
				hasMore=false;
			}
		}
		icons=new ImageIcon[iconsList.size()];
		int index=0;
		for (Iterator i=iconsList.iterator();i.hasNext();index++){
			icons[index]=(ImageIcon) i.next();
		}
		setIcon(icons[0]);
		this.delay=delay;
		this.pauseBetween=pauseBetweenAnimations;
		this.runOnce=runOnce;
	}
	public AnimatedLabel(
			String imageResourcePrefix, String imageResourceSuffix, 
			int numImages, int startIndex, 
			int delay, int pauseBetweenAnimations, boolean runOnce){
		icons=new ImageIcon[numImages];
		for (int i=0; i<numImages; i++){
                         // ImageHelper is a utility class that loads images 
                         //using the current classloader
 
			 icons[i]=ImageHelper.getImageIcon(
                          imageResourcePrefix+(i+startIndex)+imageResourceSuffix);			
		}
		setIcon(icons[0]);
		this.delay=delay;
		this.pauseBetween=pauseBetweenAnimations;
		this.runOnce=runOnce;
	}
	public AnimatedLabel(String imageResourcePrefix, String imageResourceSuffix, 
			int numImages, int startIndex, 
			int delay, int pauseBetweenAnimations){
	        this(imageResourcePrefix, imageResourceSuffix, numImages, startIndex, 
                delay, pauseBetweenAnimations, false);
	}
	
	public void addNotify() {
		if (disposed) throw new IllegalStateException ("Already disposed");
		super.addNotify();
		runAnimations();
		
	 }
	public void removeNotify() {
		
		super.removeNotify();
		stopAnimations();
		disposeResources();
	}
	private void disposeResources(){
		disposed=true;
		Arrays.fill(icons,null);
		
	}
	private Thread animatorThread;
	public void runAnimations(){
		if (!animationsRunning){
			animationsRunning=true;
			animatorThread=new Animator();
			animatorThread.start();
		}
	}
	public void stopAnimations(){
		animationsRunning=false;
		animatorThread.interrupt();
		animatorThread=null;
	}
	public void joinThread() throws InterruptedException{
		animatorThread.join();
	}
	private class Animator extends Thread{
		public void run() {
			try{
				while (animationsRunning){
					sleep(delay);
					currentIndex= (currentIndex+1)%icons.length;
					SwingUtilities.invokeAndWait(new Runnable(){
						public void run(){								
								setIcon(icons[currentIndex]);
						}
					});
					if (currentIndex==icons.length-1 && runOnce)
						animationsRunning=false;
					if (currentIndex==0)
						sleep(pauseBetween);
				}
			}
			catch (InterruptedException ex){
				
			}
			catch (InvocationTargetException ex){
				ex.printStackTrace();
			}
		}
	}
}
 
 

Other solutions

1) note: we have used this class in an online casino application with several animated labels running simultaneously with about 60 images each, on Celeron 1.2 Mhz with 256 MB RAM, so this will probably satisfy usual requirements
2) after removing from their container, they dispose all resources and cannot be re-used.
 

Comments? Corrections? Contact us or Login to edit pages directly (registration is free and takes less than displaying a JLabel)
  howto/animated_label.txt · Last modified: 2007/01/02 06:20 by 210.210.13.126 (shantha)
 
Recent changes | RSS changes | Table of contents | News Archive | Terms And Conditions | Register