Page 1 of 1

Animating an Image in Swing utilizing the Swing Timer Rate Topic: ***** 1 Votes

#1 v0rtex  Icon User is offline

  • Caffeine: db "Never Enough!"
  • member icon

Reputation: 223
  • View blog
  • Posts: 773
  • Joined: 02-June 10

Posted 19 June 2011 - 12:56 AM

*
POPULAR

Animating an Image in Swing utilizing the Swing Timer

Introduction:

In this tutorial, I will show you how to animate Images in terms of direction in Java using the Swing Timer. For those that are perhaps novice to what is animation, animation is the process whereby a Image seemingly moves across the screen. In the programming world, the Image is being updated to a new position so fast that it fakes regular movement.

What is a timer and what is its use?


A timer is generally used as a way of checking data at regular intervals. If we apply this to a game, it can be very useful. Certain elements of a game generally have to be constantly checked and certain tasks generally have to be constantly done such as collision detection and drawing the units to the screen.

A swing timer can be used to schedule tasks as described above at regular or arbitrary intervals with a single thread.
It is a class part of the javax.swing libraries.. The Swing Timer schedules actions via actionPerformed @ specific intervals as will be shown soon. This is generally perfect for Animation and GUI Related tasks.

Timer Logic:
As it is with most that are new to a concept, some questions come to mind. Some of the most common are:

How Do I Implement a Swing Timer:
The simplified steps of this would be:
1) Create a new action or class that instantiates the Timer Class.
2) Code functionality into the action or class
3) Call the timer

Where do I call my Swing Timer:
It really depends on the situation, however if it used for something like updating an Image that is immediately drawn
to the screen upon start up of the Swing application. I would suggest calling it in the constructor of your Swing Application.

How many times per second should I call it?:
Again this depends on what you are doing, if you are checking collision detection or painting something to a screen. Generally you want the timer to update many times a second, something like 15 millisecond intervals should be okay and will equate to around 66 Frames Per Second (FPS).


Now lets get into the code. There are three parts to our Ball Animation Project:

Ball - used to create features of a ball on screen, namely X and Y Positions
MainFrame - JFrame used to display our MainPanel JPanel so we do not have to use an applet.
MainPanel - JPanel that is used for drawing and animating of the "ball", Swing Timer is in here.



Now here is our code, I have purposely left out explanatory comments here here so that I can dissect the program with you afterwards however some self-documenting comments are in the listings below and a fully commented version of this program will be available at the end of the tutorial :) :

Ball.java:

public class Ball {
	/*
	 * Simple Object class to store the ball's co-ordinates.
	 */
	private int x;
	private int y;

	Ball() {
		;
	} // default constructor

	public int getX() { // accessor/GET method for data
		return x;
	}

	public void setX(int x2) { // mutator/SET method for data
		x = x2;
	}

	public int getY() {
		return y;
	}

	public void setY(int y2) {
		y = y2;
	}
}




MainFrame.java:
import java.awt.Panel;
import javax.swing.*;

public class MainFrame extends JFrame {
	// Simple Object class used to add our MainPanel to a JFrame so that it can
	// be displayed without the use of an applet.
	MainPanel mPanel;

	MainFrame() {

		setTitle("Ball animation");
		mPanel = new MainPanel();
		setSize(350, 250);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		add(mPanel); // add MainPanel JPanel to JFrame
		setVisible(true); // show class

	}

	public static void main(String[] args) {
		new MainFrame();
	}
}



MainPanel.java:
//required libraries:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import javax.swing.*;

public class MainPanel extends JPanel { // inherit JPanel
	Image ballImage; // Reserve memory for Image ballImage;
	Ball currentBall = new Ball(); // instantiate our ball class

	// Constructor:-----------------------------------------------------
	public MainPanel() {
		ImageIcon ball_IMG_ICON = new ImageIcon("ball.png");
		ballImage = ball_IMG_ICON.getImage(); // get ImageIcon ball_IMG_ICON and
												// store it in Image ballImage
		prepareImage(ballImage, this);
		currentBall.setX(10);
		currentBall.setY(10); // set currentBall's X and Y Position
		setDoubleBuffered(true);
		new Timer(15, paintTimer).start();
	}

