为什么父窗口的剪切矩形与子窗口的大小相同?

时间:2022-12-09 18:51:48

I have an app that has a parent window and a tab control child window. The tab control has the CS_HREDRAW and CS_VREDRAW class styles. When I resize the parent window, the clipping rect of the parent in WM_PAINT is the same as the size of the tab control. This does not happen with child windows that don't have the CS_HREDRAW and CS_VREDRAW class styles. Normally when you resize the parent window the clipping rect of the parent window is equal to the uncovered part of the parent window. Why does this happen?

我有一个具有父窗口和制表符控件子窗口的应用程序。选项卡控件具有CS_HREDRAW和CS_VREDRAW类样式。当我调整父窗口的大小时,WM_PAINT中父级的剪切矩形与选项卡控件的大小相同。对于没有CS_HREDRAW和CS_VREDRAW类样式的子窗口,不会发生这种情况。通常,当您调整父窗口的大小时,父窗口的剪切矩形等于父窗口的未覆盖部分。为什么会这样?

EDIT: Why is the clipping rect for the parent window the size of the whole client area of the parent? I have not specified CS_HREDRAW/CS_VREDRAW for the parent class. I want the clipping rect of the parent window to be only the uncovered area when I resize it. From what I understand the child window inherits CS_HREDRAW/CS_VREDRAW if the parent window has those class styles. The documentation doesn't say that the parent inherits those styles from the child. If the parent window doesn't have the CS_HREDRAW/CS_VREDRAW class styles, but the child does, then does the parent inherit those styles from the child?

编辑:为什么父窗口的剪切矩形是父窗口的整个客户区域的大小?我没有为父类指定CS_HREDRAW / CS_VREDRAW。我希望在调整父窗口大小时,父窗口的剪切矩形只是未覆盖的区域。根据我的理解,如果父窗口具有那些类样式,子窗口将继承CS_HREDRAW / CS_VREDRAW。文档没有说父级继承了子级的那些样式。如果父窗口没有CS_HREDRAW / CS_VREDRAW类样式,但子窗口没有,那么父窗口是否从子窗口继承这些样式?

#include <windows.h>
#include <commctrl.h>

#pragma comment(lib, "comctl32.lib")
HINSTANCE g_hInst;

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    static HWND hTab;
    static RECT rc;

    switch(msg)
    {
    case WM_CREATE:
        hTab = CreateWindowEx(0, WC_TABCONTROL, 0, WS_VISIBLE | WS_CHILD, 0, 0, 0, 0, hwnd, 0, g_hInst, 0);
        break;

    case WM_PAINT:
        {
            HDC hdc;
            PAINTSTRUCT ps;
            WCHAR text[70];

            hdc = BeginPaint(hwnd, &ps);
            wsprintf(text, L"%d, %d, %d, %d", ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right, ps.rcPaint.bottom);
            SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM)text);
            EndPaint(hwnd, &ps);
        }
        break;

    case WM_SIZE:
        GetClientRect(hwnd, &rc);
        SetWindowPos(hTab, 0, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, SWP_NOZORDER);
        break;

    case WM_DESTROY:
        PostQuitMessage(0);
        break;

    default: 
        return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}


int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
{
    const TCHAR szClassName[] = L"Appppppppppppp";
    WNDCLASSEX wc = { 0 };
    HWND hwnd;
    MSG msg;

    wc.cbSize        = sizeof(WNDCLASSEX);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wc.hCursor       = LoadCursor(0, IDC_ARROW);
    wc.hIcon         = LoadIcon(0, IDI_APPLICATION);
    wc.hInstance     = hInstance;
    wc.lpfnWndProc   = WndProc;
    wc.lpszClassName = szClassName;
    if(!RegisterClassEx(&wc)) return 0; 

    g_hInst = hInstance;
    InitCommonControls();
    hwnd = CreateWindowEx(0, szClassName, L"App", WS_OVERLAPPEDWINDOW, 40, 40, 420, 200, 0, 0, hInstance, 0);
    if(!hwnd) return 0;

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

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

    return (int)msg.wParam;
}

1 个解决方案

#1


2  

The issue is that your WM_SIZE handler is too late, parts of the main window are already marked dirty. You'd have to do it earlier, at WM_SIZING time, before calling DefWindowProc(). Which works fine, but with the gritty problem that it is hard to calculate the client area from the proposed new window size.

问题是你的WM_SIZE处理程序太晚了,主窗口的部分已经标记为脏。在调用DefWindowProc()之前,你必须在WM_SIZING时间之前做到这一点。哪个工作正常,但有一个棘手的问题,很难从建议的新窗口大小计算客户区。

The simple workaround is to mark the part of the window occupied by the child control as validated:

简单的解决方法是将子控件占用的窗口部分标记为已验证:

case WM_SIZE:
    GetClientRect(hwnd, &rc);
    SetWindowPos(hTab, 0, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, SWP_NOZORDER);
    ValidateRect(hwnd, &rc);     // <== added
    break;

#1


2  

The issue is that your WM_SIZE handler is too late, parts of the main window are already marked dirty. You'd have to do it earlier, at WM_SIZING time, before calling DefWindowProc(). Which works fine, but with the gritty problem that it is hard to calculate the client area from the proposed new window size.

问题是你的WM_SIZE处理程序太晚了,主窗口的部分已经标记为脏。在调用DefWindowProc()之前,你必须在WM_SIZING时间之前做到这一点。哪个工作正常,但有一个棘手的问题,很难从建议的新窗口大小计算客户区。

The simple workaround is to mark the part of the window occupied by the child control as validated:

简单的解决方法是将子控件占用的窗口部分标记为已验证:

case WM_SIZE:
    GetClientRect(hwnd, &rc);
    SetWindowPos(hTab, 0, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, SWP_NOZORDER);
    ValidateRect(hwnd, &rc);     // <== added
    break;