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

C++ GUI井字棋重置后残留旧图形问题技术咨询

解决井字棋重置后旧图形残留的问题

你遇到的核心问题是重置棋盘数据后,旧的X/O图案没有被完全清除,依然残留在窗口上。这主要是因为你的WM_PAINT逻辑没有先清除旧绘制内容,加上棋盘线条的绘制方式有误,导致无法覆盖旧棋子。下面是具体的解决思路和修改后的代码:

问题根源分析

  1. 未主动清除背景:每次触发WM_PAINT时,系统不会自动擦除之前绘制的像素,如果你不主动覆盖旧内容,残留的X/O就会一直显示。
  2. 棋盘线条绘制错误:你用多个Rectangle绘制棋盘的方式不对,这些矩形会填充区域而非绘制分隔线,根本起不到覆盖旧棋子的作用。
  3. 重绘参数不完整:仅使用RDW_INVALIDATE可能不会强制触发背景擦除,需要补充参数确保旧内容被清除。

具体解决方案

1. 在WM_PAINT中先清除整个客户区背景

调用FillRect用窗口默认背景色填充整个客户区,彻底覆盖旧绘制内容:

RECT clientRect;
GetClientRect(hwnd, &clientRect);
FillRect(hdc, &clientRect, (HBRUSH)(COLOR_WINDOW + 1));

2. 修正棋盘分隔线的绘制逻辑

用MoveToEx和LineTo绘制竖线和横线,替代原来错误的Rectangle调用,这样才能画出正确的井字棋分隔线:

// 绘制棋盘外边框
Rectangle(hdc, 0, 0, 600, 600);
// 绘制竖分隔线
MoveToEx(hdc, 200, 0, NULL);
LineTo(hdc, 200, 600);
MoveToEx(hdc, 400, 0, NULL);
LineTo(hdc, 400, 600);
// 绘制横分隔线
MoveToEx(hdc, 0, 200, NULL);
LineTo(hdc, 600, 200);
MoveToEx(hdc, 0, 400, NULL);
LineTo(hdc, 600, 400);

3. 完善RedrawWindow的参数

加上RDW_ERASE标志,确保重绘时强制擦除背景:

RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE | RDW_ERASE);

完整修改后的代码片段

switch( message ) {
case WM_PAINT: {
    HDC hdc;
    PAINTSTRUCT ps;
    hdc = BeginPaint( hwnd, &ps );
    
    // 第一步:清除整个客户区背景,覆盖旧内容
    RECT clientRect;
    GetClientRect(hwnd, &clientRect);
    FillRect(hdc, &clientRect, (HBRUSH)(COLOR_WINDOW + 1));
    
    // 第二步:绘制正确的棋盘分隔线
    Rectangle(hdc, 0, 0, 600, 600); // 外边框
    // 竖线
    MoveToEx(hdc, 200, 0, NULL);
    LineTo(hdc, 200, 600);
    MoveToEx(hdc, 400, 0, NULL);
    LineTo(hdc, 400, 600);
    // 横线
    MoveToEx(hdc, 0, 200, NULL);
    LineTo(hdc, 600, 200);
    MoveToEx(hdc, 0, 400, NULL);
    LineTo(hdc, 600, 400);
    
    // 第三步:绘制棋子(加了10像素内边距,避免紧贴边框)
    for(int i = 0; i < 3; i++) {
        for(int j = 0; j < 3; j++) {
            if(CP[i][j] == 1) {
                Ellipse(hdc, 200 * i + 10, 200 * j + 10, 200 * (i + 1) - 10, 200 * (j + 1) - 10);
            }
            if(CP[i][j] == 2) {
                MoveToEx(hdc, 200 * i + 10, 200 * j + 10, NULL);
                LineTo(hdc, 200 * (i + 1) - 10, 200 * (j + 1) - 10);
                MoveToEx(hdc, 200 * (i + 1) - 10, 200 * j + 10, NULL);
                LineTo(hdc, 200 * i + 10, 200 * (j + 1) - 10);
            }
        }
    }
    
    EndPaint( hwnd, &ps );
}
return 0;
break;
case WM_KEYDOWN:
    // 重置CP数组为全0
    for(int b = 0; b < 3; b++) {
        for(int c = 0; c < 3; c++) {
            CP[c][b] = 0;
        }
    }
    std::cout << "RESET\n";
    // 强制重绘并擦除背景
    RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE | RDW_ERASE);
    turn = 1;
break;

我还给棋子绘制加了10像素的内边距,让O和X不会紧贴格子边框,视觉效果更舒服,你可以根据需求调整这个数值。

内容的提问来源于stack exchange,提问作者wojciech-graj

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:03:49