I'm a beginner to Java 2D graphics, currently learning.
I have a class Surface, extending JPanel, that's overriding paintComponent method. It's where the program is supposed to draw things. An instance of Surface was added to a different class that extends JFrame. This class is called Main, it also included the main method.
I'm trying to do that Surface will call a method in the class DrawRect, and that method will create a rectangle in Surface, from the outside.
Here are my attempts:
// Class Main
package m;
import java.util.*;
import java.awt.*;
import java.awt.Event.*;
import javax.swing.*;
public class Main extends JFrame {
public static void main(String[] args) {
Main m = new Main();
}
public Main(){
setDefaultCloseOperation(EXIT_ON_CLOSE);
setTitle("Bla");
setSize(500,500);
add(new Surface());
setVisible(true);
}
}
// Class Surface
package m;
import java.util.*;
import java.awt.*;
import java.awt.Event.*;
import javax.swing.*;
public class Surface extends JPanel {
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
// What to do here?
}
}
package m;
import java.util.*;
import java.awt.*;
import java.awt.Event.*;
import javax.swing.*;
// Class DrawRect
public class DrawRect {
String color;
Surface surface;
public DrawRect(String color, Surface surface){
this.color = color;
this.surface = surface;
}
}
In other words, how can an exterior class draw something in another class? Thanks
One paint surface is one paint surface. You don't combine then. Even if you were to try and overlap them, you'd still be painting on one surface.
If you want to use a data model for another shape you could do something like this
public class MyRetangle{
int x = 10;
int y = 10;
int width = 100;
int height = 100;
Color color = Color.RED;
}
public class Surface extends JPanel {
MyRectangle rect = new MyRectangle(); // create an instance of your other class
protected void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setColor(rect.color); // use data from rect
g2.draw(new Rectangle.Double(rect.x, rect.y, rect.width, rect.height));
}
}
This is just an example. I don't know why you would ever do this, but you can see how to use data from another class as drawing data
Edit: to fit more towards your code
public class DrawRect{
int y;
int y;
int height;
int width;
Color color;
public DrawRect(int x, int y, int width, int height, Color color) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.color = color;
}
}
public class Surface extends JPanel {
protected void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
DrawRect rect = new DrawRect(20, 20, 100, 100, Color.RED);
g2.setColor(rect.color);
g2.draw(new Rectangle.Double(rect.x, rect.y, rect.width, rect.height));
}
}
Related
I'm trying to have an ArrayList of Ball objects, and I want to draw them to the screen, but only one of them gets drawn and I don't know why.
Ball class:
import javax.swing.*;
import java.awt.*;
import java.awt.geom.Ellipse2D;
import java.util.Random;
public class Ball extends JPanel{
int sX,sY;
Color color;
int speed;
int height;
int width;
int velX=0;
int velY=0;
Random randInt;
JFrame window;
public Ball(int sX,int sY,int height,int width){
this.sX=sX;
this.sY=sY;
this.color=color;
this.speed=speed;
this.height=height;
this.width=width;
}
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2d=(Graphics2D)g;
g2d.setColor(color.RED);
Ellipse2D ellipse = new Ellipse2D.Double(sX,sY,width,height);
g2d.fill(ellipse);
}
public String getCoords(){
return "X: "+String.valueOf(sX)+" Y: "+String.valueOf(sY);
}
}
BallManager class (where it stores the arraylist of ball objects)
import javax.swing.*;
import java.util.ArrayList;
public class BallManager {
ArrayList<Ball> listOfBalls;
int width,height;
JFrame window;
Ball newBall;
public BallManager(JFrame window) {
this.listOfBalls=new ArrayList<Ball>();
this.window=window;
this.addBalls(100);
//this.drawBalls();
}
public void addBalls(int n){
for (int y=0;y<n;y+=20){
for(int x=0;x<n;x+=20){
this.listOfBalls.add(new Ball(x,y,10,10));
drawBalls();
}
}
System.out.println(listOfBalls.size());
}
public void drawBalls(){
for(Ball b:listOfBalls){
window.add(b);
System.out.println(b.getCoords());
}
}
}
Main class:
public class Main {
public static void main(String[] args){
JFrameWindow j= new JFrameWindow(300,500);
BallManager bm=new BallManager(j);
}
}
Window Class:
import javax.swing.*;
import java.awt.*;
public class JFrameWindow extends JFrame {
int width;
int height;
public JFrameWindow(int width,int height){
super("JFrame ballssssss");
this.width=width;
this.height=height;
this.setLocationRelativeTo(null);
this.setSize(this.width,this.height);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setResizable(false);
this.setVisible(true);
this.getContentPane().setBackground(Color.orange);
}
}
I have no clue what the problem is. It seems to me that the balls in the arraylist move in unison with each other but I don't know why.
You've got some things a little backwards:
The Ball class should not extend from JPanel nor any other Swing component. Instead it should be a logical class, one that knows the location, color of a ball and how to draw it, in a method, say public void draw(Graphics g).
There should be only one JPanel that holds the logical Balls in an ArrayList<Ball>, and draws them all within its paintComponent method via a for-loop.
This single JPanel should be added to the JFrame, BorderLayout.CENTER.
e.g.,
public class Ball {
private static final int RADIUS = 5;
private int x;
private int y;
private Color color;
// constructors
// getters / setters
// methods to move the ball
// or might use Graphics2D and rendering hints to smooth drawing
public void draw(Graphics g) {
g.setColor(color);
g.fillOval(x - RADIUS, y - RADIUS, 2 * RADIUS, 2 * RADIUS);
}
}
and
class BallPanel extends JPanel {
private List<Ball> balls = new ArrayList<>();
// constructor -- fill the balls list
// other methods....
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Ball ball : balls) {
ball.draw(g);
}
}
}
I am trying to learn the paint method and get a ball to move across the frame. here is my code so far. w=.
I currently have two classes One is the main and one for the ball.
this is the main class
import java.awt.;
import javax.swing.;
public class PaintTest extends JPanel {
int x = 0;
int y = 0;
public void moveBall(){
x = x + 1;
y = y + 1;
}
public static void main(String[] args){
JFrame frame = new JFrame();
frame.setSize(500,500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
Ball ball = new Ball(x,y);
while(true){
ball.moveBall();
repaint();
}
}
protected void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g.setColor(Color.magenta);
g.drawLine(0,100,500,100);
g.drawLine(0,101,500,101);
g.drawLine(0,102,500,102);
g.drawLine(0,103,500,103);
g2.fillOval(x,y,35,35);
}
}
and here is the ball class
public class Ball {
int x,y;
public Ball(int x, int y){
this.x = x;
this.y = y;
}
}
now when i compile I get an error saying cannot find symbol ball in class PaintTest even though I am calling it from the class Ball. I am aware of the repaint error as i do not know what to put in front of it.
Draw in a JPanel
In its paintComponent method not in its paint method -- this gives you double buffering.
Call the super's paintComponent method in your override. This allows the JPanel to do housekeeping drawing including erasing the oval image at its old position.
Don't use a while (true) loop as this can cause serious Swing threading issues. Use a Swing Timer instead.
In the Swing Timer, increment your animation variables and then call repaint(). This will tell Swing to repaint the component which will re-draw the oval in the new location.
Don't guess at this stuff as that leads to frustration since Swing graphics coding is a different beast. Instead check the tutorials. You can find links to the Swing tutorials and to other Swing resources here: Swing Info. Also check out Performing Custom Painting with Swing.
Graphics2D goodies: RenderingHints can be used to smooth out your image jaggies.
More Graphics2D goodies: Stroke can be used to draw thicker lines when needed.
For example:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
#SuppressWarnings("serial")
public class PaintTest extends JPanel {
private static final int PREF_W = 600;
private static final int PREF_H = PREF_W;
private static final int TIMER_DELAY = 20;
private static final Stroke STROKE = new BasicStroke(5f);
private int x;
private int y;
public PaintTest() {
new Timer(TIMER_DELAY, new TimerListener()).start();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
// to smooth graphics
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(Color.magenta);
Stroke initialStroke = g2.getStroke();
g2.setStroke(STROKE);
g.drawLine(0, 100, 500, 100);
g2.setStroke(initialStroke);
g2.fillOval(x, y, 35, 35);
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
x++;
y++;
repaint();
}
}
private static void createAndShowGui() {
PaintTest mainPanel = new PaintTest();
JFrame frame = new JFrame("PaintTest");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
You have to put the paintComponent method in a JPanel. You can do it by using something like this.
JPanel panel = new JPanel(){
#Overide
public void paintComponent(Graphics g){
super.paint();
// Draw Stuff Here
}
};
The reason you are not getting the ball to move across the frame is that you are not calling the repaint method. You should do so on a thread.
Thread th = new Thread(new Runnable(){
#Overide
public void run(){
while(frame.isVisible()){
ball.moveBall();
panel.repaint();
try{Thread.sleep(5);}catch(Exception e){e.printStackTrace();}
}
}
});
Also, why are you making ball a instance of the PaintTest class? To get only one frame and ball you would want to add a class named Ball and use that to make an instance:
public class Ball{
int x, y;
public Ball(int x, int y){
this.x = x;
this.y = y;
}
}
That is why you were getting 2 frames.
Then you would want to get rid of the x and y variables in the main class. To make an instance using this class you would do:
Ball ball = new Ball(x, y);
Then to paint the ball in the paintComponent method you would do:
g.fillOval(ball.x, ball.y, 35, 35);
You didn't call the repaint(); method.
You don't need the y + 1 part.
Instead of using the while(true) loop, you should use a for loop.
You didn't call the super.paint() method.
You didn't use any Thread.sleep(), which made the ball move across instantaneously.
Here is the code:
import java.awt.*;
import javax.swing.*;
public class PaintTest extends JFrame {
int x = 8;
int y = 30;
public void moveBall(){
x = x + 1;
//y = y + 1;
try{
Thread.sleep(500);
} catch(InterruptedException e){
}
repaint();
}
public static void main(String[] args){
PaintTest frame1 = new PaintTest();
PaintTest ball = new PaintTest();
for(int i = 0; i<100; i++){
//while(true){
ball.moveBall();
}
}
public PaintTest() {
super("Paint Test");
setSize(500,500);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
public void paint(Graphics g){
Graphics2D g2 = (Graphics2D) g;
super.paint(g);
super.paint(g2);
g.setColor(Color.magenta);
g.drawLine(0,100,500,100);
g.drawLine(0,101,500,101);
g.drawLine(0,102,500,102);
g.drawLine(0,103,500,103);
g.fillOval(x,y,35,35);
}
}
This code will make the ball move across the screen VERY slowly. If you want to speed it up, change the number of miliseconds in the Thread.sleep(miliseconds) part to a smaller number of miliseconds.
I'm making a Java game. I have a Board class which extends JPanel, and have painted a node jim, which is an object instance of Ball class, to the screen using the paintComponent(Graphics g) {. I can move the Ball object around on the JPanel using arrow keys.
Instead of representing the Ball object as a red square, I would like to have an image loaded.
Board class extends JPanel:
jim = new Ball(0, 0, 50, 50, "jim");
Ball class:
public class Ball extends Component {
int x, y, w, h;
BufferedImage jimImg;
public Ball(int xLoc, int yLoc, int width, int height, String imgtype) throws IOException {
x = xLoc;
y = yLoc;
w = width;
h = height;
jimImg = ImageIO.read(new File("resources/Jim.png"));
loadImages(imgtype);
}
public void paint(Graphics g) {
g.drawImage(jimImg, 200, 0, null);
}
It's not drawing on top of the red square though, or even appearing at all.
I have also tried appending the image as a JLabel... here's code within the Ball class:
public void loadImages(String imgType) throws IOException {
if (imgType == "jim") {
JLabel utc = new JLabel("test");
ImageIcon utcImg = new ImageIcon("resources/Miller.png");
utc.setIcon(utcImg);
}
}
But since Ball class is not a JPanel, I can't add the label to the object.
Don't compare Strings with ==, use equals
if (imgType == "jim") ==>> if ("jim".eqauls(imgType))
You should be reading from a URL and not a File object. A URL can be obtained by using getClass().getResource(). e.g.
jimImg = ImageIO.read(
Ball.class.getResource("/resources/Jim.png"));
You should use a try/catch in the constructor, so you won't have to later when you instantiate the Ball
It's preffered to paint on JPanel and override its paintCompoent, or JComponet
You never actually use the variable taken from your constructor to use to paint`
g.drawImage(jimImg, x, y, w, h, this);
When working with painting, you should override the getPreferredSize of the JPanel so the frame will size it accordingly.
Here's a running example that works. Keep in mind my file structure look like
ProjectRoot/src/resources/image.png
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Ball extends JPanel {
int x, y, w, h;
BufferedImage jimImg;
public Ball(int xLoc, int yLoc, int width, int height) {
x = xLoc;
y = yLoc;
w = width;
h = height;
try {
jimImg = ImageIO.read(
Ball.class.getResource("/resources/stackoverflow5.png"));
System.out.println(jimImg);
} catch (IOException ex) {
ex.printStackTrace();
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(jimImg, x, y, w, h, this);
}
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame();
frame.add(new Ball(50, 50, 100, 100));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
});
}
}
EDIT in response to OP commment
"the way my classes are structured: Main class adds JFrame, where I add a new Board class object to the JFrame (Board class extends JPanel). Then I have Board class extends JPanel, which adds a new Ball object and has keyboard methods, etc... so I can move the Ball around. Then Ball Class is just a node with get/set methods getX(), setX() etc. So I can't add an image to the Ball class without extending JPanel?"
It doesn't look like you need ball to be a Component at all. Instead of making the ball a compoent, just make it a regular class. And in the paintComponent of your Board JPanel, just call ball.paint() for each ball you have.
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Board extends JPanel {
Ball ball = new Ball(50, 50, 200, 200);
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
ball.drawBall(g);
}
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame();
frame.add(new Board());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
});
}
}
class Ball {
int x, y, w, h;
BufferedImage jimImg;
public Ball(int xLoc, int yLoc, int width, int height) {
x = xLoc;
y = yLoc;
w = width;
h = height;
try {
jimImg = ImageIO.read(
Board.class.getResource("/resources/stackoverflow5.png"));
System.out.println(jimImg);
} catch (IOException ex) {
ex.printStackTrace();
}
}
public void drawBall(Graphics g) {
g.drawImage(jimImg, x, y, w, h, null);
}
}
I'm having difficulty with drawing Shapes (Circle & Rectangle) into a Frame.
I have created both a Circle and a Rectangle Class that implements the Shape Interface. I have then created DrawableCircle and DrawableRectangle Classes that extend the Circle and Rectangle Classes appropriately, and implement the Drawable Interface.
I am now trying to create a ShapesDriver Class which extends Frame and has within it the main method and paint(Graphics g) method. Within ShapesDriver I need to create an ArrayList of type Drawable. This ArrayList holds an instance of DrawableCircle and DrawableRectangle. In the paint method I have to iterate through the ArrayList and invoke the draw method for each shape.
This is where I am stuck...
Any help would be appreciated!
Shape Interface
public interface Shape {
public double area();
}
Circle Class
public class Circle implements Shape{
private int radius;
private double area;
public Circle(int r){
radius = r;
}
#Override
public double area() {
area = Math.PI * (radius * radius);
return area;
}
}
Rectangle Class
public class Rectangle implements Shape{
double height;
double width;
double area;
public Rectangle(double h, double w){
height = h;
width = w;
}
#Override
public double area() {
area = height * width;
return area;
}
}
Drawable Interface
import java.awt.Color;
import java.awt.Graphics;
public interface DrawableInterface {
public void setColor(Color c);
public void setPosition(int x, int y);
public void draw(Graphics g);
}
DrawableCircle
import java.awt.Color;
import java.awt.Graphics;
public class DrawableCircle extends Circle implements DrawableInterface{
private Color col;
private int posX;
private int posY;
public DrawableCircle(int r){
super(r);
}
#Override
public void setColor(Color c) {
col = c;
}
#Override
public void setPosition(int x, int y) {
posX = x;
posY = y;
}
#Override
public void draw(Graphics g) {
g.setColor(col);
g.drawOval(posX, posY, 15, 15);
}
}
DrawableRectangle
import java.awt.Color;
import java.awt.Graphics;
public class DrawableRectangle extends Rectangle implements DrawableInterface{
private Color col;
private int posX;
private int posY;
public DrawableRectangle(double h, double w){
super(h, w);
}
#Override
public void setColor(Color c) {
col = c;
}
#Override
public void setPosition(int x, int y) {
posX = x;
posY = y;
}
#Override
public void draw(Graphics g) {
g.setColor(col);
g.drawRect(posX,posY,10,10);
}
}
ShapesDriver
import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
public class ShapesDriver extends Frame {
static ArrayList<DrawableInterface> shapesArr = new ArrayList<DrawableInterface>();
public ShapesDriver() {
super("Shapes Object Array");
setSize(400, 300);
setLocation(200, 200);
setVisible(true);
}
public static void main(String[] args) {
DrawableCircle c = new DrawableCircle(500);
c.setColor(Color.GREEN);
c.setPosition(25, 25);
DrawableRectangle r = new DrawableRectangle(100, 50);
r.setColor(Color.RED);
r.setPosition(75, 75);
shapesArr.add(c);
shapesArr.add(r);
ShapesDriver shapeFrame = new ShapesDriver();
shapeFrame.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
#Override
public void paint(Graphics g) {
for (DrawableInterface s : shapesArr) {
super.paint(g);
s.draw(g);
}
}
}
"This is where I am stuck..." -- where are you stuck exactly?
Myself, I would:
use a Swing GUI not an AWT GUI since Swing is much more powerful and flexible than AWT. There's almost never a need to create AWT GUI's.
Your GUI class, ShapesDriver does nothing. It extends Frame, but you never create an instance of the ShapesDriver. Instead it has a main method where you create a separate Frame. In my GUI code, I'd create a true GUI class, that had instance fields and methods, and would be sure to create an instance of this class somewhere.
In my GUI class I'd have my ArrayList of Shape and my drawing method, and would loop through the ArrayList within the drawing method, drawing each shape as I looped.
Since I would favor using Swing, my GUI class would extend JPanel, and my drawing method would be a paintComponent(Graphics g) method. If you're required to use AWT, then you could instead use a Panel and draw in its paint(Graphics g) method.
I'd then have a main method that creates the GUI, makes it visible, and does nothing else.
I am trying to use Java2D to do some simple graphics programming. I've started easy, just trying to display a couple of circles in a JFrame. I was successful displaying a single circle, but when adding a second circle, only the last circle added to the JFrame is displayed. I use class Circle to define my circle and to override the paintComponent method used to display it. Any suggestions on what I might be doing wrong would be greatly appreciated. Code for my classes Circle and DancingCircles is provided below for reference.
import java.awt.*;
import javax.swing.*;
import java.awt.geom.*;
/**
*
* #author Paul
*/
public class Circle extends JPanel {
// Data members for Circle center and radius
private double centerX, centerY;
private double radius;
// No-argument constructor
Circle() {
centerX = 200;
centerY = 200;
radius = 10;
}
// Full-argument constructor
Circle( double x, double y, double r) {
centerX = x;
centerY = y;
radius = r;
}
// Draw a Circle
protected void paintComponent(Graphics g) {
super.paintComponent(g);
//Convert to Java2D Object
Graphics2D g2 = (Graphics2D) g;
// Create the circle
Ellipse2D circle = new Ellipse2D.Double();
circle.setFrameFromCenter(centerX, centerY, centerX + radius, centerY + radius);
// Draw it
g2.draw(circle);
}// end paintComponent
// Get/set data members
public void setCenterX(double x){this.centerX = x;}
public void setCenterY(double y){this.centerY = y;}
public void setRadius(double r){radius = r;}
public double getCenterX(){return centerX;}
public double getCenterY(){return centerY;}
public double getRadius(){return radius;}
}// end class Circle
import java.awt.*;
import javax.swing.*;
/**
*
* #author Paul
*/
public class DancingCircles extends JFrame{
// Display Dimensions
public static final int DEFAULT_WIDTH = 400;
public static final int DEFAULT_HEIGHT = 400;
// Default constructor
private DancingCircles() {
setTitle("Dancing Circles");
setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
// Add Circles to JFrame
Circle myCircle = new Circle(200.0, 200.0, 20.0);
add(myCircle); // Add circle to frame
Circle myCircle2 = new Circle(100.0, 100.0, 30.0);
add(myCircle2); // Add circle to frame
}// end DancingCircles
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable()
{
public void run()
{
DancingCircles dc = new DancingCircles();
dc.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
dc.setVisible(true);
}
});
}// end main
}
Thanks!
Paul
The way to do this is to remove the drawing methods from the circle class and create a single panel with multiple circles on it instead:
import java.awt.*;
import javax.swing.*;
import java.awt.geom.*;
import java.util.*;
public class Circles extends JPanel
{
ArrayList<Circle> circles = new ArrayList<Circle>();
public void add(Circle circle) {
circles.add(circle);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
for (Circle circle: circles) {
Ellipse2D circle2D = new Ellipse2D.Double();
circle2D.setFrameFromCenter(
circle.getCenterX(),
circle.getCenterY(),
circle.getCenterX() + circle.getRadius(),
circle.getCenterY() + circle.getRadius());
g2.draw(circle2D);
}
}
}
You are implementing each Circle as a JPanel. With the default LayoutManager of BorderLayout, the JFrame can only hold a single Component at a time when called with add(circle). When you add the second Circle, the first is removed.
To solve this, you can implement a MultiCircle class that draws multiple circles, and only add that to the JFrame once.
I'm not sure you really want your Circles to be JPanels. They really ought to look more like
class Circle {
double x,y,radius;
void draw(Graphics g) {
g.fillOval(...//etc/.
}
}
Then have a JComponent that has a bunch of Circles, and put that in your JFrame.
Having said that, if you must do it the way you've got it, then you should set the JFrame contentPane's layout to null, and make sure your Circles are not opaque. You'll also have to manually resize each Circle to fit its container.