Question

I have a program that animates a ball in a Jpanel. I have two buttons Stop and Go. Stop stops the ball moving and go is meant for the ball to move around. In my ball class I have a boolean variable that if it is true the ball moves and if it is false the ball doesn't move. So I thought in my main class when I create the frame and put the ball class in the panel I could use the buttons to change the variable to false or true depending on the button press.

public class BallTask extends JPanel implements ActionListener{


public static boolean run = false;

public BallTask(){
    this.setPreferredSize(new Dimension(width, height));
    Thread gameThread = new Thread() {
        public void run() {
            while (run) {

             .... working code


public static void main(String[] args) {

    SwingUtilities.invokeLater(new Runnable() {
        public void run() {

            JFrame window = new JFrame();
            window.setLayout(new BorderLayout());
            window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            window.add(new BallTask());
            JPanel buttons = new JPanel();
            JButton stop = new JButton("STOP");
            stop.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    run = false;
                }
            });
            JButton go = new JButton("GO");
            go.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    run = true;
                }
            });
            buttons.add(go);
            buttons.add(stop);
            window.add(buttons,BorderLayout.SOUTH);
            window.pack();
            window.setVisible(true);
        }
    });

The problem I have with the code is that the buttons don't actually change the boolean value in the BallTask class. Any ideas?

Was it helpful?

Solution

Look into using a javax.swing.Timer. Your while loop will block the EDT not allowing the button events to be dispatched.

See How to use Swing Timers.

With the timer, you can just use it's methods stop and start to, well, start and stop the timer. You can see an example here


Here's a runnable example using a Timer with your code. The code in the link above is cleaner, using a Ball object. I just threw this one together really quick

import java.awt.BorderLayout;
import java.awt.Dimension;
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.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class BallTask {

    public static boolean run = false;
    private Timer timer;
    private BallPanel ballPanel = new BallPanel();

    public BallTask() {
        timer = new Timer(30, new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if (ballPanel.x < 0 || ballPanel.x > ballPanel.getWidth()) {
                    ballPanel.dx = -ballPanel.dx;
                }
                if (ballPanel.y < 0 || ballPanel.y > ballPanel.getHeight()) {
                    ballPanel.dy = -ballPanel.dy;
                }
                // Adjust ball position
                ballPanel.x += ballPanel.dx;
                ballPanel.y += ballPanel.dy;
                ballPanel.repaint();
            }
        });
        JPanel buttons = new JPanel();
        JButton stop = new JButton("STOP");
        buttons.add(stop);
        stop.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                timer.stop();
            }
        });
        JButton go = new JButton("GO");
        buttons.add(go);
        go.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                timer.start();
            }
        });

        JPanel mainPanel = new JPanel(new BorderLayout());
        mainPanel.add(ballPanel);
        mainPanel.add(buttons, BorderLayout.SOUTH);

        JFrame window = new JFrame();
        window.add(mainPanel);
        window.pack();
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        window.setLocationRelativeTo(null);
        window.setVisible(true);

    }

    private class BallPanel extends JPanel {

        private int x;
        private int y;
        int dx = 4; // Increment on ball's x-coordinate
        int dy = 4; // Increment on ball's y-coordinate
        int radius = 15; // Ball radius

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.fillOval(x, y, 30, 30);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(500, 300);
        }
    }

    public static void main(String[] args) {

        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new BallTask();
            }
        });
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top