无法将可重用代码放入子例程

Having trouble putting reusable code into a subroutine

我试图更好地理解 Visual C++ 的怪癖。因此,我已经到了制作一个程序的阶段,该程序开始时是一个空的 window,但是当您四处点击时,会出现一个由红色和蓝色方块组成的检查板(这对眼睛不好,但是有用)。如果您再次单击这些方块,它们也会在两种颜色之间交替。每个正方形都是 100x100 像素,我的项目文件夹中有它们的图像文件(我知道我可以使用 BitBlt 的最后两个整数参数来使用半蓝半红的单个图像,因此不需要 toPaint,但这不是这里的问题)

这就是我的绘画例程现在的样子(而且效果很好,这里没有声明的都是全局变量):

case WM_PAINT:
    {
    // 'HDC hdc' declared before the switch statement
    // 'PAINTSTRUCT ps' declared before the switch statement
    // 'hWnd' is the first argument to WndProc()
    hdc = BeginPaint(hWnd, &ps); 

    HBITMAP toPaint = NULL;
    BITMAP bm;

    // 'xcor' and 'ycor' are the coordinates of the last left-click
    // 'int counters[][]' keeps track of the number of left-clicks in each square
    // 'blue' and 'red' are HBITMAPs initialized in case WM_CREATE
    if (counters[xcor / 100][ycor / 100] % 2 == (xcor / 100 + ycor / 100) % 2)
        toPaint = blue;
    else
        toPaint = red;

    HDC hdcMem = CreateCompatibleDC(hdc);
    HGDIOBJ hbmOld = SelectObject(hdcMem, toPaint);
    GetObject(toPaint, sizeof(bm), &bm);
    BitBlt(hdc, xcor - xcor % 100, ycor - ycor % 100, 100, 100, hdcMem, 0, 0, SRCCOPY);
    SelectObject(hdcMem, hbmOld);

    EndPaint(hWnd, &ps);

    break;
    }

现在,每当我调整 window 的大小时,无论是最大化,还是只是拖动边缘,所有东西都会被重新绘制,而且由于只存储了一次左键单击,它只会绘制一个正方形,其余的将恢复为默认灰色。因此,我决定抓住 WM_SIZE 的情况,并重新绘制到那时已经绘制的所有正方形:

case WM_SIZE:

    hdc = BeginPaint(hWnd, &ps);
    for (int i = 0; i < 20; i++)
    {
        for (int j = 0; j < 20; j++)
        {
            // checks whether that square has been drawn before
            if (counters[i][j] == 0)
                continue;

            HBITMAP toPaint = NULL;
            BITMAP bm;
            if (counters[i][j] % 2 == (i + j) % 2)
                toPaint = blue;
            else
                toPaint = red;

            HDC hdcMem = CreateCompatibleDC(hdc);
            HGDIOBJ hbmOld = SelectObject(hdcMem, toPaint);
            GetObject(toPaint, sizeof(bm), &bm);
            BitBlt(hdc, i*100, j*100, 100, 100, hdcMem, 0, 0, SRCCOPY);
            SelectObject(hdcMem, hbmOld);


        }
    }
    EndPaint(hWnd, &ps);

    break;

如您所见,在第一个 if-test 之后,最内层 for-loop 中的所有内容都或多或少与我在 WM_PAINT 中的内容完全相同] 案例,我认为这是一个好兆头,表明这些行应该放入其自己的函数调用中,例如 DrawSquare(HWND hWnd, int i, int j, HDC handle, PAINTSTRUCT ps)。但是,我不知道如何浏览所有指针、引用和副本。我可以得到一些可以编译的东西,但是它不会绘制任何东西。

我怎么写这样的DrawSquare()

好吧,这比我预期的要容易。使用

void DrawSquare(HWND hWnd, HDC hdc, int x, int y)
{
    HBITMAP toPaint = NULL;
    BITMAP bm;
    if (counters[x][y] % 2 == (x + y) % 2)
        toPaint = blue;
    else
        toPaint = red;

    HDC hdcMem = CreateCompatibleDC(hdc);
    HGDIOBJ hbmOld = SelectObject(hdcMem, toPaint);
    GetObject(toPaint, sizeof(bm), &bm);
    BitBlt(hdc, x * 100, y * 100, 100, 100, hdcMem, 0, 0, SRCCOPY);
    SelectObject(hdcMem, hbmOld);

    // Thanks to the comment below, to avoid memory leak
    DeleteDC(hdcMem);
}

没有 PAINTSTRUCT 工作得很好(因为我没有明确使用它)。现在我的案例是这样的:

case WM_PAINT:
    hdc = BeginPaint(hWnd, &ps);
    DrawSquare(hWnd, hdc, xcor / 100, ycor / 100);

    EndPaint(hWnd, &ps);

    break;

case WM_SIZE:

    hdc = BeginPaint(hWnd, &ps);
    for (int i = 0; i < 20; i++)
    {
        for (int j = 0; j < 20; j++)
        {
            if (counters[i][j] == 0)
                continue;
            DrawSquare(hWnd, hdc, i, j);

        }
    }
    EndPaint(hWnd, &ps);

    break;

这比我的好多了。