5

我已经读过我永远不应该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

4 回答 4

8

官方文档WM_PAINT声明您不应该在备注部分的第一句话中。说真的,这应该足以成为不这样做的理由。

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

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

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

可能还有更多的原因/惊喜。

于 2014-03-16T16:58:54.820 回答
6

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

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

  2. 使用RedrawWindow().

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

于 2014-03-16T22:38:58.450 回答
2

您没有关于其他程序的窗口的任何信息来发现您的窗口。只有操作系统有这个信息。所以你并不知道你的窗户何时何地需要重新粉刷。WM_PAINT 和 BeginPaint 提供了这个缺失的信息。

于 2014-03-16T17:21:47.390 回答
1

因为WM_PAINT不是真正的消息。

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

该无效区域由窗口管理器本身(调整窗口大小、未覆盖等)或通过调用InvalidateRectValidateRect等进行修改EndPaint

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

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

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

于 2015-04-24T09:57:22.457 回答