【问题标题】:How to make a grid of buttons如何制作按钮网格
【发布时间】:2021-10-23 20:42:38
【问题描述】:

这几天在学Java,我的第一个项目是做一个“围棋板”,9*9的行列,在十字路口放黑白石子。

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

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

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

现在我的问题来了 - 我需要创建什么代码结构才能生成一个圆形按钮,大小为 65 * 65,黑色或白色?我需要为此创建一个新课程吗?我应该如何以及在哪里集成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());
        }
    }
}

在上传帖子之前,我阅读了以下帖子:

注意:我不想访问解释如何制作“围棋板”的帖子,在这种情况下的学习过程是我的目标。

【问题讨论】:

  • 通常,您使用普通的 Java getter / setter 类创建围棋棋盘的逻辑模型。您使用绘图 JPanel 在 GUI 中创建围棋棋盘并绘制圆圈来表示棋子。 Oracle 教程Creating a GUI With Swing 将向您展示创建 Swing GUI 的步骤。跳过 Netbeans 部分。
  • 使用自定义绘画(覆盖paintComponent)创建一个圆圈板是一种方法。使用JButtons(或JLables)构建电路板,通常使用GridLayout 放置是不同的(参见示例here
  • “我需要创建什么代码结构才能生成圆形按钮,大小为 65 * 65,黑色或白色?” I 'd 改为使用使用圆形图像形成的方形按钮,并删除按钮装饰和边距。对于移除的部分,请参阅this answer。围棋棋盘的网格将由其他 9 个不同的图标组成。每个方向有 4 x T 形状,4 x 角图标,以及所有其余按钮的 + 图标。所以最终它会是一个 9x9 的按钮网格布局,调整后看起来像...所描述的模型。
  • .. @GilbertLeBlanc 在第一条评论中。 “我需要为此创建一个新类吗?” 不需要。一个普通的旧 Java JButton 就可以了,它只需要根据需要进行调整(使用其现有方法)。 “我应该如何以及在哪里集成JPanel?” 什么?我不确定我是否理解,但游戏板将是(再次标准)JPanel 和 9 x 9 GridLayout

标签: java swing user-interface jpanel jbutton


【解决方案1】:

使用 JPanel 和 9x9 GridLayout 并根据您的需要配置广告 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


【讨论】:

    【解决方案2】:

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

    这是我在 10 天前的 8 月 23 日发表的评论。

    通常,您使用纯 Java 创建围棋棋盘的逻辑模型 getter/setter 类。您使用绘图 JPanel 创建围棋板 在 GUI 中绘制圆圈来表示石头。甲骨文 教程Creating a GUI With Swing 将向您展示 创建一个 Swing GUI。跳过 Netbeans 部分。

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

    这是我创建的快速 GUI。

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

    我做的第一件事是创建一个普通的 Java getter/setter 类来保存 Go Board 的逻辑表示。我将其命名为 Board 类。

    接下来我做的是调用 SwingUtilities invokeLater 方法来启动我的 Swing GUI。此方法确保在Event Dispatch Thread 上创建和执行 Swing 组件。

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

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

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

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

    这是完整的可运行代码。我将所有类都设为内部类,这样我就可以将这段代码作为一个块发布。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-06-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-21
      • 2021-12-07
      • 1970-01-01
      相关资源
      最近更新 更多