Reputation: 63
I've made 20 objects from my Ball class, as I need 20 balls bouncing around on the screen, but right now it only shows 1 ball bouncing around. I think it has something to do with 20 JPanels being added and they are overlapping each other, but I'm not entirely sure.
package com.company;
import javax.swing.*;
import java.awt.*;
import java.util.Random;
/**
* Created by John on 25/02/2015.
*/
public class Ball extends JComponent{
int _speedX;
int _speedY;
int _size;
int _x;
int _y;
Color _color;
int _windowX;
int _windowY;
Ball(int x, int y, int sz, int sX, int sY, Color c, int windowX, int windowY){
_x = x;
_y = y;
_speedX = sX;
_speedY = sY;
_size = sz;
_color = c;
_windowX = windowX;
_windowY = windowY;
setForeground(_color);
}
public void update(){
_x = _x + _speedX;
_y = _y + _speedY;
if (_x<0 || _x>_windowX-_size){
_speedX*=-1;
}
if (_y<=0 || _y>_windowY-_size){
_speedY*=-1;
}
this.repaint();
}
public static int randInt(int min, int max) {
// NOTE: Usually this should be a field rather than a method
// variable so that it is not re-seeded every call.
Random rand = new Random();
// nextInt is normally exclusive of the top value,
// so add 1 to make it inclusive
int randomNum = rand.nextInt((max - min) + 1) + min;
return randomNum;
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.fillOval(_x, _y, _size, _size);
}
public static void main(String[] args) {
// write your code here
JFrame frame = new JFrame("Title"); //create a new window and set title on window
frame.setSize(600, 600); //set size of window
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //set the window to close when the cross in the corner is pressed
frame.setVisible(true); //make the window visible
JPanel panel = new JPanel();
frame.add(panel);
Ball[] balls = new Ball[20];
for(int i = 0; i<20;i++){
balls[i] = new Ball(randInt(0,600),randInt(0,600),randInt(10,20),randInt(1,8), randInt(1,8),Color.yellow,600,600);
panel.add(balls[i]);
}
while(true){
for(int i = 0; i < balls.length; i++) {
balls[i].update();
}
panel.repaint();
try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); }
}
}
}
Upvotes: 0
Views: 521
Reputation: 324147
it only shows 1 ball bouncing around.
I'm surprised you even see one. You shouldn't see any.
I think it has something to do with 20 JPanels being added and they are overlapping each other,
The problem is that by default a JPanel uses a FlowLayout. When you add a component to the panel the panel will respect the preferred size of the component. You are using a custom component and the default size is (0, 0) since you didn't provide one.
If you want to continue this approach by using a custom component then you need to:
use the properties of the component to control the size and location of the component on the panel. That is you can use the setSize(...)
method and setLocation(...)
method. You don't need your _x, _y and _size variables. You also don't need the color variable because you can use setForeground(...)
to set the color of your component.
Override the getPreferredSize()
method to return the size of the ball.
Override the 'paintComponent(...)` method to fill the oval with an x/y value of 0, since the painting needs to be done relative to the ball, not the panel.
In the update()
method you use the setLocation(...)
method to set the location of the component on the panel.
Now you also need to use a null layout on your panel so the balls can move randomly.
I don't recommend this approach for your final solution, but it is a good exercise to implement this logic to understand how you might go about creating a custom component and how painting is done on this component. Understanding this concept will help you better understand how Swing works in general.
Upvotes: 2
Reputation: 285405
Suggestions:
paintComponent
method, not its paint(...)
method. This will lead to smoother animation.ArrayList<Ball>
of your Ball objects and draw them inside of the paintComponent(...)
method override by iterating through the list.while (true)
loop. If you make one mistake with that loop, you'll freeze your GUI rendering it non-functioning, and so the Swing Timer is a much safer way to do this.Upvotes: 3