Почему SetWindowRgn не работает для элементов управления stati c? - PullRequest
0 голосов
/ 07 февраля 2020

У меня проблемы с округлением элементов управления stati c. Я не могу понять, почему SetWindowRgn не работает для элемента управления stati c здесь. Также я пробовал SelectClipRgn, и он работает. Но тем не менее, почему SetWindowRgn этого не делает? В документации Microsoft указано, что

Система не отображает какую-либо часть окна, которая находится за пределами области окна.

Элемент управления должен быть округлен и обрезан в соответствии с документация. Но это не так. Вот мой пример проблемы:

#include <windows.h>

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

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow)
{

    const wchar_t CLASS_NAME[] = L"Sample Window Class";

    WNDCLASS wc = { };

    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = CLASS_NAME;

    RegisterClass(&wc);

    HWND hwnd = CreateWindowEx(
        0,                              // Optional window styles.
        CLASS_NAME,                     // Window class
        L"Learn to Program Windows",    // Window text
        WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,            // 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;
    }


    HRGN hrgnMain = CreateRoundRectRgn(0, 0, 200, 200, 5, 5);
    int res = SetWindowRgn(hwnd, hrgnMain, TRUE);

    ShowWindow(hwnd, nCmdShow);

    HWND hControl = CreateWindow(L"Static", L"hello, world", WS_VISIBLE | WS_CHILD | SS_NOTIFY | SS_LEFTNOWORDWRAP,
        20, 20, 40, 40, hwnd, NULL, hInstance, NULL);

    HRGN hrgnControl = CreateRoundRectRgn(0, 0, 10, 10, 5, 5);
    res = SetWindowRgn(hControl, hrgnControl, TRUE);

    ShowWindow(hwnd, nCmdShow);

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

    return 0;
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;

    case WM_PAINT:
    {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hwnd, &ps);
        FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
        EndPaint(hwnd, &ps);
    }
    return 0;
    }

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

1 Ответ

1 голос
/ 08 февраля 2020

Некоторые встроенные элементы управления используют CS_PARENTDC стиль класса.

CS_PARENTDC устанавливает область отсечения дочернего окна равной области родительского окна. Это конфликтует с SetWindowRgn, который хочет установить пользовательский регион. В зависимости от того, как обновляется ваше окно, вы можете получить различные комбинации пользовательских регионов или нет. Например, если вы измените размер родительского окна, вы можете обновить свой элемент управления частично с заданным регионом и частично без региона.

enter image description here

Контексты родительского устройства отображения гласит, что:

Система игнорирует стиль CS_PARENTD C, если родительское окно использует контекст устройства частного или класса, если родительское окно обрезает свой дочерний элемент windows или если дочернее окно обрезает своего дочернего windows или родного брата windows.

Но похоже, что установки только WS_CLIPCHILDREN для родителя windows недостаточно. Добавление флагов WS_CLIPSIBLINGS или WS_CLIPCHILDREN в стили управления (даже если у вас есть только один дочерний элемент) вызывает желаемое поведение.

HWND hControl = CreateWindow(
                    L"Static",
                    L"hello, world",
                    WS_CLIPSIBLINGS | WS_VISIBLE | WS_CHILD | SS_NOTIFY | SS_LEFTNOWORDWRAP,
                    20, 20, 40, 40,
                    hwnd,
                    NULL,
                    hInstance,
                    NULL);

Ваш код без WS_CLIPSIBLINGS

Without WS_CLIPSIBLINGS

И с WS_CLIPSIBLINGS

With WS_CLIPSIBLINGS

В качестве альтернативы стиль CS_PARENT можно удалить с помощью GetClassLongPtr и SetClassLongPtr. Поскольку CS_PARENT используется только для повторного использования области отсечения, других неожиданных эффектов быть не должно.

SetClassLongPtr(
        hControl,
        GCL_STYLE,
        GetClassLongPtr( hControl, GCL_STYLE ) & ~CS_PARENTDC );
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...