繁体   English   中英

为什么不手动发送WM_PAINT

[英]why not to send WM_PAINT manually

我已经读过,我不应该手动发送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;
  }
}

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

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

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

因此,如果手动发送WM_PAINT BeginPaint可能无法正常工作。

可能有更多原因/意外。

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

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

  2. 使用RedrawWindow()

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

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

因为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意在接收,而不是发送。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM