So this is my main class:
package testgame;
import java.awt.EventQueue;
import javax.swing.JFrame;
public class Game extends JFrame {
public static JFrame frame = new JFrame("Just a test!");
public static void LoadUI() {
frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
frame.setSize(550, 500);
frame.setLocationRelativeTo(null);
frame.setVisible(true); }
public static void main(String[] args) {
LoadUI();
frame.add(new Circles());
}
}
And this is the class that handles what I want to paint:
package testgame;
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.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class Circles extends JPanel {
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
drawBubbles(g); }
public void drawBubbles(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
RenderingHints rh
= new RenderingHints(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
rh.put(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHints(rh);
int x, y, size;
x = (int) (Math.random() * 500) + 15;
y = (int) (Math.random() * 450) + 15;
size = (int) (Math.random() * 50) + 25;
g2d.setColor(Color.GREEN);
g2d.drawOval(x, y, size, size);
g2d.fillOval(x, y, size, size); }
}
If I add another
frame.add(new Circles());
Nothing happens. I think it has to do with the layout of the frame, but the coordinates of the bubbles are random so I'm not sure how to work with this.
In this case I'm using a fixed-size array of 5, you may change it to a bigger fixed-size array or an ArrayList
, as shown in this answer
For your particular case I would create a Circle
class that may contain the data for each circle, being the coords and the size
Then create a CirclePane
class that would paint all the Circle
s in a single paintComponent()
method.
And finally, the Main
class that would have a JFrame
that may contain the CirclePane
added to it.
With the above tips in mind, you could end up with something like this:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.geom.Ellipse2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class CircleDrawer {
private JFrame frame;
public static void main(String[] args) {
SwingUtilities.invokeLater(new CircleDrawer()::createAndShowGui); //We place our program on the EDT
}
private void createAndShowGui() {
frame = new JFrame(getClass().getSimpleName());
CirclePane circle = new CirclePane(5); //We want to create 5 circles, we may want to add more so we change it to 10, or whatever number we want
frame.add(circle);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
//Data class
class Circle {
private Point coords;
private int size;
public Circle(Point coords, int size) {
this.coords = coords;
this.size = size;
}
public Point getCoords() {
return coords;
}
public void setCoords(Point coords) {
this.coords = coords;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
}
//The drawing class
@SuppressWarnings("serial")
class CirclePane extends JPanel {
private int numberOfCircles;
private Circle[] circles;
public CirclePane(int numberOfCircles) {
this.numberOfCircles = numberOfCircles;
circles = new Circle[numberOfCircles];
for (int i = 0; i < numberOfCircles; i++) {
Point coords = new Point((int) (Math.random() * 500) + 15, (int) (Math.random() * 450) + 15); //We generate random coords
int size = (int) (Math.random() * 50) + 25; //And random sizes
circles[i] = new Circle(coords, size); //Finally we create a new Circle with these properties
}
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
for (int i = 0; i < numberOfCircles; i++) {
g2d.draw(new Ellipse2D.Double(circles[i].getCoords().getX(), circles[i].getCoords().getY(), circles[i].getSize(), circles[i].getSize())); //We iterate over each circle in the array and paint it according to its coords and sizes
}
}
@Override
public Dimension getPreferredSize() { //Never call JFrame.setSize(), instead override this method and call JFrame.pack()
return new Dimension(500, 500);
}
}
}
Which produces a similar output to this:
I hope this helps you to get a better idea, read about the MVC pattern as I made use of it for this answer.
In this answer I used the Shapes
API, according to the recommendation of @MadProgrammer in this other answer. I used it in the g2d.draw(...)
line.
For a deeper understanding in how custom painting works in Swing, check Oracle's Lesson: Performing Custom Painting and Painting in AWT and Swing tutorials.