为什么调用了 paintComponents 但看不到?

Why are the paintComponents being called but not seen?

我有一个单元格布局,每个单元格都扩展了 JComponent。 GridLayout 管理扩展 JPanel 的 Board class,Board object/panel 与其他两个面板一起添加到主面板。

这是单元格 Class:

public class Cell extends JComponent{

    private int row;
    private int col;

    private int rowHeight;
    private int colWidth;

    private boolean active = false;

    private Color color;

    public Cell(int row, int col, Color color) {
        this.row = row;
        this.col = col;

        this.color = color;
    }

    public Cell(int row, int col, int rowHeight, int colWidth, Color color) {
        this.row = row;
        this.col = col;

        this.rowHeight = rowHeight;
        this.colWidth = colWidth;

        this.color = color;
    }

    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        paintSquare(g);
    }

    private void paintSquare(Graphics g) {
        g.setColor(color);
        g.fillRoundRect(
            (int) (col * colWidth),
            (int) (row * rowHeight),
            (int) (rowHeight),
            (int) (colWidth),
            10,
            10);

    }

    public int getCol()
    {
        return col;
    }

    public int getRow()
    {
        return row;
    }

    public boolean isActive() {
        return active;
    }

    public void setActive(boolean active) {
        this.active = active;
    }

    public Color getColor() {
        return color;
    }

    public void setColor(Color color) {
        this.color = color;
    }
}

这是董事会 Class:

public class Board extends JPanel {

    public Cell[][] gameBoard;

    public final int GAME_ROWS;
    public final int GAME_COLUMNS;

    public int rowHeight;
    public int columnWidth;

    public Color selectedColor;

    public Board(int GAME_ROWS, int GAME_COLUMNS) {
        this.GAME_COLUMNS = GAME_COLUMNS;
        this.GAME_ROWS = GAME_ROWS;

        calculateDimensions();

        createGameBoard();

        setUpBoardPanel();
    }

    private void calculateDimensions() {
        rowHeight = (int) this.getHeight() / GAME_ROWS;
        columnWidth = (int) this.getWidth() / GAME_COLUMNS;
    }

    private void createGameBoard() {
        Random random = new Random();
        int cellColor;
        gameBoard = new Cell[GAME_ROWS][GAME_COLUMNS];
        for (int row = 0; row < GAME_ROWS; row++) {
            for (int col = 0; col < GAME_COLUMNS; col++) {
                cellColor = random.nextInt(Properties.COLORS.length);
                Cell newCell = new Cell(row, col, rowHeight, 
                    columnWidth,Properties.COLORS[cellColor]);
                gameBoard[row][col] = newCell;
            }
        }
    }

    private void setUpBoardPanel() {
        setLayout(new GridLayout(GAME_ROWS, GAME_COLUMNS));
        setPreferredSize(Properties.BOARD_TABLE_SIZE);
        setBorder(new EmptyBorder(20, 10, 0, 0));
        setBackground(Properties.BACKGROUND_COLOR);

        addBoardPanelComponents();
    }

    private void addBoardPanelComponents() {
        for(int r = 0; r < GAME_ROWS; r++) {
            for(int c = 0; c < GAME_COLUMNS; c++) {
                add(gameBoard[r][c]);
            }
        }
    }
}

主面板上的所有内容都完美显示,我可以看到 Board 面板已添加,因为当我更改其背景时,它会按设置显示。

我浏览了很多教程并且调用超级正确,所以我不确定如何正确添加和调用组件并且不显示。

要查看完整的程序代码可以去我的github,但相关代码在上面。 TIA!

"core"问题是,你不明白组件的坐标space是如何工作的。

组件的x/y位置是相对于父组件的。任何 component/container 的 top/left 角总是 0x0.

所以当你做这样的事情时...

g.fillRoundRect(
                (int) (col * colWidth),
                (int) (row * rowHeight),
                (int) (rowHeight),
                (int) (colWidth),
                10,
                10);

