如何制作按钮网格

How to make a grid of buttons

最近在学习Java,我的第一个项目是制作一个“围棋棋盘”,9*9行9列,交叉点放置黑白棋子

我创建了一个 9 * 9 行和列的棋盘,现在我必须使用 JButton 组件创建黑白石头。

除了第一行按钮的颜色、大小和位置(setLayout),我无法将按钮变成圆形并将石头放在交点上。

通过多次搜索相关指南,我注意到在创建和设计按钮时有一些我不熟悉的独特结构。

现在我的问题来了 - 我需要创建什么代码结构来生成一个圆形按钮,大小为 65 * 65,黑色或白色?我需要为此创建一个新的 class 吗?我应该如何以及在何处整合 JPanel?

public class Main {

    public static void main(String[] args) {
        Board board = new Board(900, 900, "Go board");
    }
}

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

public class Board extends JPanel {
    private int width;
    private int height;
    private String title;

    public int getWidth() {
        return width;
    }

    public void setWidth(int width) {
        this.width = width;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public Board(int width, int height, String title) {
        super();
        this.width = width;
        this.height = height;
        this.title = title;
        this.initBoard();

    }

    public Board() {
        super();
    }

    public void initBoard() {
        JFrame f = new JFrame(this.getTitle());
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        // f.getContentPane().setBackground(Color.getHSBColor(25, 75, 47));
        f.setSize(this.getWidth(), this.getHeight());
        // f.setLocation(550, 25);
        f.add(this, BorderLayout.CENTER);
        f.setVisible(true);

        JButton stone = new JButton("    ");
        f.add(stone);
        f.setLayout(new FlowLayout());
        stone.setBackground(Color.BLACK.darker());
        stone.setBorder(BorderFactory.createDashedBorder(getForeground()));
        stone.setPreferredSize(new Dimension(65, 65));

    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        for (int i = 0; i < 10; i++) {
            g.drawLine(0, 10 + (i * ((this.getWidth() - 20) / 9)), this.getWidth(),
                    10 + (i * ((this.getWidth() - 20) / 9)));
            g.drawLine(10 + (i * ((this.getHeight() - 20) / 9)), 0, 10 + (i * ((this.getHeight() - 20) / 9)),
                    this.getHeight());
        }
    }
}

在上传 post 之前,我阅读了以下内容 post:

注意:我不想访问post解释如何制作“Go board”的文章,在这种情况下的学习过程是我的目标。

使用带有 9x9 GridLayoutJPanel 并根据您的需要向其添加广告 JButtons,如以下非常基本的 mre 所示:

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

public class GridOfButtons extends JPanel {

    private static final int ROWS = 9, COLS = 9, SIZE = 65, BORDER = 2;
    private static final Color BOARD_COLOR = Color.BLACK;

    public GridOfButtons() {

        setLayout(new GridLayout(ROWS, COLS, BORDER, BORDER));
        setBackground(BOARD_COLOR);

        StonesFactory factory = new StonesFactory(SIZE);
        boolean isBlack = false;

        for (int col = 0; col < COLS; col++) {
            for (int row = 0; row < ROWS; row++) {
                add(factory.makeButton(isBlack));
                isBlack = !isBlack;
            }
        }

        this.initBoard();
    }

    public void initBoard() {
        JFrame f = new JFrame("Board Of Buttons");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setLayout(new GridBagLayout());
        f.add(this);
        f.pack();
        f.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(()->new GridOfButtons());
    }
}

class StonesFactory{

    private static final Color STONE = Color.YELLOW, WHITE_STONE = Color.WHITE, BLACK_STONE = Color.BLACK;
    private final int size;
    private final ImageIcon whiteIcon, blackIcon;

    public StonesFactory(int size) {
        this.size = size;
        whiteIcon = new ImageIcon(createImage(false));
        blackIcon = new ImageIcon(createImage(true));
    }

    JButton makeButton(boolean isBlack){
        JButton stone = new JButton();
        stone.setPreferredSize(new Dimension(size, size));
        stone.setBackground(STONE);
        stone.setIcon(isBlack ? blackIcon : whiteIcon);
        return stone;
    }

