Search code examples
javaswingtimerpaintcomponent

Java swing animation


I'm trying to make a flip effect with java swing, but my flip method doesn't look like a real flip.In my method I change the width with the x var and the xspeed, making the image smaller and then check if the x is >= as half of my image. hope somebody could help me improve it thanks in advance.

Animation Class

public class Animation extends JPanel implements MouseListener {

private static final long serialVersionUID = 3264508834913061718L;

public Timer timer;
public int x = 0;
public int xspeed = 2;
public  boolean turning = true;
public String pic = "/images/image.jpg";
public URL url = this.getClass().getResource(pic);
public ImageIcon im = new ImageIcon(url);
public String rev = "/images/image2.jpg";
public URL url2 = this.getClass().getResource(rev);
public ImageIcon reverse = new ImageIcon(url2);

public Animation(){
    this.setPreferredSize(new Dimension(128,128));
    this.setBackground(Color.BLACK);
    this.setFocusable(true);
    this.addMouseListener(this);

}

public void paintComponent(Graphics g){
    super.paintComponent(g);

    g.drawImage(im.getImage(), 0 , 0, im.getIconWidth() - x, im.getIconHeight(), null);
}

public void flipAnimation(){
    ActionListener actionListener = new ActionListener() {

        @Override
        public void actionPerformed(ActionEvent e) {
            // TODO Auto-generated method stub
            // 
            if (turning) {
                x = x + xspeed;
            }

            repaint();
            // x in the middle paint new image & set turning to false to stop animation
            if(x >= im.getIconWidth()/2){ 
                turning = false;
                 x = 0;
                 im = reverse; 
            }
        }
    };
    if (turning) {
        if (timer != null)timer.stop();

        timer = new Timer(30, actionListener);
        timer.start();
    }
}


@Override
public void mouseClicked(MouseEvent e) {
    // TODO Auto-generated method stub
    e.getSource();
    flipAnimation();
}

Solution

  • First, I’m guessing you want your image to “fold in” from both sides, so you’ll want to increase the image’s left edge along with its right edge:

    g.drawImage(im.getImage(), x / 2 , 0, im.getIconWidth() - x, im.getIconHeight(), this);
    

    Notice the first int argument has been changed from 0 to x / 2. Also, it is good practice to pass this as the ImageObserver argument when drawing images in a paintComponent method, since the component itself is the object which is interested in repainting itself when the image has finished loading in the background.

    Second, change this:

    if (turning) {
        x = x + xspeed;
    }
    

    to this:

    x = x + xspeed;
    

    You don’t need a flag to control the animation. (The correct way to stop the animation is to call timer.stop(), which I’ll get to in a moment.)

    Third, change this:

    if(x >= im.getIconWidth()/2){ 
        turning = false;
        x = 0;
    

    to this:

    if(x >= im.getIconWidth()){ 
        xspeed = -xspeed;
    
    • As I said, the turning flag is not needed.
    • The reason for comparing x to the image’s width, instead of half of the width, is that we want to change the image only when the first image has completely “folded in.”
    • The negation of xspeed reverses the animation.

    Finally, at the end of your actionPerformed method, you’ll want to add this:

    if (x <= 0) {
        timer.stop();
    }
    

    This halts the animation when the reverse image reaches its full size, which is why the turning flag is not needed.