Search code examples
javaswingcustom-painting

Custom painting not being performed when the custom painting code is in another class


I'm trying to write some custom painting code. Specifically, I want to have a bunch of extended JPanels which paint different aspects of my GUI, but each of these extended panels holds the instructions for how it is to be painted.

I've created the code, but for some reason, the extended JPanel isn't being painted on the main JPanel in my JFrame regardless of what I do. Here is a gist of my main class and one of my extended JPanels. What am I missing?

Breakout

//Java imports
import javax.swing.JFrame;
import java.awt.Dimension;
import javax.swing.JPanel;
//Personal imports
import Ball;

public class Breakout {

    public static void main (String[] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {//start the GUI in a new thread
            public void run(){
                showGUI();
            }
        });
    }

    private static void showGUI() {
        JFrame frame = new JFrame("Breakout");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        Dimension d = new Dimension(640,480);
        frame.setMinimumSize(d);
        frame.setResizable(false);
        JPanel p = new JPanel();
        p.add(new Ball(200,200,50,255,0,0));
        frame.add(p);
        frame.setVisible(true);
    }

}

Ball

import javax.swing.JPanel;
import java.awt.Color;
import java.awt.Graphics;

public class Ball extends JPanel {

    public int x;
    public int y;
    public int radius;
    public Color colour;

    public Ball(int x, int y, int radius, int r, int g, int b) {
        super();
        this.x = x;
        this.y = y;
        this.radius = radius;
        colour = new Color(r,g,b);
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        //define constants
        int topLeftX = x+radius;
        int topLeftY = y+radius;
        int diameter = radius *2;
        //draw outline
        g.setColor(Color.BLACK);
        g.drawOval(topLeftX, topLeftY, diameter, diameter);
        //fill it in
        g.setColor(colour);
        g.fillOval(topLeftX, topLeftY, diameter, diameter);
    }
}

Solution

  • Using JPanels in this way is going to cause you no end of problems.

    The two main problems you have are...

    1. JPanels already have an idea of size and position, adding another x/y coordinate is just confusing and could lead you to painting off the components viewable space
    2. The default preferred size of a JPanel is 0x0. This means when you add it another JPanel, using FlowLayout, the panel is given a size of 0x0, so nothing gets painted.

    Instead, create an interface which has a method called paint and takes a Graphics2D object.

    For each shape you want to paint, create a new class which implements this interface and use it's paint method to paint the object as you see fit.

    Create a custom component, extending from JPanel and maintain a List of these shapes. In it's paintComponent, use a for-loop to paint each shape in the List.

    This custom component should then be added to your frame...