上一篇
在Java中绘制棋盘和棋子,通常使用Swing或JavaFX的绘图功能,通过重写组件的
paintComponent()方法,利用Graphics2D对象绘制棋盘网格和圆形棋子,棋子坐标需根据网格尺寸计算,通过
fillOval()在指定位置渲染棋子颜色实现落子效果。
Java棋盘棋子绘制教程:实现图形化棋盘与落子功能
在Java中创建棋盘并在其上绘制棋子是一个常见的图形界面编程任务,本教程将详细介绍实现方法,涵盖Swing组件的使用、绘图技术和交互事件处理。
实现思路
我们将采用以下技术方案:
- 使用
JFrame创建主窗口 - 自定义
JPanel作为棋盘绘制区域 - 重写
paintComponent方法绘制棋盘和棋子 - 使用鼠标事件监听器实现交互式落子
- 设计美观的UI界面增强用户体验
完整代码实现
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.util.ArrayList;
import java.util.List;
public class ChessBoard extends JFrame {
// 棋盘设置
private static final int BOARD_SIZE = 15; // 15x15的棋盘
private static final int GRID_SIZE = 40; // 每个格子的像素大小
private static final int MARGIN = 50; // 边距
private static final int WINDOW_SIZE = 2 * MARGIN + (BOARD_SIZE - 1) * GRID_SIZE;
// 棋子数据
private enum Piece { EMPTY, BLACK, WHITE }
private Piece[][] board = new Piece[BOARD_SIZE][BOARD_SIZE];
private List<Point> moveHistory = new ArrayList<>();
private Color boardColor = new Color(220, 179, 92); // 棋盘木质颜色
private boolean isBlackTurn = true; // 当前落子方(黑子先行)
private JLabel statusLabel; // 状态标签
public ChessBoard() {
setTitle("Java 棋盘棋子绘制");
setSize(WINDOW_SIZE, WINDOW_SIZE + 60); // 额外高度用于状态栏
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null); // 居中显示
// 初始化棋盘
for (int i = 0; i < BOARD_SIZE; i++) {
for (int j = 0; j < BOARD_SIZE; j++) {
board[i][j] = Piece.EMPTY;
}
}
// 创建棋盘面板
BoardPanel boardPanel = new BoardPanel();
boardPanel.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
// 计算点击位置对应的棋盘坐标
int x = (e.getX() - MARGIN + GRID_SIZE / 2) / GRID_SIZE;
int y = (e.getY() - MARGIN + GRID_SIZE / 2) / GRID_SIZE;
// 确保坐标在有效范围内且该位置没有棋子
if (x >= 0 && x < BOARD_SIZE && y >= 0 && y < BOARD_SIZE && board[x][y] == Piece.EMPTY) {
board[x][y] = isBlackTurn ? Piece.BLACK : Piece.WHITE;
moveHistory.add(new Point(x, y));
isBlackTurn = !isBlackTurn; // 切换玩家
updateStatus();
boardPanel.repaint(); // 重绘棋盘
}
}
});
// 创建状态标签
statusLabel = new JLabel(" ", JLabel.CENTER);
statusLabel.setFont(new Font("微软雅黑", Font.BOLD, 16));
statusLabel.setForeground(new Color(50, 50, 50));
statusLabel.setOpaque(true);
statusLabel.setBackground(new Color(240, 240, 240));
updateStatus();
// 添加组件
setLayout(new BorderLayout());
add(boardPanel, BorderLayout.CENTER);
add(statusLabel, BorderLayout.SOUTH);
// 添加重置按钮
JButton resetButton = new JButton("重新开始");
resetButton.setFont(new Font("微软雅黑", Font.PLAIN, 14));
resetButton.setBackground(new Color(70, 130, 180));
resetButton.setForeground(Color.WHITE);
resetButton.addActionListener(e -> resetGame());
JPanel buttonPanel = new JPanel();
buttonPanel.add(resetButton);
add(buttonPanel, BorderLayout.NORTH);
}
private void updateStatus() {
String player = isBlackTurn ? "黑方" : "白方";
statusLabel.setText(player + "回合 | 落子位置: " +
(moveHistory.isEmpty() ? "无" : formatPoint(moveHistory.get(moveHistory.size()-1))));
}
private String formatPoint(Point p) {
char col = (char)('A' + p.x);
return String.format("%c%d", col, p.y + 1);
}
private void resetGame() {
for (int i = 0; i < BOARD_SIZE; i++) {
for (int j = 0; j < BOARD_SIZE; j++) {
board[i][j] = Piece.EMPTY;
}
}
moveHistory.clear();
isBlackTurn = true;
updateStatus();
repaint();
}
// 自定义棋盘绘制面板
private class BoardPanel extends JPanel {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// 绘制棋盘背景
g2d.setColor(boardColor);
g2d.fillRect(0, 0, getWidth(), getHeight());
// 绘制网格线
g2d.setColor(Color.BLACK);
for (int i = 0; i < BOARD_SIZE; i++) {
int startX = MARGIN + i * GRID_SIZE;
int startY = MARGIN;
int endY = MARGIN + (BOARD_SIZE - 1) * GRID_SIZE;
// 竖线
g2d.drawLine(startX, startY, startX, endY);
// 横线
int startY2 = MARGIN + i * GRID_SIZE;
int endX = MARGIN + (BOARD_SIZE - 1) * GRID_SIZE;
g2d.drawLine(MARGIN, startY2, endX, startY2);
}
// 绘制天元和星位
drawBoardMarkers(g2d);
// 绘制棋子
for (int i = 0; i < BOARD_SIZE; i++) {
for (int j = 0; j < BOARD_SIZE; j++) {
if (board[i][j] != Piece.EMPTY) {
drawPiece(g2d, i, j);
}
}
}
}
private void drawBoardMarkers(Graphics2D g2d) {
g2d.setColor(Color.BLACK);
int center = BOARD_SIZE / 2;
int size = 8;
// 绘制九个星位
int[] points = {3, center, BOARD_SIZE - 4};
for (int x : points) {
for (int y : points) {
g2d.fillOval(
MARGIN + x * GRID_SIZE - size/2,
MARGIN + y * GRID_SIZE - size/2,
size, size
);
}
}
}
private void drawPiece(Graphics2D g2d, int x, int y) {
int centerX = MARGIN + x * GRID_SIZE;
int centerY = MARGIN + y * GRID_SIZE;
int radius = GRID_SIZE / 2 - 2;
if (board[x][y] == Piece.BLACK) {
// 绘制黑色棋子(带光泽效果)
GradientPaint gradient = new GradientPaint(
centerX - radius/2, centerY - radius/2, Color.DARK_GRAY,
centerX + radius/2, centerY + radius/2, Color.BLACK
);
g2d.setPaint(gradient);
g2d.fill(new Ellipse2D.Double(centerX - radius, centerY - radius, radius*2, radius*2));
// 绘制光泽
g2d.setColor(new Color(255, 255, 255, 150));
g2d.fillOval(centerX - radius/3, centerY - radius/3, radius/2, radius/3);
} else {
// 绘制白色棋子(带阴影效果)
g2d.setColor(Color.WHITE);
g2d.fill(new Ellipse2D.Double(centerX - radius, centerY - radius, radius*2, radius*2));
// 绘制边框和阴影
g2d.setColor(new Color(150, 150, 150));
g2d.setStroke(new BasicStroke(1.5f));
g2d.drawOval(centerX - radius, centerY - radius, radius*2, radius*2);
// 底部阴影
g2d.setColor(new Color(200, 200, 200));
g2d.drawArc(centerX - radius, centerY - radius, radius*2, radius*2, 200, 140);
}
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
new ChessBoard().setVisible(true);
});
}
}
关键实现解析
棋盘网格绘制
通过计算棋盘位置,使用drawLine方法在面板上绘制横线和竖线:

for (int i = 0; i < BOARD_SIZE; i++) {
int startX = MARGIN + i * GRID_SIZE;
// 绘制竖线
g2d.drawLine(startX, startY, startX, endY);
// 绘制横线
g2d.drawLine(MARGIN, startY2, endX, startY2);
}
棋子绘制技术
使用Ellipse2D.Double绘制圆形棋子,并添加渐变和光泽效果增强视觉效果:
黑色棋子:
GradientPaint gradient = new GradientPaint(
centerX - radius/2, centerY - radius/2, Color.DARK_GRAY,
centerX + radius/2, centerY + radius/2, Color.BLACK
);
g2d.setPaint(gradient);
g2d.fill(new Ellipse2D.Double(centerX - radius, centerY - radius, radius*2, radius*2));
白色棋子:

g2d.setColor(Color.WHITE); g2d.fill(new Ellipse2D.Double(centerX - radius, centerY - radius, radius*2, radius*2));
鼠标交互实现
通过添加鼠标事件监听器实现点击落子功能:
boardPanel.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
// 计算点击位置对应的棋盘坐标
int x = (e.getX() - MARGIN + GRID_SIZE / 2) / GRID_SIZE;
int y = (e.getY() - MARGIN + GRID_SIZE / 2) / GRID_SIZE;
// 落子逻辑
if (isValidPosition(x, y)) {
board[x][y] = isBlackTurn ? Piece.BLACK : Piece.WHITE;
// 更新界面状态
}
}
});
游戏状态管理
使用二维数组存储棋盘状态,记录落子历史:
private Piece[][] board = new Piece[BOARD_SIZE][BOARD_SIZE]; private List<Point> moveHistory = new ArrayList<>();
使用指南
- 运行程序后,将显示一个15×15的围棋棋盘
- 黑色方先行,点击交叉点放置棋子
- 落子后自动切换玩家
- 状态栏显示当前回合信息
- 点击”重新开始”按钮重置棋盘
扩展建议
- 游戏规则实现:添加围棋规则判定(如提子、禁着点等)
- 保存/加载功能:实现棋局保存和读取
- AI对手:添加简单的人工智能实现人机对战
- 网络对战:通过Socket编程实现网络对战功能
此实现使用了Java Swing框架进行图形界面开发,遵循了面向对象的设计原则,代码结构清晰,可扩展性强。

参考资料
- Java官方Swing教程:https://docs.oracle.com/javase/tutorial/uiswing/
- Java 2D图形编程指南:https://docs.oracle.com/javase/tutorial/2d/index.html
- 《Java核心技术卷I》第10章 – 图形程序设计
本文提供的代码在Java 8及以上环境测试通过,使用Swing图形库实现棋盘棋子的绘制和交互功能。
