muco muco - 20 days ago 6
Java Question

how to show balls on screen in java swing

this is my board class and i try to call ball object in GameBoard class but i didn't and my problem is didn't show ball on screen.
Used to execute code after a given delay
The attribute is corePoolSize - the number of threads to keep in
the pool, even if they are idle

package test2;

public class Board extends JFrame{


public static int boardWidth = 800;
public static int boardHeight = 800;

public static void main(String[] args){
new Board();
}
public Board() {

this.setSize(boardWidth, boardHeight);
this.setTitle("Ball");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

GameBoard gb = new GameBoard();

this.add(gb, BorderLayout.CENTER);

ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(5);

executor.scheduleAtFixedRate(new RepaintTheBoard(this), 0L, 20L, TimeUnit.MILLISECONDS);

this.setVisible(true);
}

}

class RepaintTheBoard implements Runnable{

Board theBoard;

public RepaintTheBoard(Board theBoard){
this.theBoard = theBoard;
}

@Override
public void run() {

// Redraws the game board

theBoard.repaint();

}

}

@SuppressWarnings("serial")

//GameDrawingPanel is what we are drawing on

class GameBoard extends JComponent {

Random rnd=new Random();

public ArrayList<Ball> balls = new ArrayList<Ball>();

int width = Board.boardWidth;
int height = Board.boardHeight;

public GameBoard(){
for(int i=0; i<50; i++){

int randomStartXPos = (int) (Math.random() * (Board.boardWidth - 40) + 1);
int randomStartYPos = (int) (Math.random() * (Board.boardHeight - 40) + 1);

balls.add(new Ball(randomStartXPos,randomStartYPos,30));
}
}



public void paint(Graphics g) {


// Allows me to make many settings changes in regards to graphics

Graphics2D g2d = (Graphics2D)g;
g2d.setColor(Color.BLACK);
g2d.fillRect(0, 0, getWidth(), getHeight());



g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

g2d.setPaint(new Color(rnd.nextInt(255),rnd.nextInt(255),rnd.nextInt(255)));


for(Ball ball : balls){
ball.move();

g2d.draw(ball);

}



}

}


this ball class and i think , i have problem in move() class

package test2;

import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;

public class Ball extends Ellipse2D{

int uLeftXPos, uLeftYPos;

int xDirection = 1;
int yDirection = 1;

int diameter;
int width = Board.boardWidth;
int height = Board.boardHeight;

public Ball(int randomStartXPos, int randomStartYPos, int Diam) {
super();

this.xDirection = (int) (Math.random() * 4 + 1);

this.yDirection = (int) (Math.random() * 4 + 1);

// Holds the starting x & y position for the Rock

this.uLeftXPos = randomStartXPos;

this.uLeftYPos = randomStartYPos;
this.diameter = Diam;

}
public void move(){
if (uLeftXPos + xDirection < 0)
xDirection = 1;
if (uLeftXPos + xDirection > width - diameter)
xDirection = -1;
if (uLeftYPos + yDirection < 0)
yDirection = 1;
if (uLeftYPos + yDirection > height - diameter)
yDirection = -1;

uLeftXPos = uLeftXPos + xDirection;
uLeftYPos = uLeftYPos + yDirection;

}
@Override
public Rectangle2D getBounds2D() {
// TODO Auto-generated method stub
return null;
}
@Override
public double getX() {
// TODO Auto-generated method stub
return 0;
}
@Override
public double getY() {
// TODO Auto-generated method stub
return 0;
}
@Override
public double getWidth() {
// TODO Auto-generated method stub
return 0;
}
@Override
public double getHeight() {
// TODO Auto-generated method stub
return 0;
}
@Override
public boolean isEmpty() {
// TODO Auto-generated method stub
return false;
}
@Override
public void setFrame(double x, double y, double w, double h) {
// TODO Auto-generated method stub

}
}

Answer

Your main problem is that your Ball class extends a Shape object, Ellipse2D and does so incompletely, preventing full Ellipse2D/Shape behavior. I think that you'd be far better off not using inheritance but rather using composition -- have Ball contain a valid and complete Ellipse2D object, one that it uses to help it draw itself.

Other issues:

  • Your JComponent should have paintComponent overridden, not paint
  • You should always call the super's painting method within your override
  • It's not a good idea to have program logic within a painting method, as you can never fully control this method, nor do you want to. Better to have your move method separate and have the painting method do one thing -- paint the state of the component, and that's it.
  • Your code is skirting danger with Swing threading. Consider using a Swing Timer and not a scheduled executor service.
  • Start your GUI on the Swing thread using SwingUtilities.invokeLater(...)

  • Since your Ball object uses default overrides for most of the Ellipse2D methods, no movement will occur since its these method returns that determine the location of the Shape.

  • But again, you don't want to really override this object, but instead use composition.

Something like:

class Ball {
    private static final double ELLIPSE_W = 20;
    private static final double ELLIPSE_H = ELLIPSE_W;
    private int x = 0;
    private int y = 0;
    private Ellipse2D ellipse = new Ellipse2D.Double(x, y, ELLIPSE_W, ELLIPSE_H);
    int uLeftXPos, uLeftYPos;
    int xDirection = 1;
    int yDirection = 1;
    int diameter;
    int width = Board.boardWidth;
    int height = Board.boardHeight;

    public Ball(int randomStartXPos, int randomStartYPos, int Diam) {
        super();
        this.xDirection = (int) (Math.random() * 4 + 1);
        this.yDirection = (int) (Math.random() * 4 + 1);
        // Holds the starting x & y position for the Rock
        this.uLeftXPos = randomStartXPos;
        this.uLeftYPos = randomStartYPos;
        this.diameter = Diam;

        x = uLeftXPos;
        y = uLeftYPos;
        ellipse = new Ellipse2D.Double(x, y, ELLIPSE_W, ELLIPSE_H);
    }

    public Ellipse2D getEllipse() {
        return ellipse;
    }

    public void move() {
        if (uLeftXPos + xDirection < 0)
            xDirection = 1;
        if (uLeftXPos + xDirection > width - diameter)
            xDirection = -1;
        if (uLeftYPos + yDirection < 0)
            yDirection = 1;
        if (uLeftYPos + yDirection > height - diameter)
            yDirection = -1;
        uLeftXPos = uLeftXPos + xDirection;
        uLeftYPos = uLeftYPos + yDirection;
        x = uLeftXPos;
        y = uLeftYPos;
        ellipse = new Ellipse2D.Double(x, y, ELLIPSE_W, ELLIPSE_H);
    }
}

And in the game board:

class GameBoard extends JComponent {
    Random rnd = new Random();
    public ArrayList<Ball> balls = new ArrayList<Ball>();
    int width = Board.boardWidth;
    int height = Board.boardHeight;

    public GameBoard() {
        for (int i = 0; i < 50; i++) {
            int randomStartXPos = (int) (Math.random() * (Board.boardWidth - 40) + 1);
            int randomStartYPos = (int) (Math.random() * (Board.boardHeight - 40) + 1);
            balls.add(new Ball(randomStartXPos, randomStartYPos, 30));
        }
    }

    public void move() {
        for (Ball ball : balls) {
            ball.move();
        }
    }

    @Override
    protected void paintComponent(java.awt.Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;
        g2d.setColor(Color.BLACK);
        g2d.fillRect(0, 0, getWidth(), getHeight());
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setPaint(new Color(rnd.nextInt(255), rnd.nextInt(255), rnd.nextInt(255)));
        for (Ball ball : balls) {
            // ball.move();
            g2d.draw(ball.getEllipse());
        }
    }
}