简体   繁体   English

为什么不手动发送WM_PAINT

[英]why not to send WM_PAINT manually

I have read that I should never send WM_PAINT manually and should call InvalidateRect instead but didn't found anything about why not, however. 我已经读过,我不应该手动发送WM_PAINT ,而是应该调用InvalidateRect但是没有找到任何关于为什么不能找到的东西。 So why not? 那为什么不呢?

update works with InvalidateRect but not with SendMessage(WM_PAINT) 更新适用于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;
  }
}

Official docs for WM_PAINT state that you shouldn't in the very first sentence of the remarks section. WM_PAINT官方文档声明您不应该在备注部分的第一句中。 Seriously, that should be enough of a reason not to. 说真的,这应该是没有理由的。

As for technical reasons why, I guess this is one of them, taken from BeginPaint remarks section: 至于技术原因,我猜这是其中之一,取自BeginPaint备注部分:

The update region is set by the InvalidateRect or InvalidateRgn function and by the system after sizing, moving, creating, scrolling, or any other operation that affects the client area. 更新区域由InvalidateRectInvalidateRgn函数以及系统调整,移动,创建,滚动或影响客户区域的任何其他操作后设置。

Thus BeginPaint might not work correctly if you send WM_PAINT manually. 因此,如果手动发送WM_PAINT BeginPaint可能无法正常工作。

There might be more reasons/surprises. 可能有更多原因/意外。

If you want to trigger an immediate repaint, the correct approach is to either: 如果要触发立即重绘,正确的方法是:

  1. Use InvalidateRect() followed by UpdateWindow() . 使用InvalidateRect()然后使用UpdateWindow()

  2. Use RedrawWindow() . 使用RedrawWindow()

Those will trigger a new WM_PAINT message to be generated. 这些将触发生成新的WM_PAINT消息。

You don't have any information about other program's windows uncovering your windows. 您没有任何关于其他程序的窗口的信息来揭开您的窗口。 Only the operating system has this information. 只有操作系统才有此信息。 So you don't really know all the time when or where your window needs to be repainted. 因此,您并不总是知道窗口何时何地需要重新绘制。 WM_PAINT and BeginPaint provide this missing information. WM_PAINT和BeginPaint提供了这个缺失的信息。

Because WM_PAINT is not a real message. 因为WM_PAINT不是真正的消息。

Think of it like each window has a structure storing an "invalid region", that is, "this part of the window on the screen is not up to date anymore and need to be repainted". 可以想象它就像每个窗口都有一个存储“无效区域”的结构,也就是说,“屏幕上窗口的这一部分不再是最新的,需要重新绘制”。

That invalid region is modified by the window manager itself (window is resized, uncovered, etc ), or by calls to InvalidateRect , ValidateRect , EndPaint and such. 该无效区域由窗口管理器本身修改(窗口调整大小,未覆盖等),或者调用InvalidateRectValidateRectEndPaint等。

Now, here is a crude mock-up of how GetMessage handles this : 现在,这里是GetMessage如何处理这个问题的粗略模型:

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

tl;dr: WM_PAINT is meant to be received, not sent. tl; dr: WM_PAINT意在接收,而不是发送。

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

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