Home > Software engineering >  Why does paint(Graphics g) work, while paintComponent(Graphics g) does not?
Why does paint(Graphics g) work, while paintComponent(Graphics g) does not?

Time:01-18

I am very much a noob when it comes to swing. So far, all of my knowledge comes from YouTube and Stack Overflow. I am trying to make an interactive 5x5 board, with a random image in every spot, and a transparent JLabel on every image. I have a 2D array of ints, and I paint an image based on the ID value from the 2D array.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Panel extends JPanel{
    int rows, cols, size;
    int[][] gameBoard;
    static final int SCREEN_SIZE = 500;
    Panel(){
        setPreferredSize(new Dimension(SCREEN_SIZE, SCREEN_SIZE));
        setBackground(new Color(135, 206, 235)); //Sky blue
        newBoard();
    }
    //Here
    public void paint(Graphics g) {
        super.paint(g);
        Graphics2D g2D = (Graphics2D) g;
        for (int r = 0; r<rows; r  ) for (int c = 0; c<cols; c  ) g2D.drawImage(Images.getImage(board[r][c]), size*c, size*r, null);//Paints an image based on each int value in the 2D array
    }
    void newBoard() {
        rows = cols = 5;
        size = 100;
        board = new int[rows][cols];
        fill();
    }
    void fill() {
        for (int r = 0; r<rows; r  ) for (int c = 0; c<cols; c  ) gameBoard[r][c] = Images.randomTile(); //fills the 2D array with random values that relate to which image to display
    }
}

(I took out all the irrelevant stuff)

This part works perfectly fine. The problem is that I tried to make an array of transparent JLabels with MouseListeners to cover each image. While testing, I made them opaque, but they didn't show up. I looked through StackOverflow to find my problem, and I keep on seeing people say not to override paint, but to override paintComponent. When I tried it, I got the background, but not the images. It is the same exact code, when I override paint, everything works fine, but when I change paint to paintComponent, I just get the background.

public void paint(Graphics g) {
        super.paint(g);
        Graphics2D g2D = (Graphics2D) g;
        for (int r = 0; r<rows; r  ) for (int c = 0; c<cols; c  ) g2D.drawImage(Images.getImage(board[r][c]), size*c, size*r, null);//Paints an image based on each int value in the 2D array
    }

Works perfectly

public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2D = (Graphics2D) g;
        for (int r = 0; r<rows; r  ) for (int c = 0; c<cols; c  ) g2D.drawImage(Images.getImage(board[r][c]), size*c, size*r, null);//Paints an image based on each int value in the 2D array
    }

Only shows the background

EDIT:

import java.awt.*;

import java.awt.event.*;
import javax.swing.*;

@SuppressWarnings("serial")
public class Panel extends JPanel implements MouseListener{
    
    int rows, cols, size;
    
    int[][] board, shadowBoard;
    JLabel[][] labelBoard;
    
    static final int SCREEN_SIZE = 500;
    
    Panel(){
        
        setPreferredSize(new Dimension(SCREEN_SIZE, SCREEN_SIZE));
        setBackground(new Color(135, 206, 235));
        
        newBoard();
        
        /*Timer tick = new Timer(5000, new ActionListener() {
            
            public void actionPerformed(ActionEvent e)  {
                
                repaint();
                
            }
                
        });
        
        tick.start();*/
        
    }
    
    public void paint(Graphics g) {
        
        super.paint(g);
        
        Graphics2D g2D = (Graphics2D) g;
        
        
        for (int r = 0; r<rows; r  ) for (int c = 0; c<cols; c  ) g2D.drawImage(Images.getImage(board[r][c]), size*c, size*r, null);
    
    }
    
//Board methods
    void newBoard() {
            
        rows = 5;
        cols = 5;
        size = 100;
        board = shadowBoard = new int[rows][cols];
        labelBoard = new JLabel[rows][cols];
        fillLabelBoard();
        for (int r = 0; r<rows; r  ) for (int c = 0; c<cols; c  ) this.add(labelBoard[r][c]);
        fill();
        //printBoard();
            
    }
    
    void newBoard(int r, int c) {
        
        rows = r;
        cols = c;
        board = new int[rows][cols];
        shadowBoard = new int[rows][cols];
        size = (int) ((r>c)? SCREEN_SIZE/r : SCREEN_SIZE/c);
        Images.resize(size);
        fill();
        //printBoard();
    }
    
    void fill() {
        for (int r = 0; r<rows; r  ) for (int c = 0; c<cols; c  ) board[r][c] = Images.randomImage();
    }
    
