Need Help with This Animation Code

Hey Guys,

When I run the following code. The animation does not seem to work right. When the button is clicked the circle moves from point a to b, but does not show the movement in between. If I remove the action listener code and button and run the for loop in the go procedure the animation is smooth.

Any suggestions on how to fix this within the context of the code I’ve written? I’m sure there are better ways to do this.

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

public class SimpleAnimation implements ActionListener {

      int x=70;
      int y=70;
      MyDrawPanel drawPanel;
      
      

      public static void main (String [] args) {
            
            SimpleAnimation gui = new SimpleAnimation();
            gui.go ();
      }

      public void go () {
            
            JFrame frame = new JFrame("Tom's Animation Program");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

            JButton button = new JButton("Click To Start The Show !");
            button.addActionListener (this);
            drawPanel = new MyDrawPanel();
            frame.getContentPane().add(BorderLayout.SOUTH,button);
            frame.getContentPane().add(drawPanel);
            frame.setSize(300,300);
            frame.setVisible(true);
      }
            
      
      

      public void actionPerformed (ActionEvent event){
      
            for (int i=0; i<130; i++) {
            
                  x++;
                  y++;
                  drawPanel.repaint ();
                  try{Thread.sleep(50);
                  }catch (Exception ex){}
            }
      
      }
      class MyDrawPanel extends JPanel{

            public void paintComponent (Graphics g){

                  g.setColor(Color.white);
                  g.fillRect(0,0,this.getWidth(),this.getHeight());

                  g.setColor(Color.green);
                  g.fillOval (x,y,40,40);
            }
      }
}

To explain this problem, a little Java architecture is required. When the JVM starts, several threads are automatically started. One is the main execution thread, where you program runs. Then there is the GarbageCollector thread and the event dispatch thread. There may be others, but you need to look at the event dispatch thread. When you register an event listener(eg ActionListener), your method actionPerformed will be called from the event dispatch thread. No other events can be processed while you are in the actionPerformed method. Once this method returns, the next event can be processed. For this reason, most tutorials/books will tell you to keep your processing to a minimum in those methods. Your problem occurs because painting is also done from the event dispatch thread. So your constant calls to repaint() inside actionPerformed will not be serviced until actionPerformed exits. Since your loop is done at this point, you only see the end result. For this reason, you need to do animation in a separate thread of your own. I have modified your code to show you an example.


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

public class SimpleAnimation extends JPanel implements ActionListener, Runnable {

    int x=70;
    int y=70;
    boolean drawAnim = false;

    public static void main (String [] args) {

        SimpleAnimation gui = new SimpleAnimation();
        gui.go ();
    }

    public void go () {

        Thread t = new Thread(this);
        t.start();
        JFrame frame = new JFrame("Tom's Animation Program");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JButton button = new JButton("Click To Start The Show !");
        button.addActionListener (this);
        frame.getContentPane().add(BorderLayout.SOUTH,button);
        frame.getContentPane().add(this);
        frame.setSize(300,300);
        frame.setVisible(true);
    }

    public void run() {
        while(true) {
            if(drawAnim) {
                for (int i=0; i<130; i++) {
                    x++;
                    y++;
                    repaint ();
                    try {
                        Thread.sleep(50);
                    }
                    catch (Exception ex){}
                }
                drawAnim = false;
            }
        }
    }

    public void actionPerformed (ActionEvent event){
        drawAnim = true;
    }

    public void paintComponent (Graphics g){
        g.setColor(Color.white);
        g.fillRect(0,0,this.getWidth(),this.getHeight());

        g.setColor(Color.green);
        g.fillOval (x,y,40,40);
    }
}