	// ----------------------------------------------------------------

	public void paint(Graphics g) {

		super.paint(g);
		Graphics2D g2d = (Graphics2D) g;
		g2d.drawImage(ballImage, currentBall.getX(), currentBall.getY(), this); //Draws the ball Image at the correct X and Y co-ordinates.									
		Toolkit.getDefaultToolkit().sync(); // necessary for linux users to draw  and animate image correctly
		g.dispose();

	}

	Action paintTimer = new AbstractAction() { // functionality of our timer:
		public void actionPerformed(ActionEvent e) {
			// set X and Y co-ordinates that will then be fetched when drawing
			// the ball Image on the JPanel.
			currentBall.setX(currentBall.getX() + 5);
			currentBall.setY(currentBall.getY() + 5);
			repaint();
		}
	};
}




Dissecting the code:

Lets first start with ball.java:

The class simply contains two private integers namely x and y that are used to store the ball's position on screen and that have accessors/mutators or GETTERS/SETTERS to access and change the information as this will be necessary when redrawing the ball Image.

Well that was simple enough... Now for MainFrame.java:

Our MainFrame.java class contains the main method and this is the class that is called first. We simply add our MainPanel (JPanel Component) to our JFrame container via:
MainPanel mPanel = new MainPanel();




and then set some mundane information about the JFrame namely (note the comments if you are unsure of what the methods do):

setTitle("Ball Animation"); //You guessed it, this sets the Title of our Swing Application to Ball Animation
setSize(350,250); //sets Size of JFrame, 350 pixels wide by 250 pixels high
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //EXITS the program when you click the "X" button
add(mPanel); //adds our MainPanel object
setVisible(true); //shows the MainFrame



Now for the actual animation, lets look at our JPanel MainPanel.java:


We firstly create a Image data structure for the ball Image and instantiate our ball class with the handle of currentBall
Image ballImage;
ball currentBall = new Ball();



We then proceed to load the image via the following:

ImageIcon ball_IMG_ICON = new ImageIcon("ball.png");
ballImage= ball_IMG_ICON.getImage(); //get ImageIcon ball_IMG_ICON and store it in Image ballImage
prepareImage(ballImage, this);



We then set the starting position of currentBall namely to 10,10 from the Top Left Corner:
currentBall.setX(10); currentBall.setY(10); //set currentBall's X and Y Position



The next statement is very important if you are drawing loads of things at once and I included this as it is necessary knowledge:
setDoubleBuffered(true);



Application will use buffers this is efficient as in this case the drawing is done in memory and then
copied to the screen which can speed up our program although once again due to today's hardware features most Computer Systems will not lag running a program like this however this method is essential when you are drawing and animating many things at once especially to avoid flickering. For more on buffers, see this Link.


Next we create a Swing Timer that will perform the action we describe later in the program and how often we call it:
new Timer(15, paintTimer).start(); 



Here is a breakdown of the parameters/methods used:
  • new Timer(:
    create Timer, call it in constructor of MainPanel().
  • 15,:
    15 = time between next call, measured in milliseconds. Decreasing this value can smooth
    animation but means your application requires more memory and processing to constantly paint, generally not a big issue today however. A interval of 15 milliseconds equates to 66 or so fps when drawing the image(s) which is more than acceptable for most applications.

  • paintTimer):
    paintTimer refers to the action method that we are going to call
  • .start();:
    start() obviously starts our Timer



Hence the final statement is: create Timer(15, paintTimer).start();


Now onto the paint method, this is overridden from the java.awt.component and is called every time we use repaint(). The comments explain the relevant code:

public void paint(Graphics g) { 

    super.paint(g); //we repaint the JPanel and clear old images otherwise the previous image and new image would overlap
    
    Graphics2D g2d = (Graphics2D)g; //creates a Graphics2D element which we use for drawing
    
    g2d.drawImage(ballImage, currentBall.getX(), currentBall.getY(), this);//paint ballImage @ currentBall's X and Y position

    Toolkit.getDefaultToolkit().sync(); //This if for linux systems, it synchronizes the painting otherwise it would not be smooth.

   g.dispose(); 
}



