2

The program makes a ball glide across from top left to bottom right and works. But if I were to shift the line

frame.getContentPane().add(ball);

from its current position to after the for loop, why doesn't the ball show up on the frame. I agree that the ball should no longer move, because all the shifting done in the for loop happens even before I add the ball to the JFrame,but I don't understand why the ball doesn't show up on the screen when I ultimately add it to the frame. Here's the code of the working program, if you shift the line mentioned above to after the for loop, the ball no longer shows up

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

public class Animate 
{
    private JFrame frame;
    private int x,y;
    public static void main(String args[])
    {
        Animate ballRoll = new Animate();
        ballRoll.go();
    }

    public void go()
    {
        frame = new JFrame();
        frame.setSize(500,500);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        MyRoll ball = new MyRoll();
        frame.getContentPane().add(ball);
        for(x = 5;x<=350;x++)
        {
            y=x;

            try
            {
                Thread.sleep(50);
            }
            catch(Exception e)
            {
                System.out.println("dsfsd");
            }
            ball.repaint();
        }


    }

    class MyRoll extends JPanel
    {
        public void paintComponent(Graphics g)
        {
            g.setColor(Color.BLACK);
            g.fillRect(0, 0, this.getWidth(), this.getHeight());
            g.setColor(Color.ORANGE);
            g.fillOval(x, y, 100, 100);
        }
    }
}
user3760100
  • 679
  • 1
  • 9
  • 20
  • `Thread.sleep(50);` this is not how to do animation. Use a Swing `Timer` to call `repaint()`.. – Andrew Thompson Jun 21 '14 at 09:34
  • Wonderful points mentioned in the answer below. I myself was thinking about giving the answer, though, the post below covered everything. In the mean time updated your [code](https://www.dropbox.com/s/v73bbamakoms6mc/Animate.java) too, for you to have a look around. – nIcE cOw Jun 21 '14 at 10:11

1 Answers1

5

Some points to remember:

  1. Don't use Thread.sleep() that sometime hangs the whole swing application instead try with Swing Timer that is most suitable for swing application.

    Read more How to Use Swing Timers

  2. Don't forget to call super.paintComponent() in overridden paintComponent() method.

  3. Call frame.setVisible(true) in the end after adding all the components.

  4. Use frame.pack() instead of frame.setSize(500,500) that fits the components as per component's preferred size.

  5. Override getPreferredSize() to set the preferred size of the JPanel in case of custom painting.

  6. Use SwingUtilities.invokeLater() or EventQueue.invokeLater() to make sure that EDT is initialized properly.

    Read more


Sample code: (change it as per your custom painting)

private Timer timer;
...

timer = new javax.swing.Timer(50, new ActionListener() {

    @Override
    public void actionPerformed(ActionEvent arg0) {
        y = ++x;
        ball.repaint();

        if (x > 350) {
            timer.stop();
        }
    }
});
timer.setRepeats(true);
timer.start();

public static void main(String args[]) {
    SwingUtilities.invokeLater(new Runnable() {

        @Override
        public void run() {
            Animate ballRoll = new Animate();
            ballRoll.go();
        }
    });
}

class MyRoll extends JPanel {
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        ...
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(..., ...);
    }
}
Community
  • 1
  • 1
Braj
  • 46,415
  • 5
  • 60
  • 76
  • 1
    +1 to one awesome answer. One more point, if I could add to the above, would be to keep the access specifier, the same, for overridden methods. `paintComponent` has a `protected` access specifier in this case, try not to change that to `public`. – nIcE cOw Jun 21 '14 at 10:14
  • @Braj thanks a lot for your help. I got to learn a lot of new things thanks to you. But just out of curiosity,I would still like to know why shifting frame.getContentPane().add(ball); to after the for loop results in the ball not showing up in the frame.Could you please tell me the reason for that too.Thanks a million – user3760100 Jun 21 '14 at 11:37
  • `Thread.sleep()` is blocking the GUI and `frame.setVisible()` is called before adding the component in it. call `frame.setVisible(true);` in the end and look what happens? There is no meaning of calling `repaint` until and unless component is added in `JFrame`. – Braj Jun 21 '14 at 11:41