why not to send WM_PAINT manually

99封情书 提交于 2019-12-18 07:16:10

问题


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. So why not?

update works with InvalidateRect but not with 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;
  }
}

回答1:


Official docs for WM_PAINT state that you shouldn't in the very first sentence of the remarks section. 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:

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.

Thus BeginPaint might not work correctly if you send WM_PAINT manually.

There might be more reasons/surprises.




回答2:


If you want to trigger an immediate repaint, the correct approach is to either:

  1. Use InvalidateRect() followed by UpdateWindow().

  2. Use RedrawWindow().

Those will trigger a new WM_PAINT message to be generated.




回答3:


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.




回答4:


Because WM_PAINT is not a real message.

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.

Now, here is a crude mock-up of how GetMessage handles this :

... 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.



来源:https://stackoverflow.com/questions/22438365/why-not-to-send-wm-paint-manually

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!