    //construct image for button's icon
    private BufferedImage createImage(boolean isBlack) {
        BufferedImage img = new BufferedImage(size , size,  BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2 = img.createGraphics();
        g2.setColor(isBlack ? BLACK_STONE : WHITE_STONE);
        g2.fillOval(0,0,size,size);
        g2.dispose();
        return img;
    }
}

(运行它online)




或者,您可以通过自定义绘画 JPanel 来制作电路板。这将使个别“石头”不可点击且更难修改:

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

public class GridByPainting extends JPanel {

    private static final int ROWS = 9, COLS = 9, SIZE = 65, BORDER = 2;
    private static final Color BOARD_COLOR = Color.BLACK, STONE = Color.YELLOW,
            WHITE_STONE = Color.WHITE, BLACK_STONE = Color.BLACK;
    private final Dimension size;

    public GridByPainting() {
        int x = BORDER + COLS*(SIZE + BORDER);
        int y = BORDER + ROWS*(SIZE + BORDER);
        size = new Dimension(x,y);
        this.initBoard();
    }

    @Override
    public Dimension getPreferredSize() {
        return size;
    }
    public void initBoard() {
        JFrame f = new JFrame("Grid By Painting");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setLayout(new GridBagLayout());
        f.add(this);
        f.pack();
        f.setVisible(true);
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        int width = getWidth(); int height = getHeight();
        int stoneWidth = (width - BORDER) / COLS  - BORDER;
        int stoneHeight = (height -BORDER)/ ROWS - BORDER ;

        //draw board
        g.setColor(BOARD_COLOR);
        g.fillRect(0, 0, width, height);

        boolean isBlack = true;
        //draw square stones
        for (int col = 0; col < COLS; col++) {
            for (int row = 0; row < ROWS; row++) {
                int x = BORDER + col*(stoneWidth + BORDER);
                int y = BORDER + row*(stoneHeight + BORDER);
                g.setColor(STONE);
                g.fillRect(x, y, stoneWidth, stoneHeight);
                //draw circle
                g.setColor(isBlack ? BLACK_STONE : WHITE_STONE);
                isBlack = !isBlack;
                g.fillOval(x, y, stoneWidth, stoneHeight);
            }
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(()->new GridByPainting());
    }
}

(运行它online)


您似乎跳过了 Oracle 教程的一些重要部分,Creating a GUI With Swing

这是我 8 月 23 日的评论,也就是 10 天前。

Generally, you create a logical model of a Go board using a plain Java getter / setter class. You use a drawing JPanel to create the Go board in the GUI and draw circles to represent the stones. The Oracle tutorial, Creating a GUI With Swing, will show you the steps to creating a Swing GUI. Skip the Netbeans section.

那么,您的逻辑模型在哪里?你的图呢JPanel?

这是我创建的快速 GUI。

我的代码有一个逻辑模型。我的代码有一个绘图 JPanel.

我做的第一件事是创建一个简单的 Java getter / setter class 来保存围棋棋盘的逻辑表示。我将其命名为 Board class.

接下来我做的是通过调用 SwingUtilities invokeLater 方法启动我的 Swing GUI。此方法确保 Swing 组件在 Event Dispatch Thread.

上创建和执行

我使用 Runnable class 的 run 方法创建了 JFrameJFrame 方法必须按特定顺序调用。这是我用于所有 Swing 应用程序的顺序。

我将 JFrame 的创建与任何后续 JPanels 的创建分开。我这样做是为了让我的代码井然有序、易于阅读和理解。

我扩展 JPanel 来创建绘图 JPanel。我这样做是为了覆盖 JPanel class 的 paintComponent 方法。 drawing JPanel 绘制(画)棋盘状态。就这样。没有其他的。另一个 class 将负责向逻辑围棋棋盘添加棋子并重新绘制绘图 JPanel。

MoveListenerclass实现了一个MouseListener(扩展了一个MouseAdapter)来响应围棋棋盘上的鼠标点击。 MoveListener class 记录轮到谁了。在围棋棋盘的更复杂版本中,您将有另一个普通的 Java getter / setter class 来跟踪游戏状态。

这是完整的可运行代码。我将所有 classes 都放在 classes 中,这样我就可以 post 将这段代码作为一个块。

import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

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

public class GoBoard implements Runnable {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new GoBoard());
    }
    
