user3389836
user3389836

Reputation: 53

Timers and actionPerformed in java

So all i'm trying to do is make a ball bounce around a window, but for some reason, while no red flags are raised on eclipse, when i run it, it just displays a static ball.

This is what i got so far:

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

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

public class Pong extends JPanel implements ActionListener {
    int x=600, y=250, vx=5, vy=5;
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Pong p = new Pong();
        JFrame f = new JFrame();
        f.setSize(1400, 700);
        f.add(p);
        f.setVisible(true);
        Timer t = new Timer(100, p);
        t.start();  
        t.addActionListener(p);
    }

    public void paintComponent(Graphics b){
        b.fillOval(x,y, 50, 50);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if(y>700||y<0) {
            vy=-vy;
        }
        if(x>1400||x<0) {
            vx=-vx;
        }
        y=y+vy;
        x=x+vx;
    }
}

Upvotes: 2

Views: 2962

Answers (4)

matt forsythe
matt forsythe

Reputation: 3912

You need to add a call to repaint() at the end of actionPerformed. Note that this will lead to other painting problems (the ball just gets smeared across the screen) because you also need to call super.paintComponent(b); as the first thing in your paintComponent method.

Also there is no need to call t.addActionListener(p), as the ActionListener has already been added by the call to new Timer(100, p). Since the ActionListener is now actually added twice, actionPerformed gets called twice per timer pop and your ball moves two times faster than you intended.

Note also that as you currently have it, the process will never end until it is killed. You need to make sure you dispose of your JFrame:

f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

and shutdown your Timer:

final Timer t = new Timer(100, p);  // need to make this final to avoid compile error
f.addWindowListener(new WindowAdapter() {
    @Override
    public void windowClosed(WindowEvent e) {
        t.stop();
    }
});

I noticed that I had a bunch of "Pong" processes still running after testing your code. :)

Upvotes: 3

Faran Yahya
Faran Yahya

Reputation: 238

You should call repaint after you modify a location. for example

   public void actionPerformed(ActionEvent e) {
        if(y>700||y<0) {
             vy=-vy;
             repaint();
          }...

Upvotes: 0

T-Bull
T-Bull

Reputation: 2146

You need to call repaint on the JPanel or it will not have any reason to repaint itself.

public void actionPerformed(ActionEvent e) { 
    ...

    this.repaint(this.getVisibleRect());
}

(untested)

Upvotes: 0

JB Nizet
JB Nizet

Reputation: 691645

The timer must ask the panel to repaint itself:

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

Upvotes: 4

Related Questions