winapi - 删除窗口背景

标签 winapi background erase

据我了解,Windows 在给定窗口的(重新)绘制方面进行了分工;分为背景删除和前景绘画。发送 WM_ERASEBKGND 消息以准备给定窗口的无效部分进行绘制,通常此准备包括删除背景,以便实际绘制可以从干净的 Canvas 开始。在我看来,这条消息总是在 Windows 使给定窗口的一部分无效时发送(因此基本上总是与正在发布的 WM_PAINT 消息一起发送)。每当应用程序本身使给定窗口(的一部分)无效时,InvalidateRect 函数的最后一个参数指定是否发送 WM_ERASEBKGND。所以我写了一个小程序来测试我的假设,但它的行为让我有点困惑。这是说程序:

#ifndef UNICODE
#define UNICODE
#endif 

#include <windows.h>

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hwInstance, PWSTR pCmdLine, int nCmdShow)
{
    // Register the window class.
    const wchar_t CLASS_NAME[] = L"Sample Window Class";

    WNDCLASS wc = {0};

    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); 
    wc.lpszClassName = CLASS_NAME;

    RegisterClass(&wc);

    // Create the window.

    HWND hwnd = CreateWindowEx(
        0,                              // Optional window styles.
        CLASS_NAME,                     // Window class
        L"Learn to Program Windows",    // Window text
        WS_OVERLAPPEDWINDOW,            // Window style

                                        // Size and position
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,

        NULL,       // Parent window    
        NULL,       // Menu
        hInstance,  // Instance handle
        NULL        // Additional application data
    );

    if (hwnd == NULL)
    {
        return 0;
    }

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    // Run the message loop.

    MSG msg = {0};
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return 0;
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    static int eb_count = 0; // counts number of WM_ERASEBKGND messages

    switch (uMsg)
    {
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;

    case WM_PAINT:
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hwnd, &ps);
        RECT rect;

        wchar_t text[40]; 
        wsprintf(text, L"Number of WM_ERASEBKGND messages: %i\n", eb_count);

        GetClientRect(hwnd, &rect);
        DrawText(hdc, text, -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);

        EndPaint(hwnd, &ps);
        return 0;

    case WM_RBUTTONDOWN: // repaint whenever RBUTTONDOWN
        InvalidateRect(hwnd, NULL, FALSE);
        UpdateWindow(hwnd);
        return 0;

    case WM_ERASEBKGND:
        eb_count++;
        return 0;
    }

    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

我在窗口过程中处理WM_ERASEBKGND(这是我的开关中的一个案例),所以它不应该被传递给默认窗口过程。但是,我没有执行任何实际的背景删除(我只是增加了一个静态变量)并且我返回 0 以指示实际上没有发生删除。在我看来,在这个程序中,背景永远不应该被删除。然而,这确实发生在两个不同的实例中。

每当我最大化窗口时,无效部分的背景确实会被类背景画笔删除。但这怎么可能呢?窗口过程在收到 WM_ERASEBKGND 消息时当然不会做这样的事情。

每当 DrawText 重新绘制它的字符串时,类似的事情就会发生。我希望递增的数字会相互叠加(当然会导致难以辨认的困惑)。因此,“DrawText”函数似乎也以某种方式删除了它在其中绘制字符串的矩形的背景。

我的最后一个问题与我的假设有关,即只要 Windows 使窗口的一部分无效,就会发送 WM_ERASEBKGND 消息。我注意到,每当窗口被另一个窗口覆盖并随后被覆盖时,似乎没有发送任何 WM_ERASEBKGND 消息。这是否意味着我的假设是错误的? 抱歉阅读时间过长,但对于回答这些问题的任何和所有帮助将不胜感激。

最佳答案

... my assumption that a WM_ERASEBKGND message is sent whenever Windows invalidates part of a window. I noticed that whenever the window is covered by another window and subsequently uncovered, no WM_ERASEBKGND message seems to be sent ...

那是因为,从 Vista 开始,我们有 Desktop Window Manager (DWM)潜伏在,呃,背景中。这会缓冲所有屏幕窗口的内容,这样 Windows 就不需要在部分内容未被覆盖时发出 WM_ERASEBKGND 或 WM_PAINT 请求 - 它只需将所谓的后台缓冲区复制回屏幕即可。

[部分] 窗口仍然会失效 - 无论是您还是操作系统 - 但不像 XP 时代那样频繁。例如,尝试最小化和恢复窗口 - 然后必须重新绘制它。当您这样做时,DWM 可能会在窗口最小化时丢弃后台缓冲区以节省内存。

除此之外,其他人在评论中所说的。

关于winapi - 删除窗口背景,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50721591/

相关文章:

c++ - 将对象的指针作为参数传递给 DialogBoxParam()

css - 在样式表中定义时不显示背景图像

c++ - 在 std::list 上 push_back 或删除时出现段错误

c++ - 删除循环内 vector 的元素

c++ - 在 VC++ 中使用 GetOpenFileName() API 打开文件夹而不是文件

c++ - PfCreateInterface 返回错误 120(未实现)

css - IE8 截掉背景图片

google-chrome - 仅适用于移动屏幕的 Windows 机器上的 chrome 中出现仅在下拉菜单后面的黑框?

c++ - 从多级 unordered_map 中删除元素?

c++ - 重用 Web 浏览器控件