1

I want to make a program in Java that drops a square at the position of your mouse. For that I wanted to draw a grid as background and then add the squares but as soon as I add a new component to the JFrame the background disappears. This also happens the other way around so if I add a Square and then add the Background the square disappears. The following is the code. My question is now how I can add the second Graphic without the first one disappearing. I'm also sorry if my English isn't that great it is not my native language.

import java.awt.BorderLayout;
import java.awt.Image;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.WindowConstants;

//Mainmethod
public class App {
    public static void main(String[] args) throws Exception {
        System.out.println("Hello World");
        MainFrame myFrame = new MainFrame();
        myFrame.init(); 
    }
}
//Window
public class MainFrame extends JFrame{
    public void init(){
        Image Logo; // Image for the window icon
        JPanel contentPane;
        Background background = new Background();
        Sand sand = new Sand();

        try {//sets the WidnowIcon
            Logo = ImageIO.read(new File("Logo.jpg"));
            setIconImage(Logo);
        } catch (IOException e) {
            
            e.printStackTrace();
        }
        //JFrameconfiguratio     
        setTitle("Sandsim");
        setSize(600, 600);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setVisible(true);

        //contentPaneconfiguration
        contentPane = new JPanel();
        contentPane.setLayout(new BorderLayout());
        contentPane.setVisible(true);
        setContentPane(contentPane);

        //adds Background and sand but you can only see the one that was added last
        contentPane.add(background);
        contentPane.add(sand);
    }
}
//draws the Bakground as grid of 10 by 10 squares
class Background extends JComponent {
    public void paintComponent(Graphics g) {

        int positionX = 0;
        int positionY = 0;

        Graphics2D g2d = (Graphics2D) g;
        g2d.setColor(Color.BLACK);


        for (int i = 0; i < getBounds().width / 10; i++) {
            g2d.drawLine(positionX, 0, positionX, getBounds().height);
            positionX += 10;
        }
        for (int i = 0; i < getBounds().height / 10; i++) {
            g2d.drawLine(0, positionY, getBounds().width, positionY);
            positionY += 10;
        }
    }
}
//draws a Sandcorn as 10 by 10 Rectangle
public class Sand extends JComponent{
    public void paintComponent(Graphics g){

        Graphics2D g2d =(Graphics2D)g;
        g2d.setColor(Color.YELLOW);
        g2d.fillRect(10, 10, 10, 10);

    }
}

I tried to get it to work for to hours now but I couldn't find a solution for it. I looked on Oracle and searched for some tutorials on the Internet but they always worked without making any special adjustments or something like that. I would really appreciate any kind of help.

5
  • 2
    Always call super.paintComponent(g) first
    – g00se
    Commented May 28 at 12:28
  • There are a couple of ways to do this, but one easy way is to only paint in a single component, and instead keep a list/array of all objects that need painting, and make sure you paint them all in a single paintComponent method. Another way to do this is to layer components with see-through backgrounds, but this will only work if you call super.paintComponent(g); at the start of your paintComponent method, see here for some help: stackoverflow.com/questions/15309611/…
    – sorifiend
    Commented May 28 at 12:30
  • Another possible solution is to use a background JPanel that uses a new GridLayout(10, 10) and fill it with "cell" JPanels. Give the panels a MouseListener that changes the cell's color (background color) on mouse press. Commented May 28 at 12:34
  • You need to investigate how BorderLayout behaves
    – g00se
    Commented May 28 at 12:34
  • Besides the things already mentioned you should not be extending JFrame. Extend JPanel and add that class to the frame. You should really check out the Java Tutorials on painting. And check out SO for examples of how to paint. There are plenty of them.
    – WJS
    Commented May 28 at 12:41

1 Answer 1

3

Here is a very rudimentary example of what you described. It does the following:

  • takes the current mouse position and converts it to a proper grid location. If the mouse is at 258,584, it converts it to 251, 581 which would be just inside the upper left corner of the target grid square.
  • draws a yellow square on the grid where the mouse is clicked. It draws it of size 9x9 to fit inside the grid.
  • It also incorporates other suggestions above and eliminates some classes. I also ignored the logo code although it worked.

Note that what may not be obvious to those new to painting is that super.paintComponent() does many things including clearing the background. This means that everything needs to be repainted. Which is why I use a list to hold all the previously drawn squares. Each time the mouse button is clicked on a square, a new square position is added to the list and all (which includes the one just added) are painted when repaint() is called.

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class MainFrame extends JPanel {
    JFrame f = new JFrame();

    record Square(int x, int y) {
    }

    List<Square> squares = new ArrayList<>();

    public static void main(String[] args) throws Exception {
        System.out.println("Hello World");
        MainFrame myFrame = new MainFrame();
        myFrame.init();
    }

    public void init() {

        // JFrameconfiguration
        f.setTitle("Sandsim");
        f.add(this);
        addMouseListener(new MyMouseListener());
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.pack();
        f.setVisible(true);

    }
    public Dimension getPreferredSize() {
        return new Dimension(600,600);
    }
    // draws the Bakground as grid of 10 by 10 squares

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        int positionX = 0;
        int positionY = 0;

        Graphics2D g2d = (Graphics2D) g;
        g2d.setColor(Color.BLACK);

        for (int i = 0; i < getBounds().width / 10; i++) {
            g2d.drawLine(positionX, 0, positionX, getBounds().height);
            positionX += 10;
        }
        for (int i = 0; i < getBounds().height / 10; i++) {
            g2d.drawLine(0, positionY, getBounds().width, positionY);
            positionY += 10;
        }

        g2d.setColor(Color.YELLOW);
        for (Square sq : squares) {
            g2d.fillRect(sq.x, sq.y, 9, 9);
        }
    }

    class MyMouseListener extends MouseAdapter {
        @Override
        public void mouseClicked(MouseEvent me) {
            squares.add(new Square(me.getX()/10*10 + 1, me.getY()/10*10+1));
            f.repaint();
        }

    }

}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.