【问题标题】:How does "BeginPaint" function know the update region - windows programming?“BeginPaint”函数如何知道更新区域——windows编程?
【发布时间】:2015-10-10 08:23:18
【问题描述】:

我是 Windows 编程新手,我有一个关于绘制窗口的问题,特别是关于 BeginPaint 函数的问题

当我在 MSDN 上读到它时,它说

通过调用 BeginPaint 函数开始绘画操作。此函数使用有关重绘请求的信息填充 PAINTSTRUCT 结构。当前更新区域在 PAINTSTRUCT 的 rcPaint 成员中给出。

我的问题是,当我在 wndproc 中处理 WM_PAINT 消息并通过调用 BeginPaint 函数开始时,我没有向此函数提供有关我收到的特定消息或需要的更新区域的任何数据待画,那么这个函数如何填充PAINTSTRUCT,包括无效的矩形“rcPaint成员”?!

    case WM_PAINT:
    {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hwnd, &ps);
        // All painting occurs here, between BeginPaint and EndPaint.
        EndPaint(hwnd, &ps);
    }

当我在 MSDN 上引用 BeginPaint 函数时,它说

应用程序不应调用 BeginPaint,除非响应 WM_PAINT 消息

我的猜测可能是这个函数在内部从 Windows 获取这些信息 通过请求此信息和发送到窗口的最后一条 WM_PAINT 消息,我将它的句柄“`hwnd'”作为函数的第一个参数传递。对吗?

提前致谢。

【问题讨论】:

标签: c++ windows winapi


【解决方案1】:

我怀疑这在任何地方都有记录,因为它是与程序员无关的实现细节,但我很确定更新区域是与 HWND 一起存储的内部数据结构。您可以知道,因为有几个函数仅基于 HWND 对更新区域进行操作:[In]ValidateRect、[In]ValidateRgn、GetUpdateRgn、BeginPaint 等。

【讨论】:

    【解决方案2】:

    Windows 为每个窗口维护一个内部数据结构,其中包含其无效区域。 PAINTSTRUCT 结构的 RECT 成员设置为等于该矩形(包含无效区域的最小矩形)。正如 user1610015 已经指出的那样,这不是程序员通常关心的事情。

    当你打电话时

    hdc = BeginPaint(hwnd, &ps);
    

    PAINTSTRUCTURE 结构的 RECT 结构被更新为无效矩形。

    我的猜测可能是这个函数通过请求这个信息和最后一个发送到窗口的 WM_PAINT 消息从 Windows 内部获取这个信息,我将它的句柄“`hwnd'”作为第一个参数传递给函数。对吗?

    Windows 不会在消息队列中放置多个 WM_PAINT 消息。相反,它会不断更新窗口更新区域。例如,如果您在消息队列中已经有一条 WM_PAINT 消息,并且在此消息被调用从队列中删除之前

    GetMessage(&msg, NULL, 0, 0)
    

    ,您验证/更改更新区域(例如通过 ValidateRect)然后 Windows 更新内部更新区域为窗口保留。如果您对 ValidateRect 的调用验证了整个无效区域,则 WM_PAINT 消息将从消息队列中删除,而不会被处理。

    此外,当你打电话时

    hdc = BeginPaint(hwnd, &ps);
    

    您获得的设备上下文 (DC) 包含一个默认矩形剪切区域,该区域等于无效矩形(与 PAINSTRUCT 中的 rcPaint 设置为相等的矩形相同)。您不能在剪辑区域之外进行绘制。 例如,您可以使用

    偏移剪辑区域
    // This does not change the update region for the window
    // This changes the clipping region associated with the DC hdc
    OffsetClipRgn(hdc, xOffset, yOffset);
    

    总而言之,无效区域不一定等于剪切区域(但通常是因为 BeginPaint 完成了这一点)。窗口(窗口内部处理)的非空无效/更新区域的存在是导致 WM_PAINT 被放置在消息队列中的原因。

    【讨论】:

    • 语义,但WM_PAINT 从未放入消息队列中。这是在需要时生成的人为消息。
    • @JonathanPotter:这通常是如何管理WM_PAINT,但它也可以是一个真实的消息,例如在使用UpdateWindow(): "如果窗口的更新区域不为空,UpdateWindow 函数通过向窗口发送 WM_PAINT 消息来更新指定窗口的客户区。该函数直接向指定窗口的窗口过程发送 WM_PAINT 消息窗口,绕过应用程序队列。"
    • @JonathanPotter: 或 RedrawWindow() 指定了 RDW_INTERNALPAINT 标志:“无论窗口的任何部分是否无效,都会将 WM_PAINT 消息发布到窗口。”
    • @JonathanPotter:在WM_PAINT 文档中也有这个注释:“窗口可能会收到内部绘制消息,因为调用带有 RDW_INTERNALPAINT 标志设置的 RedrawWindow。在这种情况下,窗口可能没有更新区域。应用程序应调用 GetUpdateRect 函数来确定窗口是否具有更新区域。如果 GetUpdateRect 返回零,则应用程序不应调用 BeginPaint 和 EndPaint 函数。"
    • @RemyLebeau:所以你想学究我的学究。好吧,就这样吧。 “..sends a WM_PAINT message directly to the window procedure”与将其放入消息队列不同。先生,请你!
    猜你喜欢
    • 1970-01-01
    • 2015-03-30
    • 2012-05-12
    • 1970-01-01
    • 2021-04-20
    • 2015-11-08
    • 1970-01-01
    • 1970-01-01
    • 2011-08-16
    相关资源
    最近更新 更多