Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JPanel won't paint correctly

I am quite new to Java and Swing, and this is also my first post so sorry if it doesn't make too much sense.

What I am trying to do is when I click on a JPanel, I want it to add a circle where I click. At the moment, all that seems to happen is when I click, a small grey square appears inside the JPanel I want to add to, but I can't seem to find any way of making it draw as a circle.

I have a class that extends JPanel called "Ball" which is what is being added when I click. At the moment, I am not too worried about it being in the correct location, just for it to draw the ball correctly. Below is the code for my "Ball" class:

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

class Ball extends JPanel{

private int x,y,w,h;

//I will use this constructor to put the ball in the correct location later.
Ball(){
    /*this.w = 100;
    this.h = 100;
    this.x = 200;
    this.y = 200;*/
}

//draw the ball
    @Override
public void paintComponent(Graphics g) {
      super.paintComponent(g);
      g.drawOval(200,200,10,10);
      g.setColor(Color.RED);
    }

}

I can kind of guess that it is something to do with the paintComponent method, but everywhere I have looked doesn't seem to have a solution for me.

Any help would be great, thanks!

like image 886
Stefoth Avatar asked Jan 16 '23 07:01

Stefoth


2 Answers

The Graphcis context has already been translated to meet the x/y location that the component should appear within it's parent container, this means that the top, left corner of the Graphics context within the paintComponent method is actually 0x0.

You need to define some size for the ball, you're painting at 10x10, which would suggest that your ball component should return a preferredSize of 10x10

public Dimension getPreferredSize() {
    return new Dimension(10, 10);
}

You will become responsible for providing appropriate layout details to the ball when it's added to the parent container...

public void mouseClicked(MouseEvent evt) {
    Point p = evt.getPoint();
    Ball ball = new Ball();
    Dimension size = ball.getPreferredSize();
    ball.setBounds(new Rectangle(p, size));
    add(ball);
}

This, of course, assumes you have a null layout set for the parent container

UPDATED

Something like...

See spot run

public class PaintBalls {

    public static void main(String[] args) {
        new PaintBalls();
    }

    public PaintBalls() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException ex) {
                } catch (InstantiationException ex) {
                } catch (IllegalAccessException ex) {
                } catch (UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new Board());
                frame.setSize(200, 200);
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class Board extends JPanel {

        public Board() {
            setLayout(null);
            setBackground(Color.WHITE);
            addMouseListener(new MouseAdapter() {

                @Override
                public void mouseClicked(MouseEvent e) {
                    Point p = e.getPoint();
                    Ball ball = new Ball();
                    Dimension size = ball.getPreferredSize();
                    p.x -= size.width / 2;
                    p.y -= size.height / 2;

                    ball.setBounds(new Rectangle(p, size));
                    add(ball);
                    repaint();
                }

            });
        }

    }

    public class Ball extends JPanel {

        public Ball() {
            setOpaque(false);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(10, 10);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            g2d.setColor(Color.RED);
            g2d.fillOval(0, 0, 10, 10);
            g2d.dispose();
        }
    }
}
like image 88
MadProgrammer Avatar answered Jan 31 '23 06:01

MadProgrammer


You probably have a main JPanel where you click.

I would rather design the main panel to handle the mouse click and the Ball class to be a simple Object that defines a drawBall(Graphics g, int x, int y) method that knows how to paint a Ball. This would be called by the paintComponent() method in the main panel. In the main panel, you handle the mouse click, create an object of type Ball and call repaint(). Inside the paintComponent() you call ball.drawBall().

like image 33
Dan D. Avatar answered Jan 31 '23 05:01

Dan D.