John Watson
John Watson

Reputation: 869

Basic animation not performing

I am learning java. This is my first animation. I want a ball to move up and down continuously when start button is pressed, and it should STOP when stop button is pressed. The code I have written moves the ball 5 times(3 times down and 2 times up). But the panel displays only start and final positions, it does not display intermediate positions. How to display intermediate positions as well?

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

public class dabble
{
    private boolean z = true;
    private int x=10;
    private int y=10;
    private JFrame frame;
    private JLabel label;
    private mypanel panel;
    private JButton b1;
    private JButton b2;

    public static void main (String[] args)
    {
        dabble dab = new dabble();
        dab.start();
    }

    void start()
    {
        frame = new JFrame();
        label = new JLabel();
        panel = new mypanel();
        b1= new JButton("Start");
        b2= new JButton("Stop");

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        b1.addActionListener(new al1());
        b2.addActionListener(new al2());

        frame.getContentPane().add(BorderLayout.NORTH,b1);
        frame.getContentPane().add(BorderLayout.SOUTH,b2);
        frame.getContentPane().add(BorderLayout.CENTER,panel);
        frame.getContentPane().add(BorderLayout.EAST,label);
        frame.setSize(600,600);
        frame.setVisible(true);
    }

    void go()
    {
        for(int i=0;i<5;i++)
        {
            if(z==false)
                break;
            //label.setText("Hi");
            y=510-y;
            panel.repaint();
            try{
                Thread.sleep(500);
                //label.setText("sleep");
            }catch(Exception Ex)
            {
             //label.setText("exp");
            }
        }
    }

    class al1 implements ActionListener{
        public void actionPerformed(ActionEvent event){
            go();
        }
    }

    class al2 implements ActionListener{
        public void actionPerformed(ActionEvent event){
            z=false;
        }
    }

    class mypanel extends JPanel 
    {
        public void paintComponent ( Graphics g)
        {
            g.setColor(Color.white);
            g.fillRect(0,0,this.getWidth(),this.getHeight());
            int red = (int) (Math.random()*255);
            int green = (int) (Math.random()*255);
            int blue = (int) (Math.random()*255);
            Color c1 = new Color(red,green,blue);
            g.setColor(c1);
            g.fillOval(x,y,20,20);
        }
    }
}

Upvotes: 2

Views: 270

Answers (2)

Guillaume Polet
Guillaume Polet

Reputation: 47607

Well you perform your loop 5 times (instead of an infinite loop). Moreover you change the vertical position from 10 to 500 and then back to 10 etc... If you want to see intermediate position, you should consider asking to repaint the intermediate positions as well providing the intermediate values of y.

OK, doing the following solves your issues but it is definitely a poor design:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class dabble {

    private static final long ANIMATION_DURATION = 5000; // 5 seconds
    private static final int REFRESH_RATE = 10;// 10 times per second
    private boolean incrementing = true;
    private volatile boolean z = true;
    private int x = 10;
    private volatile int y = 10;
    private JFrame frame;
    private JLabel label;
    private mypanel panel;
    private JButton b1;
    private JButton b2;

    public static void main(String[] args) {
        dabble dab = new dabble();
        dab.start();
    }

    void start() {
        frame = new JFrame();
        label = new JLabel();
        panel = new mypanel();
        b1 = new JButton("Start");
        b2 = new JButton("Stop");

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        b1.addActionListener(new al1());
        b2.addActionListener(new al2());

        frame.getContentPane().add(BorderLayout.NORTH, b1);
        frame.getContentPane().add(BorderLayout.SOUTH, b2);
        frame.getContentPane().add(BorderLayout.CENTER, panel);
        frame.getContentPane().add(BorderLayout.EAST, label);
        frame.setSize(600, 600);
        frame.setVisible(true);
    }

    void go() {
        new Animation().start();
    }

    class al1 implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent event) {
            go();
        }
    }

    class al2 implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent event) {
            z = false;
        }
    }

    class mypanel extends JPanel {
        @Override
        public void paintComponent(Graphics g) {
            g.setColor(Color.white);
            g.fillRect(0, 0, this.getWidth(), this.getHeight());
            int red = (int) (Math.random() * 255);
            int green = (int) (Math.random() * 255);
            int blue = (int) (Math.random() * 255);
            Color c1 = new Color(red, green, blue);
            g.setColor(c1);
            g.fillOval(x, y, 20, 20);
        }
    }

    class Animation extends Thread {

        private long start;

        @Override
        public void run() {
            start = System.currentTimeMillis();
            while (true) {
                if (!z) {
                    return;
                }
                double progress = (double) (System.currentTimeMillis() - start) / ANIMATION_DURATION;
                System.err.println(progress);
                if (incrementing) {
                    y = (int) (10 + 500 * progress);
                } else {
                    y = (int) (510 - 500 * progress);
                }
                if (progress > 1.0) {
                    start = System.currentTimeMillis();
                    incrementing = !incrementing;
                }

                panel.repaint();
                try {
                    Thread.sleep(1000 / REFRESH_RATE);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }
}

Upvotes: 0

Russell Zahniser
Russell Zahniser

Reputation: 16364

Calling repaint() does not actually paint the panel - it just marks it to be painted later. And painting always happens on the event dispatch thread, as do event listener notifications.

Since go() is being called on the event dispatch thread (by a button action listener), the panel cannot be repainted while go() is running. You simply queue up a single repaint that happens as soon as go() is done.

What you probably want to do is to use a javax.swing.Timer that fires once every 500 ms, and have its action be to move the ball one step and then call repaint().

Upvotes: 2

Related Questions