0

Let's say I have two classes, the first extends JPanel and using Graphics draws a playing board on it. The second makes a JFrame and adds the panel to it.

You can imagine the frame looking something like this: sample JFrame

I now want to add an ellipse to a specific rectangle on click. I understand that I would be using a two-dimensional array in order to get the position I wanted, but I don't understand how the ellipse itself would be drawn on to the existing panel since I used the paint(Graphics g) to draw the playing board.

Here is the code for drawing the board itself if you need it:

class MyBoard extends JPanel {
    private static int height = 6;
    private static int width = 7;
    private static int squareSize = 100;
    private int board[][] = new int[height][width];

    public void paint(Graphics g) {
        for (int i = 0; i < height; i++) {
            for (int j = 0; j < width; j++) {
                g.drawRect(j * squareSize, i * squareSize, squareSize, squareSize);
            }
        }
    }
}

Thanks!

  • 2
    First off: You should never override `paint` but always `paintComponent`. Second: In the overriden code you should generally call `super.paint` (or `super.paintComponent` once you made the switch). Third: You could simply save the square you want to draw in (let's say x = 1, y = 0) and then draw the ellipse there after your two for-loops like `g.drawOval(x*squareSize + squareSize/4, y*squareSize + squareSize/4, squareSize/2, squareSize/2);` – Ben Mar 14 '18 at 13:17
  • @Ben Thanks! I switched to the `paintComponent` and added the `super` , but could you tell me what the difference is? They do the same thing right? Also lets say I wanted to create the ellipse on click. How would I go about that? Make an mouse listener and get the coordinates, but how would I then pass those x and y values to the `paintComponent` ? – Some Student Mar 14 '18 at 13:23

1 Answers1

2

First two things that you should remember: Never override paint but paintComponent and call super.paintComponent in there so that borders and everything works as expected. Regarding why this is the case, reference this question: Difference between paint() and paintcomponent()?


Now to answer your question. Assuming you have an existing logic to determine in which square you want to draw your Ellipse (let's assume you have two Integers elX and elY that are the column and row of your square) you can simply go and draw it after you have finished drawing the board itself.

Imagine sample code like this:

@Override
public void paintComponent(Graphics g)
{
    super.paintComponent(g);

    // Draw the board
    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            g.drawRect(j * squareSize, i * squareSize, squareSize, squareSize);
        }
    }

    // Draw the ellipse at the correct location using half the size of a normal square.
    g.drawOval(elX * squareSize + squareSize / 4, elY * squareSize + squareSize / 4, squareSize / 2 , squareSize / 2);
}

Now the final part of how to go about actually determining where to draw your ellipse. A simple solution would be to add a MouseListener to your panel. And then in the mouseClicked method you calculate where you actually did click.

Could look like this:

this.addMouseListener(new MouseListener()
{

    @Override
    public void mouseClicked(MouseEvent e)
    {
        int column = e.getX() / squareSize;
        int row = e.getY() / squareSize;

        board[column][row] = 1;
    }

    [...] // add the other methods to override

}

Then you slightly adapt your paintComponent method with something like this:

for (int column = 0; column < width; ++column)
{
    for (int row = 0; row < height; ++row)
    {
        if (board[column][row] == 1)
        {
            g.drawOval(column * squareSize + squareSize / 4, row * squareSize + squareSize / 4, squareSize / 2, squareSize / 2);
        }
    }
}

and now you draw an ellipse everywhere you click. You could also check if the clicked square already has 1 set as a value and reset it to 0 to have some toggle mechanism or increment it and draw different things based on the integer value... it's all up to you :)

Ben
  • 1,665
  • 1
  • 11
  • 22
  • Thanks! I also have a follow up question : how could I draw the ellipse on different squares when I pressed on them? I would use the mouse listener and get the x and y coordinates and then what would I do to pass them to the `paintComponent` ? – Some Student Mar 14 '18 at 13:27
  • @SomeStudent I've updated the answer a bit. Also I just used the currently unused `board` 2D-Array for this. Obviously feel free to change this to single variables or just use another array. – Ben Mar 14 '18 at 13:33
  • Glad I could help. – Ben Mar 14 '18 at 13:39