    void fillLabelBoard() {
        for (int r = 0; r<rows; r  ) {
            for (int c = 0; c<cols; c  ) {
                labelBoard[r][c] = new JLabel();
                labelBoard[r][c].setBounds(0, 0, size, size);
                labelBoard[r][c].setBackground(Color.red);
                labelBoard[r][c].setOpaque(true);
                labelBoard[r][c].addMouseListener(this);
                //add(labelBoard[r][c]);
                
            }
        }
    }
    
//Debugging
    void printBoard() {
        for (int[] r: board) {
            for (int c: r) System.out.print(c);
            System.out.print("\n");
        }
        System.out.println(rows);
        System.out.println(cols);
        System.out.println(size);
    }

    @Override
    public void mouseClicked(MouseEvent e) {
        System.out.print("click");
        
    }

    @Override
    public void mousePressed(MouseEvent e) {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void mouseReleased(MouseEvent e) {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void mouseEntered(MouseEvent e) {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void mouseExited(MouseEvent e) {
        // TODO Auto-generated method stub
        
    }
    
    
}

Full, unedited code

CodePudding user response:

The origin paint method inside JComponent does use the RepaintManager to determine if the rendering/painting must be done or not. Also it has a mechanism for Double-Buffering etc. inside.

paint only calls paintComponent when the component or it's client rectangle is marked as dirty, so a paint is necessary.

When you are overwriting paint you just call the origin method and after this you paint your own stuff - this will always be done.

But when you override paintComponent your parts will not be rendered when the origin paint method does not see the need to render/paint it. If you want to use paintComponent - you have to ensure the component will be marked as dirty/to render. For details look into JComponent paint implementation.

CodePudding user response:

Again, no issue. Both paint and paintComponent will produce a grid, the problem isn't with the code you're presenting us.

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class Test {

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

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new Panel());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class Panel extends JPanel implements MouseListener {

        int rows, cols, size;

        int[][] board, shadowBoard;
        JLabel[][] labelBoard;

        static final int SCREEN_SIZE = 500;

        Panel() {

            setPreferredSize(new Dimension(SCREEN_SIZE, SCREEN_SIZE));
            setBackground(new Color(135, 206, 235));

            newBoard();

            /*Timer tick = new Timer(5000, new ActionListener() {

            public void actionPerformed(ActionEvent e)  {

                repaint();

            }

        });

        tick.start();*/
        }

//        public void paint(Graphics g) {
//            super.paint(g);
//            Graphics2D g2D = (Graphics2D) g;
//            paintBoard(g2D);
//        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2D = (Graphics2D) g;
            paintBoard(g2D);
        }

        protected void paintBoard(Graphics2D g2d) {
            for (int r = 0; r < rows; r  ) {
                for (int c = 0; c < cols; c  ) {
                    g2d.drawRect(c * size, r * size, size, size);
//                    g2D.drawImage(Images.getImage(board[r][c]), size * c, size * r, null);
                }
            }
        }

//Board methods
        void newBoard() {

            rows = 5;
            cols = 5;
            size = 100;
            board = shadowBoard = new int[rows][cols];
            labelBoard = new JLabel[rows][cols];
            fillLabelBoard();
            for (int r = 0; r < rows; r  ) {
                for (int c = 0; c < cols; c  ) {
                    this.add(labelBoard[r][c]);
                }
            }
//            fill();
//            printBoard();

        }

        void newBoard(int r, int c) {

            rows = r;
            cols = c;
            board = new int[rows][cols];
            shadowBoard = new int[rows][cols];
            size = (int) ((r > c) ? SCREEN_SIZE / r : SCREEN_SIZE / c);
            //Images.resize(size);
//            fill();
            //printBoard();
        }

//        void fill() {
//            for (int r = 0; r < rows; r  ) {
//                for (int c = 0; c < cols; c  ) {
//                    board[r][c] = Images.randomImage();
//                }
//            }
//        }

        void fillLabelBoard() {
            for (int r = 0; r < rows; r  ) {
                for (int c = 0; c < cols; c  ) {
                    labelBoard[r][c] = new JLabel();
                    labelBoard[r][c].setBounds(0, 0, size, size);
                    labelBoard[r][c].setBackground(Color.red);
                    labelBoard[r][c].setOpaque(true);
                    labelBoard[r][c].addMouseListener(this);
                    //add(labelBoard[r][c]);

                }
            }
        }

//Debugging
        void printBoard() {
            for (int[] r : board) {
                for (int c : r) {
                    System.out.print(c);
                }
                System.out.print("\n");
            }
            System.out.println(rows);
            System.out.println(cols);
            System.out.println(size);
        }

        @Override
        public void mouseClicked(MouseEvent e) {
            System.out.print("click");

        }

        @Override
        public void mousePressed(MouseEvent e) {
            // TODO Auto-generated method stub

        }

        @Override
        public void mouseReleased(MouseEvent e) {
            // TODO Auto-generated method stub

        }

        @Override
        public void mouseEntered(MouseEvent e) {
            // TODO Auto-generated method stub

        }

        @Override
        public void mouseExited(MouseEvent e) {
            // TODO Auto-generated method stub

        }

    }
}
  •  Tags:  
  • Related