Compartilhar via


Como usar estilos visuais com controles personalizados e desenhados pelo proprietário

Este tópico descreve como usar a API de estilos visuais para aplicar estilos visuais a controles personalizados ou controles desenhados pelo proprietário.

Controles de desenho com estilos visuais

Estilos visuais são suportados pelo ComCtrl32.dll versão 6 e posterior. Se o aplicativo estiver configurado para usar ComCtrl32.dll versão 6 e posterior, e se essa versão estiver disponível no sistema, os estilos visuais atuais serão aplicados automaticamente a todos os controles comuns no aplicativo. No entanto, os estilos visuais atuais não são aplicados automaticamente a controles personalizados ou controles desenhados pelo proprietário. Seu aplicativo deve incluir código que verifica se os estilos visuais estão disponíveis e, em caso afirmativo, usa a API de estilos visuais para aplicar os estilos visuais atualmente selecionados aos controles personalizados e desenhados pelo proprietário.

Para verificar se os estilos visuais estão disponíveis, chame a função IsAppThemed. Se os estilos visuais não estiverem disponíveis, use o código de fallback para desenhar o controle.

Se os estilos visuais estiverem disponíveis, você poderá usar funções de estilos visuais, como DrawThemeText para renderizar seu controle. Observe que DrawThemeTextEx permite personalizar a aparência do texto, mantendo algumas propriedades da fonte do tema enquanto modifica outras.

Para desenhar um controle no estilo visual atual

  1. Chame OpenThemeData, passando o hwnd do controle ao qual você deseja aplicar estilos visuais e uma lista de classes que descreve o tipo do controle. As classes são definidas em Vssym32.h. OpenThemeData retorna um identificador HTHEME, mas se o gerenciador de estilos visuais estiver desabilitado ou o estilo visual atual não fornecer informações específicas para um determinado controle, a função retornará NULL. Se o valor de retorno for NULL, use funções de desenho de estilos não visuais.
  2. Para desenhar o plano de fundo do controle, chame DrawThemeBackground ou DrawThemeBackgroundEx.
  3. Para determinar o local do retângulo de conteúdo, chame GetThemeBackgroundContentRect.
  4. Para renderizar texto, use DrawThemeText ou DrawThemeTextEx, baseando as coordenadas no retângulo retornado por GetThemeBackgroundContentRect. Essas funções podem renderizar texto na fonte do tema para uma parte e estado de controle especificados ou na fonte atualmente selecionada no contexto do dispositivo (DC).
  5. Quando seu controle recebe uma mensagem WM_DESTROY, chame CloseThemeData para liberar o identificador de tema que foi retornado quando você chamou OpenThemeData.

O código de exemplo a seguir demonstra uma maneira de desenhar um controle de botão no estilo visual atual.

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

O código de exemplo a seguir está no manipulador de mensagens WM_PAINT para um controle de botão subclassificado. O texto para o controle é desenhado na fonte de estilos visuais, mas a cor é definida pelo aplicativo dependendo do estado do controle.

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

Você pode usar partes de outros controles e renderizar cada parte separadamente. Por exemplo, para um controle de calendário que consiste em uma grade, você pode tratar cada quadrado formado pela grade como um botão da barra de ferramentas, obtendo o identificador de tema da seguinte maneira:

OpenThemeData(hwnd, L"Toolbar");

Você pode misturar e combinar partes de controle chamando OpenThemeData várias vezes para um determinado controle e usando o identificador de tema apropriado para desenhar partes diferentes. Em alguns estilos visuais, no entanto, certas partes podem não ser compatíveis com outras partes.

Outra abordagem para renderizar controles no estilo visual ativo é usar as cores do sistema. Por exemplo, você pode usar as cores do sistema para definir a cor do texto ao chamar a função DrawThemeTextEx. A maioria das cores do sistema é definida quando um arquivo de estilo visual é aplicado.

Respondendo a alterações de tema

Quando seu controle recebe uma mensagem WM_THEMECHANGED e está segurando um identificador global para o tema, ele deve fazer o seguinte:

  • Chame CloseThemeData para fechar o identificador de tema existente.
  • Chame OpenThemeData para obter o identificador de tema para o estilo visual recém-carregado.

O exemplo a seguir ilustra as duas chamadas.

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

Habilitar estilos visuais

Estilos visuais