如何使用Java Swing创建圆形JButton实现9x9围棋棋盘落子功能
实现思路
1. 自定义圆形棋子按钮
需要单独创建StoneButton类继承JButton,重写绘制逻辑实现圆形效果,同时屏蔽默认按钮的样式干扰:
- 重写
paintComponent方法绘制固定65*65尺寸的填充圆 - 去掉默认的按钮边框、内容填充、焦点绘制,避免方形背景外露
- 重写
contains方法保证点击区域仅响应圆形范围
2. JPanel整合与棋子定位
你的Board类本身就是JPanel的子类,直接在Board上做布局即可:
- 给
Board设置绝对定位布局(setLayout(null)),所有棋子按钮直接添加到Board实例上,不要添加到外层JFrame - 棋子放置坐标需要和你绘制网格的计算逻辑对齐:你当前网格的交叉点坐标为
x=10 + i*(getWidth()-20)/9、y=10 + j*(getHeight()-20)/9,将按钮的左上角坐标设为交叉点x - 32、交叉点y -32(32是65*65按钮的半长),即可让按钮中心刚好落在交叉点上。
实现代码
自定义圆形按钮类 StoneButton.java
import javax.swing.*; import java.awt.*; import java.awt.geom.Ellipse2D; public class StoneButton extends JButton { private Color stoneColor; private static final int SIZE = 65; public StoneButton(Color color) { this.stoneColor = color; setPreferredSize(new Dimension(SIZE, SIZE)); setContentAreaFilled(false); // 取消默认背景填充 setBorderPainted(false); // 取消默认边框 setFocusPainted(false); // 取消焦点边框 } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g.create(); // 抗锯齿优化 g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.setColor(stoneColor); g2d.fillOval(0, 0, SIZE, SIZE); g2d.dispose(); } @Override public boolean contains(int x, int y) { // 限制点击区域为圆形 Shape shape = new Ellipse2D.Float(0, 0, getWidth(), getHeight()); return shape.contains(x, y); } }
修改后的Board.java
import java.awt.*; import javax.swing.*; public class Board extends JPanel { private int width; private int height; private String title; private int gridGap; // 网格每格间距,统一计算避免逻辑不一致 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.gridGap = (width - 20) / 9; // 提前计算网格间距,和绘制逻辑统一 setLayout(null); // 启用绝对定位 this.initBoard(); // 测试添加棋子:在(0,0)交叉点放黑子,(1,1)交叉点放白子 addStone(0, 0, Color.BLACK); addStone(1, 1, Color.WHITE); } public Board() { super(); } // 统一添加棋子的方法:i是横向网格序号,j是纵向网格序号,color是棋子颜色 public void addStone(int i, int j, Color color) { StoneButton stone = new StoneButton(color); // 计算按钮左上角坐标,中心对齐交叉点 int x = 10 + i * gridGap - 32; int y = 10 + j * gridGap - 32; stone.setBounds(x, y, 65, 65); add(stone); } public void initBoard() { JFrame f = new JFrame(this.getTitle()); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.setSize(this.getWidth(), this.getHeight()); f.add(this, BorderLayout.CENTER); // 不要给JFrame设置FlowLayout,棋子都放在当前Board面板上 f.setVisible(true); } public void paintComponent(Graphics g) { super.paintComponent(g); for (int i = 0; i < 10; i++) { g.drawLine(0, 10 + (i * gridGap), this.getWidth(), 10 + (i * gridGap)); g.drawLine(10 + (i * gridGap), 0, 10 + (i * gridGap), this.getHeight()); } } }
内容的提问来源于stack exchange,提问作者a.v
相关产品推荐
相关产品推荐