Now for the action method. This is the functionality of our Swing Timer, without this method. There would be no point to the timer. The method is actually really simplistic and simply increases the Ball's X and Y values and then repaints the JPanel whenever it is called:

Action paintTimer = new AbstractAction() { 

	public void actionPerformed(ActionEvent e) {//functionality of our timer:

		//set X and Y co-ordinates that will then be fetched when drawing the ball Image on the JPanel.
		currentBall.setX(currentBall.getX() + 5);  
		currentBall.setY(currentBall.getY() +5);
		repaint();
	}	
};





Here is an example of what will be displayed on the screen:

Posted Image

I hope you have enjoyed this tutorial, It simply animates a image across a screen but can be extended to do much more such as move a player across a screen. The full commented code listing of MainPanel.java can be found below, this was the only class I removed essential comments out of for explanation.

MainPanel.java With comments:

//required libraries:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import javax.swing.*;

public class MainPanel extends JPanel {
	Image ballImage;
	Ball currentBall = new Ball(); // instantiate our ball class

	public MainPanel() {
		ImageIcon ball_IMG_ICON = new ImageIcon("ball.png");
		ballImage = ball_IMG_ICON.getImage(); // get ImageIcon ball_IMG_ICON and
												// store it in Image ballImage
		prepareImage(ballImage, this);
		currentBall.setX(10);
		currentBall.setY(10); // set currentBall's X and Y Position
		setDoubleBuffered(true);

		/*
		 * Application will use buffers this is efficient as in this case the
		 * drawing is done in memory and then copied to the screen which can
		 * speed up our program although once again due to today's hardware
		 * features most Computer Systems will not lag running a program like
		 * this however this method is essential when you are drawing and
		 * animating many things at once.
		 */
		new Timer(15, paintTimer).start();

		/*
		 * create Timer, call it in constructor of MainPanel() 15 = time between
		 * next call, measured in milliseconds. Decreasing this value can smooth
		 * animation but means your application requires more memory and
		 * processing to constantly paint, generally not a big issue today
		 * however. 15 millisecond interval equates to around 66 fps. paintTimer
		 * refers to the action method that we are going to call start()
		 * obviously starts our Timer
		 */
		// call paintTimer's action every 15 milliseconds
	}

	public void paint(Graphics g) {

		super.paint(g); // we repaint the JPanel and clear old images otherwise
						// the previous image and new image would overlap
		Graphics2D g2d = (Graphics2D) g; // creates a Graphics2D element which
											// we use for drawing
		g2d.drawImage(ballImage, currentBall.getX(), currentBall.getY(), this);// paint
																				// ballImage
																				// @
																				// currentBall's
																				// X
																				// and
																				// Y
																				// position
		Toolkit.getDefaultToolkit().sync(); // This is for linux systems, it
											// synchronizes the painting
											// otherwise it would not be smooth.
		g.dispose();

	}

	Action paintTimer = new AbstractAction() {

		public void actionPerformed(ActionEvent e) {// functionality of our
													// timer:

			// set X and Y co-ordinates that will then be fetched when drawing
			// the ball Image on the JPanel.
			currentBall.setX(currentBall.getX() + 5);
			currentBall.setY(currentBall.getY() + 5);
			repaint();
		}
	};
}



I hope you have enjoyed this tutorial, thanks
v0rtex

This post has been edited by v0rtex: 19 June 2011 - 05:04 AM


Is This A Good Question/Topic? 6
  • +

Replies To: Animating an Image in Swing utilizing the Swing Timer

#2 jacknjill5  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 3
  • Joined: 09-September 11

Posted 09 September 2011 - 04:01 AM

i just tried out this code but my image is not loading in the frame even though i put it in the same directory.I use netbeans to code.what seems to be the problem?can i do it like this: add a panel to the frame in the design part and write the "MainPanel.java" code in that only?will it work.im into trying this but please reply why the image isnt loading.
Was This Post Helpful? 0
  • +
  • -

#3 Shealladh  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 2
  • Joined: 22-June 11

Posted 26 October 2011 - 06:26 AM

Thanks for the tutorial.

Our class briefly touched on swing and looking forward to doing more with it, your tut sparked some experimenting :D
Was This Post Helpful? 0
  • +
  • -

