Поделиться через


Использование визуальных стилей с пользовательскими и Owner-Drawn элементами управления

В этом разделе описывается, как использовать API визуальных стилей для применения визуальных стилей к пользовательским элементам управления или элементам управления, нарисованным владельцем.

Управление элементами рисования с помощью визуальных стилей

Визуальные стили поддерживаются ComCtrl32.dll версией 6 и более поздними. Если приложение настроено на использование ComCtrl32.dll версии 6 и более поздних версий и если эта версия доступна в системе, текущие визуальные стили автоматически применяются ко всем общим элементам управления в приложении. Однако текущие стили визуальных элементов не применяются автоматически к пользовательским элементам управления или элементам управления, созданным пользователем. Приложение должно содержать код, который проверяет доступность визуальных стилей и, если да, использует API визуальных стилей для применения выбранных визуальных стилей к пользовательским и нарисованным владельцем элементам управления.

Чтобы проверить доступность стилей визуальных элементов, вызовите функцию IsAppThemed. Если стили визуальных элементов недоступны, используйте резервный код для рисования элемента управления.

Если доступны визуальные стили, вы можете использовать такие функции, как DrawThemeText для отрисовки элемента управления. Обратите внимание, что DrawThemeTextEx позволяет настраивать внешний вид текста, сохраняя некоторые свойства шрифта темы при изменении других.

Отрисовать элемент управления в актуальном визуальном стиле

  1. Вызовите OpenThemeData, передав элемента управления, к которому требуется применить стили визуальных элементов и список классов, описывающий тип элемента управления. Классы определены в Vssym32.h. OpenThemeData возвращает дескриптор HTHEME, но если диспетчер визуальных стилей отключен или текущий визуальный стиль не предоставляет определенные сведения для данного элемента управления, функция возвращает NULL. Если возвращаемое значение равно NULL, используйте функции рисования не визуальных стилей.
  2. Чтобы нарисовать фон элемента управления, вызовите DrawThemeBackground или DrawThemeBackgroundEx.
  3. Чтобы определить расположение прямоугольника содержимого, вызовите GetThemeBackgroundContentRect.
  4. Для отрисовки текста используйте либо DrawThemeText, либо DrawThemeTextEx, ориентируясь на прямоугольник, возвращаемый функцией GetThemeBackgroundContentRect. Эти функции могут отображать текст в шрифте темы для указанной части элемента управления и состояния, либо в шрифте, выбранном в контексте устройства (DC).
  5. Когда элемент управления получает сообщение WM_DESTROY, вызовите CloseThemeData, чтобы освободить дескриптор темы, возвращенный при вызове OpenThemeData.

В следующем примере кода демонстрируется один из способов рисования элемента управления кнопкой в текущем визуальном стиле.

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.
    }
}

Следующий пример кода находится в обработчике сообщений WM_PAINT для подклассированного элемента управления кнопкой. Текст элемента управления рисуется в шрифте визуальных стилей, но цвет определяется приложением в зависимости от состояния элемента управления.

// 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.
}

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

OpenThemeData(hwnd, L"Toolbar");

Вы можете смешивать и сопоставлять элементы управления, вызывая OpenThemeData несколько раз для заданного элемента управления и используя соответствующий дескриптор темы для рисования разных частей. Однако в некоторых визуальных стилях некоторые части могут быть несовместимы с другими частями.

Другой подход для отрисовки элементов управления в активном визуальном стиле — это использование системных цветов. Например, можно использовать системные цвета для задания цвета текста при вызове функции DrawThemeTextEx. Большинство системных цветов задаются при применении файла визуального стиля.

Реагирование на изменения темы

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

  • Вызовите CloseThemeData, чтобы закрыть существующий дескриптор темы.
  • Вызовите OpenThemeData, чтобы получить дескриптор темы для недавно загруженного визуального стиля.

В следующем примере показаны два вызова.

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

включение визуальных стилей

Визуальные стили