I'm trying to make a GUI where it has essentially has multiple bouncing balls. The balls are added via a JButton. I was able to make the Ball class successfully and have it animate on the screen with only one ball, however I was not able to get multiple balls added via the use of the button. I have tried making an ActionListener which creates new threads and calls on SwingUtilities.InvokeLater, but it only made the GUI freeze. I have tried following this guide on how to use InvokeLater: http://www.javamex.com/tutorials/threads/invokelater.shtml
Here is my code so far. Any help is appreciated. (I realize that the bouncing ball question has been asked here before, but I was not able to understand the methods explained in the replies and thought I would ask here rather than comment on a 2 year old question)
Ball Class
package BouncingBall;
import javax.swing.*;
import java.awt.*;
import java.awt.geom.Ellipse2D;
import java.util.ArrayList;
import java.util.Random;
public class Ball extends JComponent
{
private double dx;
private double dy;
private double x;
private double y;
private Color color;
private Random rand = new Random();
private Ellipse2D.Double ball;
private final static int diam = 10;
private final static int xLim = BallFrame.FRAME_WIDTH-diam;
private final static int yLim = BallFrame.FRAME_HEIGHT-diam*7;
boolean xUpperBound = true;
boolean yUpperBound = true;
public Ball()
{
color = new Color(rand.nextFloat(),rand.nextFloat(),rand.nextFloat());
x = rand.nextInt(xLim);
y = rand.nextInt(yLim);
dx = rand.nextInt(9)+1;
dy = rand.nextInt(9)+1;
}
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
draw(g2);
}
public void draw(Graphics2D g2)
{
ball = new Ellipse2D.Double(x,y,diam,diam);
g2.setColor(color);
g2.fill(ball);
}
public void move()
{
if (((x+dx) < xLim) && xUpperBound)
x+=dx;
else if (x > 0)
{
xUpperBound = false;
x-=dx;
}
else
xUpperBound = true;
if (((y+dy) < yLim) && yUpperBound)
y+=dy;
else if (y > 0)
{
yUpperBound = false;
y-=dy;
}
else
yUpperBound = true;
}
public void animate()
{
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
try
{
while (true)
{
repaint();
move();
Thread.sleep(40);
}
}
catch (InterruptedException e)
{
System.out.println("Thread was interrupted!");
}
}
});
}
}
BallFrame Class
package BouncingBall;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
public class BallFrame extends JFrame
{
public final static int FRAME_WIDTH = 800;
public final static int FRAME_HEIGHT = 600;
public BallFrame()
{
class ballListener implements ActionListener
{
@Override
public void actionPerformed(ActionEvent actionEvent)
{
Thread thread = new Thread()
{
public void run()
{
Ball temp = new Ball();
temp.animate();
add(temp);
}
};
thread.start();
}
}
setLayout(new BorderLayout());
JButton addBall = new JButton("Add Ball");
ActionListener listener = new ballListener();
addBall.addActionListener(listener);
add(addBall, BorderLayout.SOUTH);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
BallFrame frame = new BallFrame();
frame.setSize(FRAME_WIDTH, FRAME_HEIGHT );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.setVisible( true );
}
});
}
}