将可重用代码放入子例程

时间:2015-07-01 07:58:58

标签: c++ visual-c++ bitblt

我试图更好地理解Visual C ++的怪癖。因此,我来​​到舞台,我制作一个以空窗口开始的程序,但当你点击时,会出现一个红色和蓝色方块的检查板(它对眼睛不好,但是有用)。如果再次单击它们,方块也会在两种颜色之间切换。每个正方形是100x100像素,我在我的项目文件夹中有他们的图像文件(我知道我可以使用BitBlt的最后两个整数agruments来使用半蓝色,半红色的单个图像,因此不需要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;
    }

现在,每当我调整窗口大小时,无论是最大化还是只是拖动边缘,一切都会被重新绘制,并且由于只存储了一个左键单击,它只会绘制一个正方形,其余的将返回默认为灰色。因此,我决定抓住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;

正如您所看到的,在第一次for - 测试之后,最内层if - 循环内的所有内容或多或少都与我WM_PAINT案例中的内容完全相同,我认为这是一个好的迹象,这些行应该放入自己的函数调用,如DrawSquare(HWND hWnd, int i, int j, HDC handle, PAINTSTRUCT ps)。但是,我无法弄清楚如何导航所有指针,引用和副本。我可以得到一些可以编译的东西,但之后它就不会画任何东西。

我怎么写这样的DrawSquare()

1 个答案:

答案 0 :(得分:1)

嗯,这比我预想的要容易。使用

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;

这比我的好多了。