0

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.

Frakcool
  • 10,915
  • 9
  • 50
  • 89
  • 1
    The default layout for a `JFrame` is `BorderLayout`, so using `JFrame.add(Component)` will just replace the existing `Circle` (`JPanel`). For your problem, I'd suggest having a single `JPanel` where you specify the number of circles to be drawn. [Oracle Guide to Layout Managers](https://docs.oracle.com/javase/tutorial/uiswing/layout/index.html) – d.j.brown Oct 16 '17 at 17:43

1 Answers1

1

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 Circles 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:

enter image description here

I hope this helps you to get a better idea, read about the MVC pattern as I made use of it for this answer.


Note:

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.

Community
  • 1
  • 1
Frakcool
  • 10,915
  • 9
  • 50
  • 89
  • Eyy sorry for the late answer. Thank you very much! I wonder tho: what if I want to add a single circle instead of a bunch in the main? Do I have to write two CirclePane circle = new CirclePane(1); ? – Gianfranco Stercoforti Oct 20 '17 at 17:29
  • @GianfrancoStercoforti you're welcome If this answer solved your question, be sure to [accept it](https://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work) so other people know that this question has been solved :) – Frakcool Oct 20 '17 at 17:31
  • Also another thing: when you call CirclePane circle = new CirclePane(1); are you calling the class or the method? – Gianfranco Stercoforti Oct 20 '17 at 17:35
  • I'm creating a new Object from `CirclePane`, actually I'm calling the constructor: `public CirclePane(int numberOfCircles) {` (which is the one that will provide us the reference to our new `CirclePane` instance – Frakcool Oct 20 '17 at 17:49