1

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);
    }
}
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
Koz Ross
  • 3,040
  • 2
  • 24
  • 44
  • You should be using `frame.getContentPane().add()` to add components. – BitNinja Mar 02 '14 at 02:50
  • 1
    @codeNinja: Why? "`add()` … has been overridden to forward to the `contentPane` as necessary." – trashgod Mar 02 '14 at 02:59
  • @trashgod I didn't know that. But I feel that `getContentPane().add()` is a bit more readable. – BitNinja Mar 02 '14 at 03:02
  • External links go stale, and few people will follow them. For better help sooner, post a [MCTaRE](http://stackoverflow.com/help/mcve) (Minimal Complete Tested and Readable Example) (as an edit to the question). – Andrew Thompson Mar 02 '14 at 03:16
  • `Component`s already have a concpept of position and size, I'd recommend against this approach and instead using a single `JPanel` which would act as the painter and then devise some kind of "Paintable" class which knew how to paint itself. You would then add these paintable objects to the panel and have the panel paint them via the `paintComponent` method – MadProgrammer Mar 02 '14 at 03:22
  • MadProgrammer's solution is the correct way, see [here](http://stackoverflow.com/a/21871022/2587435) and [here](http://stackoverflow.com/a/22059290/2587435) for examples – Paul Samsotha Mar 02 '14 at 03:56

2 Answers2

3

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...

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
0

In your showGUI method in your main class you have this code:

JPanel p = new JPanel();
p.add(new Ball(200,200,50,255,0,0));
frame.add(p);

This code creates a new JPanel then adds another JPanel to that. This is incorrect because it simply does not make sense to add another JPanel to a perfectly good JPanel that you just created. Instead just do this:

frame.getContentPane().add(new Ball(200, 200, 50, 255,0,0));

Or if you prefer:

Ball ball = new Ball(200, 200, 50, 255,0,0);
frame.getContentPane().add(ball);
BitNinja
  • 1,477
  • 1
  • 19
  • 25
  • While you recommendation could work, it limits OP to a single component. It also fails to correct the underlying issue which caused the issue in the first place – MadProgrammer Mar 02 '14 at 03:28