You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用C#在跳棋棋盘上绘制圆形棋子并解决绘制不显示问题

问题原因

你绘制的棋子不显示是两个核心问题导致的:

  • CreateGraphics 生成的绘制内容是临时的,只要控件触发重绘(比如窗体加载完成后首次渲染、窗口大小变动、被其他窗口遮挡后恢复)就会被完全清空
  • 你在将Panel加入窗体控件集合之前就调用了绘制操作,此时控件尚未完成初始化,绘制内容不会生效
修复后的可运行代码
using System;
using System.Drawing;
using System.Windows.Forms;

namespace Checkers
{
    public partial class Form1 : Form
    {
        private Panel[,] _chessBoardPanels;
        // 定义棋子颜色常量
        private readonly Brush _blackPieceBrush = Brushes.Black;
        private readonly Brush _redPieceBrush = Brushes.Red;
        private readonly Pen _pieceBorderPen = new Pen(Color.White, 2);
        private const int tileSize = 100;
        private const int gridSize = 8;

        public Form1()
        {
            InitializeComponent();
            // 调整窗体大小适配棋盘
            this.ClientSize = new Size(tileSize * gridSize, tileSize * gridSize);
            this.FormBorderStyle = FormBorderStyle.FixedSingle;
            this.MaximizeBox = false;
        }

        public static void DrawCircle(Graphics g, Pen pen, float centerX, float centerY, float radius)
        {
            g.DrawEllipse(pen, centerX - radius, centerY - radius, radius * 2, radius * 2);
        }

        public static void FillCircle(Graphics g, Brush b, float centerX, float centerY, float radius)
        {
            g.FillEllipse(b, centerX - radius, centerY - radius, radius * 2, radius * 2);
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            var clr1 = Color.DarkGray;
            var clr2 = Color.White;
            _chessBoardPanels = new Panel[gridSize, gridSize];

            for (int n = 0; n < gridSize; n++)
            {
                for (int m = 0; m < gridSize; m++)
                {
                    var newPanel = new Panel
                    {
                        Size = new Size(tileSize, tileSize),
                        Location = new Point(tileSize * n, tileSize * m),
                        Tag = new Point(n, m) // 存储当前格子坐标,后续移动棋子用
                    };

                    // 绑定Paint事件,所有绘制逻辑放这里
                    newPanel.Paint += (s, pe) =>
                    {
                        Point pos = (Point)((Panel)s).Tag;
                        int x = pos.X;
                        int y = pos.Y;

                        // 跳棋规则:仅在深色格子上放置棋子,前三行放黑棋,后三行放红棋
                        if ((x + y) % 2 == 1)
                        {
                            float cx = tileSize / 2f;
                            float cy = tileSize / 2f;
                            float radius = cx * 0.4f; // 留边避免贴格子边缘
                            if (y < 3)
                            {
                                FillCircle(pe.Graphics, _blackPieceBrush, cx, cy, radius);
                                DrawCircle(pe.Graphics, _pieceBorderPen, cx, cy, radius);
                            }
                            else if (y > 4)
                            {
                                FillCircle(pe.Graphics, _redPieceBrush, cx, cy, radius);
                                DrawCircle(pe.Graphics, _pieceBorderPen, cx, cy, radius);
                            }
                        }
                    };

                    Controls.Add(newPanel);
                    _chessBoardPanels[n, m] = newPanel;

                    // 设置背景色
                    newPanel.BackColor = (n + m) % 2 == 0 ? clr2 : clr1;
                }
            }
        }
    }
}
面向对象实现思路

新增CheckersPiece类封装棋子属性和行为,降低界面逻辑和业务逻辑的耦合:

public class CheckersPiece
{
    // 棋子所在格子坐标
    public int Row { get; set; }
    public int Column { get; set; }
    // 棋子颜色
    public Color PieceColor { get; set; }
    // 是否是王棋
    public bool IsKing { get; set; }

    // 移动方法,返回移动是否合法
    public bool Move(int targetRow, int targetColumn, Panel[,] board)
    {
        // 这里补充移动规则判断逻辑,比如是否走斜向、是否跳吃、是否越界等
        if (Math.Abs(targetRow - Row) == 1 && Math.Abs(targetColumn - Column) == 1)
        {
            // 普通移动逻辑
            Row = targetRow;
            Column = targetColumn;
            return true;
        }
        // 跳吃逻辑自行补充
        return false;
    }

    // 渲染方法,将棋子绘制到对应格子
    public void Draw(Graphics g, int tileSize)
    {
        float cx = tileSize / 2f;
        float cy = tileSize / 2f;
        float radius = cx * 0.4f;
        using (Brush brush = new SolidBrush(PieceColor))
        {
            g.FillEllipse(brush, cx - radius, cy - radius, radius * 2, radius * 2);
        }
        using (Pen pen = new Pen(Color.White, 2))
        {
            g.DrawEllipse(pen, cx - radius, cy - radius, radius * 2, radius * 2);
        }
        // 王棋额外加标记
        if (IsKing)
        {
            g.DrawString("王", SystemFonts.DefaultFont, Brushes.Gold, new PointF(cx - 10, cy - 10));
        }
    }
}

后续你只需要在Form中维护一个CheckersPiece[,]数组存储所有棋子对象,棋子状态变化后调用对应Panel的Invalidate()方法触发重绘即可。

内容的提问来源于stack exchange,提问作者user16612111

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 20:36:02