Search code examples
javaswingjframejpanel

Graphics2d on JPanel


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.


Solution

  • 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();
            }
    
        }
    
    }