Udostępnij za pośrednictwem


Używanie stylów wizualnych z kontrolkami niestandardowymi i Owner-Drawn

W tym temacie opisano sposób używania API stylów wizualnych do nakładania stylów wizualnych na kontrolki niestandardowe lub kontrolki rysowane przez właściciela.

Kontrolki rysowania ze stylami wizualnymi

Style wizualne są obsługiwane przez ComCtrl32.dll w wersji 6 i nowszych. Jeśli aplikacja jest skonfigurowana do używania ComCtrl32.dll w wersji 6 lub nowszej, a jeśli ta wersja jest dostępna w systemie, bieżące style wizualizacji są automatycznie stosowane do wszystkich typowych kontrolek w aplikacji. Bieżące style wizualizacji nie są jednak automatycznie stosowane do kontrolek niestandardowych ani kontrolek rysowanych przez właściciela. Twoja aplikacja musi zawierać kod, który sprawdza, czy są dostępne style wizualne, a jeśli tak, używa interfejsu API stylów wizualnych do zastosowania aktualnie wybranych stylów wizualnych do kontrolek niestandardowych i rysowanych na zamówienie.

Aby sprawdzić, czy są dostępne style wizualizacji, wywołaj funkcję IsAppThemed. Jeśli style wizualizacji nie są dostępne, użyj kodu rezerwowego, aby narysować kontrolkę.

Jeśli są dostępne style wizualizacji, możesz użyć funkcji stylów wizualnych, takich jak DrawThemeText do renderowania kontrolki. Należy pamiętać, że DrawThemeTextEx umożliwia dostosowanie wyglądu tekstu, zachowując niektóre właściwości czcionki motywu podczas modyfikowania innych.

Aby narysować kontrolkę w bieżącym stylu wizualizacji

  1. Wywołaj OpenThemeData, przekazując hwnd kontrolki, do której chcesz zastosować style wizualizacji, oraz listę klas opisujących typ kontrolki. Klasy są definiowane w vssym32.h. OpenThemeData zwraca uchwyt HTHEME, ale jeśli menedżer stylów wizualnych jest wyłączony lub bieżący styl wizualny nie dostarcza specyficznych informacji dla określonej kontrolki, funkcja zwraca NULL. Jeśli zwracana wartość to NULL, użyj funkcji rysujących w stylach niewizualnych.
  2. Aby narysować tło kontrolki, wywołaj DrawThemeBackground lub DrawThemeBackgroundEx.
  3. Aby określić lokalizację prostokąta zawartości, wywołaj metodę GetThemeBackgroundContentRect.
  4. Aby renderować tekst, użyj DrawThemeText lub DrawThemeTextEx, bazując na współrzędnych na prostokącie zwróconym przez GetThemeBackgroundContentRect. Te funkcje mogą wyświetlać tekst w czcionce motywu dla określonej części i stanu kontrolki, lub w czcionce aktualnie wybranej w kontekście urządzenia (DC).
  5. Gdy kontrolka odbiera komunikat WM_DESTROY, wywołaj CloseThemeData, aby zwolnić uchwyt motywu, który był zwrócony przy wywołaniu OpenThemeData.

Poniższy przykładowy kod przedstawia jeden ze sposobów narysowania kontrolki przycisku w bieżącym stylu wizualizacji.

HTHEME hTheme = NULL;

hTheme = OpenThemeData(hwndButton, L"Button");
// ...
DrawMyControl(hDC, hwndButton, hTheme, iState);
// ...
if (hTheme)
{
    CloseThemeData(hTheme);
}


void DrawMyControl(HDC hDC, HWND hwndButton, HTHEME hTheme, int iState)
{
    RECT rc, rcContent;
    TCHAR szButtonText[255];
    HRESULT hr;
    size_t cch;

    GetWindowRect(hwndButton, &rc);
    GetWindowText(hwndButton, szButtonText,
                  (sizeof(szButtonText) / sizeof(szButtonText[0])+1));
    hr = StringCchLength(szButtonText,
         (sizeof(szButtonText) / sizeof(szButtonText[0])), &cch);
    if (hTheme)
    {
        hr = DrawThemeBackground(hTheme, hDC, BP_PUSHBUTTON, iState, &rc, 0);
        if (SUCCEEDED(hr))
        {
            hr = GetThemeBackgroundContentRect(hTheme, hDC, BP_PUSHBUTTON, 
                    iState, &rc, &rcContent);
        }

        if (SUCCEEDED(hr))
        {
            hr = DrawThemeText(hTheme, hDC, BP_PUSHBUTTON, iState, 
                    szButtonText, cch,
                    DT_CENTER | DT_VCENTER | DT_SINGLELINE,
                    0, &rcContent);
        }

    }
    else
    {
        // Draw the control without using visual styles.
    }
}

Poniższy przykładowy kod znajduje się w obsłudze komunikatów WM_PAINT dla kontrolki przycisku podklasowanego. Tekst elementu sterującego jest rysowany czcionką stylów wizualnych, ale kolor jest definiowany przez aplikację w zależności od stanu elementu sterującego.

// textColor is a COLORREF whose value has been set according to whether the button is "hot".
// paint is the PAINTSTRUCT whose members are filled in by BeginPaint.
HTHEME theme = OpenThemeData(hWnd, L"button");
if (theme)
{
    DTTOPTS opts = { 0 };
    opts.dwSize = sizeof(opts);
    opts.crText = textColor;
    opts.dwFlags |= DTT_TEXTCOLOR;
    WCHAR caption[255];
    size_t cch;
    GetWindowText(hWnd, caption, 255);
    StringCchLength(caption, 255, &cch);
    DrawThemeTextEx(theme, paint.hdc, BP_PUSHBUTTON, CBS_UNCHECKEDNORMAL, 
        caption, cch, DT_CENTER | DT_VCENTER | DT_SINGLELINE, 
        &paint.rcPaint, &opts);
    CloseThemeData(theme);
}
else
{
    // Draw the control without using visual styles.
}

Można używać części z innych kontrolek i renderować poszczególne części oddzielnie. Na przykład w przypadku kontrolki kalendarza składającej się z siatki można traktować każdy kwadrat utworzony przez siatkę jako przycisk paska narzędzi, uzyskując uchwyt motywu w następujący sposób:

OpenThemeData(hwnd, L"Toolbar");

Części sterowania można mieszać i dopasowywać, wywołując OpenThemeData wiele razy dla danej kontrolki i używając odpowiedniego uchwytu motywu w celu narysowania różnych części. Jednak w niektórych stylach wizualizacji niektóre części mogą nie być zgodne z innymi częściami.

Innym podejściem do renderowania kontrolek w aktywnym stylu wizualizacji jest użycie kolorów systemowych. Można na przykład użyć kolorów systemowych, aby ustawić kolor tekstu podczas wywoływania funkcji DrawThemeTextEx. Większość kolorów systemowych jest ustawiana podczas stosowania pliku stylu wizualizacji.

Reagowanie na zmiany motywu

Gdy kontrolka odbiera komunikat WM_THEMECHANGED i przechowuje globalny uchwyt do motywu, powinna wykonać następujące czynności:

  • Aby zamknąć istniejący uchwyt motywu, wywołaj CloseThemeData.
  • Wywołaj OpenThemeData, aby uzyskać dojście motywu do nowo załadowanego stylu wizualizacji.

Poniższy przykład ilustruje dwa wywołania.

case WM_THEMECHANGED:
     CloseThemeData (g_hTheme);
     g_hTheme = OpenThemeData (hwnd, L"MyClassName");

Aktywacja stylów wizualnych

style wizualne