5

I am creating a program that uses JFrame, JPanel, JLabel and all other sorts of swing components.

What I want to do is create a 2D animation on a separate JPanel that is dedicated to this animation. So I will be overriding the paintComponent (Graphics g) method.

I have experience making animations with for loops + Threads, but I am hearing that threads are not safe with swing.

Due to this, is it safe for me to make an animation with the use of the Runnable interface? If not what shall I use (e.g. Timer) and please give a small example on how to best use it (or a link to a web page).

EDIT:

Thanks to Jeff, I will be using Timer to create the animation. For future viewers of this question, here is a quick program I coded in about 5 minutes, excuse the dirty code.

I have also added some quick comments.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;


class JFrameAnimation extends JFrame implements ActionListener
{

    JPanel panel;
    Timer timer;
    int x, y;

    public JFrameAnimation ()
    {
        super ();
        setDefaultCloseOperation (EXIT_ON_CLOSE);
        timer = new Timer (15, this); //@ First param is the delay (in milliseconds) therefore this animation is updated every 15 ms. The shorter the delay, the faster the animation.
        //This class iplements ActionListener, and that is where the animation variables are updated. Timer passes an ActionEvent after each 15 ms.

    }


    public void run ()
    {

        panel = new JPanel ()
        {
            public void paintComponent (Graphics g)  //The JPanel paint method we are overriding.
            {
                g.setColor (Color.white);
                g.fillRect (0, 0, 500, 500); //Setting panel background (white in this case);
                //g.fillRect (-1 + x, -1 + y, 50, 50);  //This is to erase the black remains of the animation. (not used because the background is always redrawn.
                g.setColor (Color.black);
                g.fillRect (0 + x, 0 + y, 50, 50); //This is the animation.

            }

        }
        ;
        panel.setPreferredSize (new Dimension (500, 500)); //Setting the panel size

        getContentPane ().add (panel); //Adding panel to frame.
        pack ();
        setVisible (true);
        timer.start (); //This starts the animation.
    }


    public void actionPerformed (ActionEvent e)
    {
        x++;
        y++;
        if (x == 250)
            timer.stop (); //This stops the animation once it reaches a certain distance.
        panel.repaint ();  //This is what paints the animation again (IMPORTANT: won't work without this).
        panel.revalidate (); //This isn't necessary, I like having it just in case.

    }


    public static void main (String[] args)
    {
        new JFrameAnimation ().run (); //Start our new application.
    }
}
Jimmy Huch
  • 4,400
  • 7
  • 29
  • 34
  • No need to give you an example as there are plenty to be found on this site and others if take a little effort to do some searching. Good luck! – Hovercraft Full Of Eels Jun 08 '11 at 03:03
  • for example, check out my code in this link: [java-label-settext-and-setbounds-clashing](http://stackoverflow.com/questions/4702805/java-label-settext-and-setbounds-clashing/4702819#4702819) – Hovercraft Full Of Eels Jun 08 '11 at 03:24

2 Answers2

8

Jimmy, I think you are misunderstanding how threads work in Swing. You must use a specific thread called the Event Dispatch Thread to do any updating on swing components (with a few specific exceptions I won't discuss here). You can use a swing timer to set a recurring task to run on the event dispatch thread. See this example of how to use Swing timers. http://download.oracle.com/javase/tutorial/uiswing/misc/timer.html

You should also read up on the Event Dispatch Thread so you understand its place in Swing http://download.oracle.com/javase/tutorial/uiswing/concurrency/dispatch.html

Java also provides a variety of methods for working with Swing in the SwingUtilities class, notably invokeLater and invokeAndWait which will run code on the event dispatch thread.

Jeff Storey
  • 56,312
  • 72
  • 233
  • 406
  • Okay, i didn't know much about invokeLater and invokeAndWait. After a quick read about this whole EDT stuff, I have a choice of doing one of two things. 1 - Use Timer that will move my animation one pixel at a time calling the repaint () method. 2 - Create an animation with a class that implements Runnable and use invokeAndWait to run the animation. Which one would you recommend? – Jimmy Huch Jun 08 '11 at 03:02
  • If it's a constant, smooth animation, a timer is going to be a pretty simple approach and it sounds like it should work well for what you are describing. You typically wouldn't want to do a long running animation in invokeAndWait since that would lockup the event dispatch thread until finished and other user interface (for example, mouse events) couldn't be processed until the animation is done (unless of course that is what you want). – Jeff Storey Jun 08 '11 at 03:11
  • Yeh, I coded up something real quick, looks like I will be using Timer! Thanks for your help Jeff. – Jimmy Huch Jun 08 '11 at 03:20
1

While is good to understand the EDT and SwingUtilities (everybody doing Swing should do so) if you're going to be doing a lot of animation I would recommend to use the TimingFramework. This will allow you to concentrate a little more on design and will give you a better control on "rate". Inherently the timing framework uses a Swing timer so the callbacks are on the EDT. Part of the Filthy-rich clients collection, the author made the chapter available.

Have fun!

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
Windust
  • 11
  • 1