OldSchool
OldSchool

Reputation: 2183

Timer of swing not performing as expected

I was suggested not to use sleep for pausing purpose and instead use swing timer but still its not working.The animation i want to achieve is a ball travelling from the top left corner diagonally towards the bottom.

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

class Show_starter {

    int x, y;
    JFrame window = new JFrame("Graphic_show");
    Graphic_panel jp = new Graphic_panel();

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

    private void go() {
        window.getContentPane().add(BorderLayout.CENTER, jp);
        window.setSize(600,800);
        window.setVisible(true);
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    class Graphic_panel extends JPanel {

        public void paintComponent(Graphics g) {

            for ( int i = 0; i < 100; ++i) {
                g.setColor(Color.white);
                g.fillRect(0, 0, this.getWidth(), this.getHeight());
                g.setColor(Color.green);
                g.fillOval(x, y, 40, 40);

                x++;
                y++;

                try {

                    Timer tmr = new Timer(1000, new TimerListener()); //This fires an event after every 1 sec after it has started by start().
                   //But The ball travels too much fast and stops at a point and again travels very fast.
                    tmr.serRepeats(false); // even this is not working.
                    tmr.start();
                    //should i use repaint here or in Listener for this timer?
                } catch (Exception e){}
            }
        }

        class TimerListener implements ActionListener {

            public void actionPerformed(ActionEvent e) {
                jp.repaint();
            }
        }
    }
}

The behaviour it is showing is very odd ball first goes at very high speed and stops momentarily at a point and again moves at same speed.

I have also tried to change the time for timer event to fire but the same thing happens.

Even inside loop where I have started timer the follow function call is not working

setRepeats(false);

Upvotes: 1

Views: 346

Answers (2)

Madhawa Priyashantha
Madhawa Priyashantha

Reputation: 9872

don't create new timers always one timer is enough .decrees timing interval bit more .1 second is too slow for a animation.you don't need a loop and don't increment x and y inside paintcomponet() method because this method get called for some reason for example when you resize,minimize,maximize.

the unexpected behavior is due to your loop and creating new timers(). for example in x y start at zero but in first second x y increased to 100,100 in next paint you see them in a 100,100 position .that's look like quick move and then stop ...

example code (edited)

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

public class Show_starter {

    private Timer tmr;

    int x, y;
    JFrame window = new JFrame("Graphic_show");
    Graphic_panel jp = new Graphic_panel();

    public static void main(String[] args) {

        Show_starter start = new Show_starter();
        start.go();

    }

    private void go() {

        window.getContentPane().add(BorderLayout.CENTER, jp);
        window.setSize(600, 800);
        window.setVisible(true);
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        tmr = new Timer(10, new ActionListener() { // time gap in millisecond

            @Override
            public void actionPerformed(ActionEvent ae) {

                jp.increse();
                jp.repaint();
            }
        });
        tmr.start();

    }

    class Graphic_panel extends JPanel {

        public void increse() {
            x++;
            y++;
            if (x > 100) { // stop animation at x>100
                tmr.stop();
            }
        }

        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);

        }

    }
}

output (smoother than that)

enter image description here

Upvotes: 2

Rahul
Rahul

Reputation: 299

Firstly you should not use a loop inside paint component.

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);
}

Just draw it and make x and y public in the class so that you can easily access from outside

Now run a runnable (consult invokelater and swingUtilities) or create a new Thread

inside public void run() do whatever animations you want to do . You can use a loop but add Thread.sleep(//in miliseconds) and repaint() in each iteration .

note : you need to change the x and y and repaint() so that it is drawn in a new position. And the sleep() is needed to slow down the execution otherwise it can't be visible to viewer.

Upvotes: 0

Related Questions