0

I do realize there is another topic very similar to my question here

Differs from here due to the method of adding balls to the panel (not content Panes)

However the issue addressed in that topic doesn't really answer my question and explain why the problem I'm having is occuring

I'm trying to create a very simple program that can create multiple balls which can bounce independently and do not interact with eachother however whenever I create one ball successfully the next attempted implementation is overwritten and the previous ball is not shown

I believe that a possible cause to this is due to the layout and how adding a multiple balls is not possible on a default Center layout

I saw some suggestions and examples using lists and/or a null layout and after attempting some of these none worked

The program consists of two classes one "GUI" for creating the window and adding the balls and the "Ball" class which is the ball itself

Here is the GUI class

import javax.swing.JFrame;
import java.awt.*;
public class Gui extends JFrame{
    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLayout(new BorderLayout());
        frame.add(new Ball());
        frame.add(new Ball(200,200,8,8,25,25)); //This overwrites above line
        frame.setSize(500,400);
        frame.setVisible(true);
    }
}

Here is the ball class

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Ellipse2D;
public class Ball extends JPanel implements ActionListener{
    Timer timer = new Timer(10,this);
    double x_coord = 250, y_coord = 250, x_vector = 5, y_vector = 5, x_size = 50, y_size = 50;
    public Ball(double x_c, double y_c, double x_v, double y_v, double x_s, double y_s){
        x_coord = x_c;
        y_coord = y_c;
        x_vector = x_v;
        y_vector = y_v;
        x_size = x_s;
        y_size = y_s;
        timer.start();
        setFocusable(true);
    }
    public Ball(){
        timer.start();
        setFocusable(true);
    }
    public void paintComponent(Graphics g){
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;
        Rectangle rect = g2d.getClipBounds();
        rect.x = (int) x_coord;
        rect.y = (int) y_coord;
        g2d.fill(new Ellipse2D.Double(rect.getX(), rect.getY(), x_size, y_size));
        if(rect.getY() < 0 || rect.getY() > (getHeight()-y_size)){
            y_vector *= -1;
        }else if(rect.getX() < 0 || rect.getX() > (getWidth()-x_size)){
            x_vector *= -1;
        }
    }
    public void actionPerformed(ActionEvent e) {
        repaint();
        x_coord += x_vector;
        y_coord += y_vector;
    }
}

I would very much appreciate a well explaining answer since I still am quite green with JPanel and JFrame, Thanks!

Community
  • 1
  • 1
Matt B
  • 52
  • 5
  • 1
    I don't know that I would make the ball the panel. Nor would I put the timer there. Put the timer in the "controller" which would create a new ball, add it to a container of balls, then redraw from the list. – ChiefTwoPencils Feb 03 '16 at 20:25
  • So I should try to make one single panel and then make a new class that would add new balls to the existing single panel? – Matt B Feb 03 '16 at 20:31
  • I'd say so; think of the balls as shapes not panels. I'd have the `Ball` class implement a `Drawable` `interface` with a `draw` method. Have your panel do `list.forEach(b -> b.draw(g));` upon being triggered by the timer. The timer would also trigger the position changes. – ChiefTwoPencils Feb 03 '16 at 20:39
  • 1
    Don't use component based objects, the layout manager is controlling the placement of the components. A better solution would be to use a single component and use a "painter" concept which would allow to externalise how something is painted (the individual balls) – MadProgrammer Feb 03 '16 at 20:41
  • 2
    Which is discusses and demonstrated [here](http://stackoverflow.com/questions/13022754/java-bouncing-ball/13022788#13022788) – MadProgrammer Feb 03 '16 at 20:45

1 Answers1

-1

I tried the controller concept suggested by a comment and the idea of a "painter" concept, and just overall cleaned up the code

Also fixed the ball phasing through the window when hitting a corner

Although I would call the case closed but I don't think forcing myself to have one JPanel creator (Ball Creator) is a very good idea when thinking of implementing different types of objects/drawings

Gui Class

import javax.swing.*;
import java.awt.*;
public class Gui extends JFrame{
    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLayout(new BorderLayout());
        frame.setSize(500,400);
        System.out.println();
        BallCreator creator = new BallCreator();
        frame.add(creator);
        frame.setVisible(true);
    }
}

New Ball Creator Class

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class BallCreator extends JPanel implements ActionListener{
    Timer timer = new Timer(10, this);
    Ball2 ball = new Ball2();
    Ball2 ball2 = new Ball2(100,100,-7,7,40,40);
    Ball2 ball3 = new Ball2(50,50,6,-6,60,60);
    public BallCreator(){
        timer.start();
    }
    public void paint(Graphics g){
        super.paint(g);
        ball.paint(g);
        ball2.paint(g);
        ball3.paint(g);
    }
    public void actionPerformed(ActionEvent e){
        repaint();
    }
}

Ball Class

import javax.swing.*;
import java.awt.*;
import java.awt.geom.Ellipse2D;
public class Ball2 extends JPanel{
    double x_coord = 250, y_coord = 250, x_vector = 5, y_vector = 5, x_size = 50, y_size = 50;
    public Ball2(double x_c, double y_c, double x_v, double y_v, double x_s, double y_s){
        x_coord = x_c;
        y_coord = y_c;
        x_vector = x_v;
        y_vector = y_v;
        x_size = x_s;
        y_size = y_s;
    }
    public Ball2(){
    }
    public void paint(Graphics g){
        super.paint(g);
        Graphics2D g2d = (Graphics2D) g;
        Rectangle rect = g2d.getClipBounds();
        rect.x = (int) x_coord;
        rect.y = (int) y_coord;
        g2d.fill(new Ellipse2D.Double(rect.getX(), rect.getY(), x_size, y_size));
        if (rect.getX() >= (484-x_size-3) && x_vector > 0){
            x_vector *= -1;
        }
        if (rect.getX() <= 0 && x_vector < 0){
            x_vector *= -1;
        }
        if (rect.getY() >= (361-y_size-4) && y_vector > 0){
            y_vector *= -1;
        }
        if (rect.getY() <= 0 && y_vector < 0){
            y_vector *= -1;
        }
        y_coord += y_vector;
        x_coord += x_vector;
    }
}
Matt B
  • 52
  • 5
  • I book marked this question and just now got back around to it. Please take a look at my answer and see if you'll be convinced about my controller suggestion. – ChiefTwoPencils Feb 22 '16 at 02:13