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。