1

I am animating a series of images in java. So far I able to animate without any problem. The problem occur only when I add in control(Start, Stop, etc..). When I press Start in my GUI the GUI does not show the animation only the last frame is shown after the animation has ended.

I not sure is it the threading problem or a painting problem, as I have tried a few methods and none of them worked.

Following is my code:

public class SwingAnimation extends JPanel implements ActionListener {

protected JFrame frame;
protected JLabel lblDisplay;
protected JButton BtnStart, BtnStop, BtnPause;
protected JCheckBox chkLoop;
protected Thread th;

public static void main(String[] args) {
    SwingAnimation sa = new SwingAnimation();
}

public SwingAnimation() {
    frame = new JFrame("Animation");
    Panel panel = new Panel();

    lblDisplay = new JLabel();
    BtnStart = new JButton("Start");
    BtnStop = new JButton("Stop");
    BtnPause = new JButton("Pause");
    chkLoop = new JCheckBox("Loop");

    BtnStop.setEnabled(false);
    BtnPause.setEnabled(false);

    BtnStart.setActionCommand("start");
    BtnStop.setActionCommand("stop");
    BtnPause.setActionCommand("pause");

    panel.add(lblDisplay);
    panel.add(BtnStart);
    panel.add(BtnPause);
    panel.add(BtnStop);
    panel.add(chkLoop);
    frame.add(panel, BorderLayout.CENTER);
    frame.setSize(400, 400);
    frame.setVisible(true);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    //set the frame in the center of the screen
    Dimension screensize = Toolkit.getDefaultToolkit().getScreenSize();
    int screen_x = (screensize.width - frame.getWidth()) / 2;
    int screen_y = (screensize.height - frame.getHeight()) / 2;
    frame.setLocation(screen_x, screen_y);

    BtnStart.addActionListener(this);
    BtnStop.addActionListener(this);
    BtnPause.addActionListener(this);
    chkLoop.addActionListener(this);
    th = new Thread();
    //ImageAnimator();
}

public void ImageAnimator() {
    try {
        for (int i = 0; i <= 299; i++) {
            ImageIcon images = new ImageIcon("C:\\Users\\Desktop\\Images\\Snap" + i + ".jpg");
            lblDisplay.setIcon(images);
            th.sleep(25);
        }
    } catch (InterruptedException e) {
    }
}

public void actionPerformed(ActionEvent e) {
    if ("start".equals(e.getActionCommand())) {
        BtnStart.setEnabled(false);
        BtnStop.setEnabled(true);
        BtnPause.setEnabled(true);
        lblDisplay.setVisible(true);
        ImageAnimator();
    } else if ("stop".equals(e.getActionCommand())) {
        BtnStart.setText("Start");
        BtnStart.setEnabled(true);
        BtnStop.setEnabled(false);
        BtnPause.setEnabled(false);
        lblDisplay.setVisible(false);
        th = null;
    } else if ("pause".equals(e.getActionCommand())) {
        BtnStart.setText("Resume");
        BtnStart.setEnabled(true);
        BtnStop.setEnabled(true);
        BtnPause.setEnabled(false);
    }
}

}

HH.
  • 769
  • 2
  • 10
  • 21
  • not realated to your problem but there is no need for creating the Thread saved in `th`. The `sleep` method is static and should be called as `Thread.sleep(25)`. – user85421 Jan 06 '10 at 21:22

2 Answers2

3

Quick Fix:

Change ImageAnimator() like this:

        lblDisplay.setIcon(images);
        lblDisplay.paintImmediately(getBounds());
        th.sleep(25);

The problem you're having is that setting an icon does not automatically cause Swing to repaint the component onscreen. Calling paintImmediately will do that.

General advice:

Animation in swing is normally done using the Swing Timer. You'll notice at the moment that your UI is unresponsive - once you've started the animation, you won't be able to stop it until its over. That's because all Swing events happen on a single thread - the Event Dispatch Thread. Running a loop with Thread.sleep(...) in the middle ties this thread up, leaving it unavailable to process other input (such as pressing the stop button)

This article helped me immeasurably when I was trying to understand how Swing handles concurrency, and The Swing Trail has lots of advice on using Swing effectively, painting custom components etc.

I'd also plug the demo code on Filthy Rich Clients, I'm working through the book at the moment and it's worth a look.

MHarris
  • 1,801
  • 3
  • 21
  • 34
  • and method names should start with a lower case letter so imageAnimator()... :) – willcodejavaforfood Dec 16 '09 at 09:21
  • Good call. I work with a couple of ex C++ gurus, and have gotten so used to their random approach to capitalisation, it didn't even register. :( – MHarris Dec 16 '09 at 09:35
  • Thanks for the advice, but the paintImmediately() method did not work as it keeps telling me that it can't find symbol. But I'll be switching to the swing timer. – HH. Dec 16 '09 at 09:37
  • That'll teach me to double check things I've not used in a while. I think lblDisplay.paintImmediately(lblDisplay.getBounds()) should do the trick, but you're better off on the swing timer anyway. :) – MHarris Dec 16 '09 at 09:53
  • Well,lblDisplay.paintImmediately(lblDisplay.getBounds()) did not do the trick, but rather lblDisplay.paint(lblDisplay.getGraphics()) did it. But i need to let the app run once before i can see the animation. – HH. Dec 16 '09 at 10:19
1

This Java 2D games tutorial covers several basic animation techniques. Some related example that illustrate the techniques are cited here, and this complete example illustrates stop and start buttons.

Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045