#4 Jimmt  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 3
  • Joined: 01-December 11

Posted 01 December 2011 - 09:58 PM

This article is well written, but I'm afraid it doesn't help my program. My program is about clicking a destination and having an image move to the destination. I have the algorithm figured out and I have implemented it, but it takes two clicks(two on the dest. two on the image) to make the image move, and after that, if you try moving it, it glitches. I'm not sure if this is a timer problem or what, but could you please take a look at it.
public void moveTo(final int newX, final int newY, final JPanel repaintPanel){
        
        
        new Timer(0, a).start();
       
        
        
        a = new AbstractAction(){
            int i = imgX;
            public void actionPerformed(ActionEvent e){
                double dx = newX - imgX; //distance x
               double dy = newY - imgY; //distance y
                final double slope = dy / dx;
            
                double transfer = 0.0;
                
                
               if(imgX > newX - 100 && imgX < newX + 100){
                   
                  
                      if(newY > imgY) //if the destination Y is within 200 pixels, just add or subtract y, don't do anything with the x
                      imgY++;
                      if(newY < imgY)
                      imgY--;
                      if(imgY == newY){imgY = newY;}
                      
                  
              }
               
               
               
               
               
              
                  if(imgX < newX){
                    
                    
                   
                   if(imgX == newX){imgX = newX;}
                   if(imgY == newY){imgY = newY;}
                   
                   
                   transfer = slope * i - slope * newX + newY; 
                   
                   
                   
                   
                   imgY = (int)transfer; //cast to int in the final step, not earlier
                  
               
                   imgX = i;
              
                  i++;
             
               
           } else if(imgX > newX) {
                      
                       if(imgX == newX){imgX = newX;}
                   if(imgY == newY){imgY = newY;}
                   
                   
                   transfer = slope * i - slope * newX + newY; 
                   
                   
                   
                   
                   imgY = (int)transfer;//cast to int in the final step, not earlier
               
                   imgX = i;
                      
                      
                      
                      i--;
                      
                  }
        i++;
        repaintPanel.repaint();
            }};
            
                
                
        
               
                   
                       
                   
               
               
        
           
                  
        
           

    
   
}      


here is the method that gets the mouse clicks:
public void mousePressed(MouseEvent e) {
        int clickX = e.getX();
        int clickY = e.getY();
        
       for(int i = 0; i < userSoldierArr.length; i++){
           
        if((clickX > userSoldierArr[i].imgX && clickX < userSoldierArr[i].imgX + 30) && (clickY > userSoldierArr[i].imgY && clickY < userSoldierArr[i].imgY + 30)){//if the user clicks on the unit
            
           userSoldierArr[i].moveTo(relX, relY, this);
           
           this.repaint();
        }  }
        
       }
    public void mouseReleased(MouseEvent e) {
       relX = e.getX();
       relY = e.getY();
        
    }



One more thing, I've tried this animating with a thread and thread.sleep before, and that worked fine, but I had a bug I had to fix, so I thought it would be easier to use this. Before, I used for loops inside the if statements.

Thanks for any help.

oh, and one more thing: my graphics method.
for(int i = 0; i < userSoldierArr.length; i++){
         g2d.drawImage(userSoldierArr[i].unitImg, userSoldierArr[i].imgX, userSoldierArr[i].imgY, null);
        
             }


That's inside the paintcomponent() method which paints a JPanel.
Was This Post Helpful? 0
  • +
  • -

#5 pcboyyyy  Icon User is offline

  • D.I.C Head

Reputation: 0
  • View blog
  • Posts: 75
  • Joined: 29-August 10

Posted 08 March 2012 - 12:05 PM

View Postjacknjill5, on 09 September 2011 - 04:01 AM, said:

i just tried out this code but my image is not loading in the frame even though i put it in the same directory.I use netbeans to code.what seems to be the problem?can i do it like this: add a panel to the frame in the design part and write the "MainPanel.java" code in that only?will it work.im into trying this but please reply why the image isnt loading.


I am having the same problem and first I thought it was because I did not have ball.png, but after adding an image to my source package that did not help it. Does anyone has any ideas? :dozingoff:
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1