你是说,填充一个相对于组件本身左上角(始终为 0x0col * width x row * rowHeight 开始的矩形

你应该做的更像这样...

g.fillRoundRect(
                0,
                0,
                getWidth() - 1,
                getHeight() - 1,
                10,
                10);

这将填充组件的整个可见区域。

但为什么要用getWidthgetHeight。嗯,在这个上下文中,这确保了组件的整个可见区域都被填充了,但是你如何影响组件的大小?

首选方法是覆盖组件的 getPreferredSize 方法和 return "preferred" 大小(所有条件都相同)。

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

这向父布局管理器提供了有关组件 "like" 布局方式的提示。

另一个问题是...

    private void calculateDimensions() {
        rowHeight = (int) this.getHeight() / GAME_ROWS;
        columnWidth = (int) this.getWidth() / GAME_COLUMNS;
    }

这是没有意义的,因为在组件经过布局传递之前,它的大小是 0x0,所以,基本上你是说 rowHeightcolumnWidth 应该是 0x0:/

老实说,最好还是摆脱它。如果需要,直接将已知值播种到 Cell

可运行示例...

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.util.Random;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;

public class Test {

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

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

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new Board(10, 10));
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class Board extends JPanel {

        public Cell[][] gameBoard;

        public final int GAME_ROWS;
        public final int GAME_COLUMNS;

        public int rowHeight = 50;
        public int columnWidth = 50;

        public Color selectedColor;

        public Board(int GAME_ROWS, int GAME_COLUMNS) {
            this.GAME_COLUMNS = GAME_COLUMNS;
            this.GAME_ROWS = GAME_ROWS;

            createGameBoard();

            setUpBoardPanel();
        }

        private void createGameBoard() {
            Random random = new Random();
            int cellColor;
            Color[] colors = new Color[]{Color.BLUE, Color.CYAN, Color.DARK_GRAY, Color.GRAY, Color.GREEN, Color.LIGHT_GRAY, Color.MAGENTA, Color.ORANGE, Color.PINK, Color.RED, Color.YELLOW};
            gameBoard = new Cell[GAME_ROWS][GAME_COLUMNS];
            for (int row = 0; row < GAME_ROWS; row++) {
                for (int col = 0; col < GAME_COLUMNS; col++) {
                    cellColor = random.nextInt(colors.length);
                    Cell newCell = new Cell(row, col, rowHeight,
                                    columnWidth, colors[cellColor]);
                    gameBoard[row][col] = newCell;
                }
            }
        }

        private void setUpBoardPanel() {
            setLayout(new GridLayout(GAME_ROWS, GAME_COLUMNS));
            setBorder(new EmptyBorder(20, 10, 0, 0));
            setBackground(Color.RED);

            addBoardPanelComponents();
        }

        private void addBoardPanelComponents() {
            for (int r = 0; r < GAME_ROWS; r++) {
                for (int c = 0; c < GAME_COLUMNS; c++) {
                    add(gameBoard[r][c]);
                }
            }
        }
    }

    public class Cell extends JComponent {

        private int row;
        private int col;

        private int rowHeight;
        private int colWidth;

        private boolean active = false;

        private Color color;

        public Cell(int row, int col, int rowHeight, int colWidth, Color color) {
            this.row = row;
            this.col = col;

            this.rowHeight = rowHeight;
            this.colWidth = colWidth;

            this.color = color;
            setBorder(new LineBorder(Color.BLACK));
        }

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

        protected void paintComponent(Graphics g) {
            super.paintComponent(g);

            paintSquare(g);
        }

        private void paintSquare(Graphics g) {
            g.setColor(color);
            g.fillRoundRect(
                            0,
                            0,
                            getWidth() - 1,
                            getHeight() - 1,
                            10,
                            10);

        }

        public int getCol() {
            return col;
        }

        public int getRow() {
            return row;
        }

        public boolean isActive() {
            return active;
        }

        public void setActive(boolean active) {
            this.active = active;
        }

        public Color getColor() {
            return color;
        }

        public void setColor(Color color) {
            this.color = color;
        }
    }

}