为什么不手动发送WM_PAINT

时间:2014-03-16 14:48:44

标签: c++ winapi windows-messages wm-paint

我已经读过,我不应该手动发送WM_PAINT,而是应该调用InvalidateRect,但是没有找到任何关于原因的信息。那为什么不呢?

更新适用于InvalidateRect,但不适用于SendMessage(WM_PAINT)

LRESULT CALLBACK window_proc(HWND wnd, UINT msg, WPARAM w_param, LPARAM l_param)
{
  switch (msg)
  {
    case WM_PAINT:
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(wnd, &ps);

        Polyline(..);

        EndPaint(wnd, &ps);
        return 0;

    case WM_USER:           
        // SendMessage(wnd, WM_PAINT, NULL, NULL);
        // InvalidateRect(wnd, NULL, FALSE);

        return 0;
  }
}

4 个答案:

答案 0 :(得分:5)

WM_PAINT的官方文档声明您不应该在备注部分的第一句话中。说真的,这应该是没有理由的原因。

至于技术原因,我想这是其中之一,取自BeginPaint备注部分:

  

更新区域由 InvalidateRect InvalidateRgn 功能以及系统调整,移动,创建,滚动或影响客户区的任何其他操作后设置

如果您手动发送BeginPaintWM_PAINT可能无法正常工作。

可能有更多原因/意外。

答案 1 :(得分:3)

如果您想触发立即重绘,正确的方法是:

  1. 使用InvalidateRect()后跟UpdateWindow()

  2. 使用RedrawWindow()

  3. 这些将触发生成新的WM_PAINT消息。

答案 2 :(得分:2)

您没有任何关于其他程序窗口的信息,无法揭开您的窗口。只有操作系统才有此信息。因此,您无需知道窗口何时何地需要重新绘制。 WM_PAINT和BeginPaint提供了这个缺失的信息。

答案 3 :(得分:1)

因为WM_PAINT不是真实的信息。

可以想象每个窗口都有一个存储“无效区域”的结构,也就是说,“屏幕上窗口的这一部分不再是最新的,需要重新绘制”。

窗口管理器本身(窗口已调整大小,未覆盖等)或通过调用InvalidateRectValidateRectEndPaint等修改了无效区域。

现在,这是GetMessage如何处理这个问题的粗略模型:

... GetMessage(MSG* msg, ...)
{
  while(true) {
    if(ThereIsAnyMessageInTheMessageQueue()) {
      *msg = GetFirstMessageOfTheMessageQueue();
      return ...;
    } else if(TheInvalidRegionIsNotEmpty()) {
      *msg = CreateWMPaintMessage();
      return ...;
    } else {
      WaitUntilSomethingHappend();
    }
  }
}

tl; dr:WM_PAINT意味着收到,而不是发送。