    private Board board;
    
    private DrawingPanel drawingPanel;
    
    public GoBoard() {
        this.board = new Board();
    }

    @Override
    public void run() {
        JFrame frame = new JFrame("Go Board");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        this.drawingPanel = new DrawingPanel(board);
        frame.add(drawingPanel, BorderLayout.CENTER);
        
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }
    
    public class DrawingPanel extends JPanel {

        private static final long serialVersionUID = 1L;
        
        private final int margin, pieceRadius, lineSpacing;
        
        private Board board;
        
        public DrawingPanel(Board board) {
            this.board = board;
            
            this.margin = 60;
            this.pieceRadius = 40;
            this.lineSpacing = 100;
            this.setBackground(new Color(0x993300));
            int width = 8 * lineSpacing + margin + margin;
            this.setPreferredSize(new Dimension(width, width));
            this.addMouseListener(new MoveListener(board));
        }
        
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g;
            paintHorizontalLines(g2d);
            paintVerticalLines(g2d);
            paintPieces(g2d);
        }
        
        private void paintHorizontalLines(Graphics2D g2d) {
            int x = margin;
            int y1 = margin;
            int y2 = getHeight() - margin;
            
            g2d.setColor(Color.YELLOW);
            g2d.setStroke(new BasicStroke(3f));
            for (int index = 0; index < 9; index++) {
                g2d.drawLine(x, y1, x, y2);
                x += lineSpacing;
            }
        }
        
        private void paintVerticalLines(Graphics2D g2d) {
            int x1 = margin;
            int x2 = getWidth() - margin;
            int y = margin;
            
            g2d.setColor(Color.YELLOW);
            g2d.setStroke(new BasicStroke(3f));
            for (int index = 0; index < 9; index++) {
                g2d.drawLine(x1, y, x2, y);
                y += lineSpacing;
            }
        }
        
        private void paintPieces(Graphics2D g2d) {
            int[][] b = board.getBoard();
            for (int row = 0; row < b.length; row++) {
                for (int column = 0; column < b[row].length; column++) {
                    int x = column * lineSpacing + margin;
                    int y = row * lineSpacing + margin;
                    if (b[row][column] == 1) {
                        g2d.setColor(Color.BLACK);
                        g2d.fillOval(x - pieceRadius, y - pieceRadius, 
                                pieceRadius + pieceRadius, pieceRadius + pieceRadius);
                    } else if (b[row][column] == 2) {
                        g2d.setColor(Color.WHITE);
                        g2d.fillOval(x - pieceRadius, y - pieceRadius, 
                                pieceRadius + pieceRadius, pieceRadius + pieceRadius);
                    }
                }
            }
        }
        
    }
    
    public class MoveListener extends MouseAdapter {
        
        private boolean isBlackTurn = true;
        
        private Board board;
        
        public MoveListener(Board board) {
            this.board = board;
        }

        @Override
        public void mouseReleased(MouseEvent event) {
            Point point = event.getPoint();
            int margin = 60;
            int pieceRadius = 40;
            int lineSpacing = 100;
            int column = (point.x - margin + pieceRadius) / lineSpacing;
            int row = (point.y - margin + pieceRadius) / lineSpacing;
            int piece = (isBlackTurn) ? 1 : 2;
            board.setPiece(piece, row, column);
            drawingPanel.repaint();
            isBlackTurn = !isBlackTurn;
        }
        
    }
    
    public class Board {
        
        private int[][] board;
        
        public Board() {
            this.board = new int[9][9];
        }
        
        /**
         * <p>
         * This method inserts a piece on the board.
         * </p>
         * 
         * @param piece  - 1 for black, 2 for white
         * @param row    - row of piece
         * @param column - column of piece
         */
        public void setPiece(int piece, int row, int column) {
            this.board[row][column] = piece;
        }

        public int[][] getBoard() {
            return board;
        }
        
    }

}