【问题标题】:Why are the paintComponents being called but not seen?为什么调用paintComponents 但看不到?
【发布时间】:2019-01-01 11:09:50
【问题描述】:

我有一个单元格的网格布局,每个单元格都扩展了 JComponent。 GridLayout 管理扩展 JPanel 的 Board 类,并且 Board 对象/面板与其他两个面板一起添加到主面板。

这是单元格类:

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;
    }
}

这是董事会课程:

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,相关代码在上面。蒂亚!

【问题讨论】:

  • 覆盖paintComponent以在组件上绘图时,您应该在JPanel上进行,而不是在JComponent上进行
  • @Snowy_1803 你能进一步解释一下吗?
  • 你的 Cell 类应该扩展 JPanel,它不是一个新的组件类型。开发人员不应覆盖除 JPanel 和 JLabel 之外的任何其他组件上的绘画。
  • @Snowy_1803 你从哪里得到这些信息?扩展JComponent 应该没问题。尽管在网上找到代码 sn-ps 很常见,人们正在扩展 JPanel 以进行自定义绘画,但这并没有真正意义,因为它违反了 Liskov 替换原则。 (JPanel 应该是其他组件的容器。)坦率地说,在 JLabel 上覆盖 paintComponent 听起来是个非常糟糕的主意。
  • 我的第一个想法是这是一个布局问题。由于您使用的是网格布局,我建议您在 Cell 类上覆盖 getPreferredSize,然后避免使用任何显式调整大小的方法,例如 setPreferredSize

标签: java swing grid-layout jcomponent


【解决方案1】:

“核心”问题是,您不了解组件的坐标空间是如何工作的。

组件的x/y 位置是相对于其父级的。任何组件/容器的上/左角始终为0x0

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

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

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

你应该做的是更像这样的事情......

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

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

但是为什么要使用getWidthgetHeight。好吧,在这种情况下,这确保了组件的整个可见区域都被填充了,但是如何影响组件的大小呢?

首选方法是覆盖组件的getPreferredSize 方法并返回“首选”大小(所有条件都相同)。

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

这为父布局管理器提供了有关组件“希望”如何布局的提示。

另一个问题是......

    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;
        }
    }

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多