C++ 画线不行,可能有什么问题?
我想通过在第一个坐标上单击鼠标来画线,第一个坐标是线的起点,第二个坐标是线的终点。 当我运行我的项目时,什么都没有发生。 我无法找到我的代码丢失了什么C++ 画线不行,可能有什么问题?,c++,winapi,C++,Winapi,我想通过在第一个坐标上单击鼠标来画线,第一个坐标是线的起点,第二个坐标是线的终点。 当我运行我的项目时,什么都没有发生。 我无法找到我的代码丢失了什么 LONG WINAPI WndProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam) { HDC hdc; BOOL fDraw = FALSE; POINT ptPrevious = { 0 }; HPEN Pen = CreatePen(PS_S
LONG WINAPI WndProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
BOOL fDraw = FALSE;
POINT ptPrevious = { 0 };
HPEN Pen = CreatePen(PS_SOLID, 3, RGB(0, 0, 255));
switch (Message) {
case WM_LBUTTONDOWN: {
fDraw = TRUE;
ptPrevious.x = LOWORD(lParam);
ptPrevious.y = HIWORD(lParam);
break;
}
case WM_LBUTTONUP: {
if (fDraw)
{
hdc = GetDC(hWnd);
MoveToEx(hdc, ptPrevious.x, ptPrevious.y, NULL);
LineTo(hdc, LOWORD(lParam), HIWORD(lParam));
ReleaseDC(hWnd, hdc);
}
fDraw = FALSE;
break;
}
case WM_MOUSEMOVE: {
if (fDraw)
{
hdc = GetDC(hWnd);
MoveToEx(hdc, ptPrevious.x, ptPrevious.y, NULL);
LineTo(hdc, ptPrevious.x = LOWORD(lParam),
ptPrevious.y = HIWORD(lParam));
ReleaseDC(hWnd, hdc);
}
break;
}
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, Message, wParam, lParam);
}
return 0;
}
不要三次获取DC,获取一次并在鼠标上释放。
此外,您的绘图最终将被验证,因此您需要记录鼠标移动并在WM_PAINT handler中重复这些内容。不要三次获取DC,获取一次,然后在鼠标向上移动时释放。
此外,您的绘图最终将被验证,因此您需要记录鼠标移动并在WM_PAINT handler中重复这些内容。从根本上说,问题在于您的任何数据都不是持久的。由于它们都是局部变量,当WndProc返回时,它们的内容将消失。fDraw在每条消息上都设置为FALSE,对于WM_LBUTTONDOWN或WM_MOUSEMOVE消息,fDraw永远不会为true。因此什么也没有发生 您需要创建一个类来保存fDraw、ptPrevious和一个结构来保存要绘制的线的坐标。在WM_MOUSEMOVE和WM_LBUTTONUP消息中使用无效设置。然后仅使用PAINT消息中提供的DC绘制它们以响应WM_PAINT消息
使用MFC类可以大大简化这些任务。从根本上说,问题在于没有数据是持久的。由于它们都是局部变量,当WndProc返回时,它们的内容将消失。fDraw在每条消息上都设置为FALSE,对于WM_LBUTTONDOWN或WM_MOUSEMOVE消息,fDraw永远不会为true。因此什么也没有发生 您需要创建一个类来保存fDraw、ptPrevious和一个结构来保存要绘制的线的坐标。在WM_MOUSEMOVE和WM_LBUTTONUP消息中使用无效设置。然后仅使用PAINT消息中提供的DC绘制它们以响应WM_PAINT消息
使用MFC类可以大大简化这些任务。因为声明的变量是局部变量,所以可以使用静态变量声明变量
static BOOL fDraw = FALSE;
static POINT ptPrevious = { 0 };
此外,您忘记使用SelectObject功能将笔选择到DC
您还可以使用WM_PAINT重画来改进代码:
例如:
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
static BOOL fDraw = FALSE;
static BOOL fDraw_begin = FALSE;
static POINT ptPrevious;
static RECT rcClient;
static POINT pt;
static HPEN Pen;
switch (message)
{
case WM_CREATE:
{
Pen = CreatePen(PS_SOLID, 3, RGB(255, 0, 0));
break;
}
case WM_LBUTTONDOWN:
{
ptPrevious.x = (LONG)LOWORD(lParam);
ptPrevious.y = (LONG)HIWORD(lParam);
return 0;
}
case WM_LBUTTONUP:
{
if (fDraw = TRUE)
{
fDraw = FALSE;
fDraw_begin = TRUE;
InvalidateRect(hwnd, &rcClient, TRUE);
UpdateWindow(hwnd);
}
return 0;
}
case WM_MOUSEMOVE:
{
if (wParam && MK_LBUTTON)
{
GetClientRect(hwnd, &rcClient);
hdc = GetDC(hwnd);
SetROP2(hdc, R2_NOTXORPEN);
if (!IsRectEmpty(&rcClient)) // Detecting whether the rectangular area is empty
{
MoveToEx(hdc, ptPrevious.x, ptPrevious.y, NULL);
LineTo(hdc, (LONG)LOWORD(lParam),
(LONG)HIWORD(lParam));
}
MoveToEx(hdc, ptPrevious.x, ptPrevious.y, NULL);
LineTo(hdc, (LONG)LOWORD(lParam),
(LONG)HIWORD(lParam));
pt.x = (LONG)LOWORD(lParam);
pt.y = (LONG)HIWORD(lParam);
fDraw = TRUE;
ReleaseDC(hwnd, hdc);
}
return 0;
}
case WM_PAINT:
{
hdc = BeginPaint(hwnd, &ps);
SelectObject(hdc, Pen);
if (fDraw_begin)
{
fDraw_begin = FALSE;
MoveToEx(hdc, ptPrevious.x, ptPrevious.y, NULL);
LineTo(hdc, pt.x,
pt.y);
}
EndPaint(hwnd, &ps);
ReleaseDC(hwnd, hdc);
return 0;
}
case WM_DESTROY:
{
DeleteObject(Pen);
PostQuitMessage(0);
return 0;
}
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
因为声明的变量是局部变量,所以可以使用静态变量声明变量
static BOOL fDraw = FALSE;
static POINT ptPrevious = { 0 };
此外,您忘记使用SelectObject功能将笔选择到DC
您还可以使用WM_PAINT重画来改进代码:
例如:
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
static BOOL fDraw = FALSE;
static BOOL fDraw_begin = FALSE;
static POINT ptPrevious;
static RECT rcClient;
static POINT pt;
static HPEN Pen;
switch (message)
{
case WM_CREATE:
{
Pen = CreatePen(PS_SOLID, 3, RGB(255, 0, 0));
break;
}
case WM_LBUTTONDOWN:
{
ptPrevious.x = (LONG)LOWORD(lParam);
ptPrevious.y = (LONG)HIWORD(lParam);
return 0;
}
case WM_LBUTTONUP:
{
if (fDraw = TRUE)
{
fDraw = FALSE;
fDraw_begin = TRUE;
InvalidateRect(hwnd, &rcClient, TRUE);
UpdateWindow(hwnd);
}
return 0;
}
case WM_MOUSEMOVE:
{
if (wParam && MK_LBUTTON)
{
GetClientRect(hwnd, &rcClient);
hdc = GetDC(hwnd);
SetROP2(hdc, R2_NOTXORPEN);
if (!IsRectEmpty(&rcClient)) // Detecting whether the rectangular area is empty
{
MoveToEx(hdc, ptPrevious.x, ptPrevious.y, NULL);
LineTo(hdc, (LONG)LOWORD(lParam),
(LONG)HIWORD(lParam));
}
MoveToEx(hdc, ptPrevious.x, ptPrevious.y, NULL);
LineTo(hdc, (LONG)LOWORD(lParam),
(LONG)HIWORD(lParam));
pt.x = (LONG)LOWORD(lParam);
pt.y = (LONG)HIWORD(lParam);
fDraw = TRUE;
ReleaseDC(hwnd, hdc);
}
return 0;
}
case WM_PAINT:
{
hdc = BeginPaint(hwnd, &ps);
SelectObject(hdc, Pen);
if (fDraw_begin)
{
fDraw_begin = FALSE;
MoveToEx(hdc, ptPrevious.x, ptPrevious.y, NULL);
LineTo(hdc, pt.x,
pt.y);
}
EndPaint(hwnd, &ps);
ReleaseDC(hwnd, hdc);
return 0;
}
case WM_DESTROY:
{
DeleteObject(Pen);
PostQuitMessage(0);
return 0;
}
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
那么我可以在switch语句之外声明DC吗?我可以用WM_PAINT而不是WM_MOUSEMOVE吗?在通用Windows应用程序中,绘图是根据WM_PAINT完成的。绘图不会持久。这意味着,如果窗口最小化,下一个最大化将不会显示您之前绘制的内容。这就是为什么在Windows请求时绘制它,也就是说,在WM_PAINT中。在进行实时绘制时,您可以使用GetDC获取DC,但也可以保存您在案例中绘制的东西,即开始/结束xy,并使用内存DC重复它以响应WM_PAINT。因此,您可以在WM_LBUTTONDOWN上使用GetDC,但将dc保存到WM_LBUTTONUP。然后记录您在WM_PAINT中重新绘制的内容。那么我可以在switch语句之外声明DC吗?我可以用WM_PAINT而不是WM_MOUSEMOVE吗?在通用Windows应用程序中,绘图是根据WM_PAINT完成的。绘图不会持久。这意味着,如果窗口最小化,下一个最大化将不会显示您之前绘制的内容。这就是为什么在Windows请求时绘制它,也就是说,在WM_PAINT中。在进行实时绘制时,您可以使用GetDC获取DC,但也可以保存您在案例中绘制的东西,即开始/结束xy,并使用内存DC重复它以响应WM_PAINT。因此,您可以在WM_LBUTTONDOWN上使用GetDC,但将dc保存到WM_LBUTTONUP。然后记录所绘制的内容以在WM_PAINT中重新绘制。绘制到屏幕外位图,然后将其绘制到屏幕WM_PAINT。绘制到屏幕外位图,然后将其绘制到屏幕WM_PAINT。