无法将可重用代码放入子例程
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;
这比我的好多了。
我试图更好地理解 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;
这比我的好多了。