Partilhar via


Usando estilos visuais com controles personalizados e Owner-Drawn

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

Os estilos visuais são suportados pelo ComCtrl32.dll versão 6 e posterior. Se seu 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 em seu 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 seus 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 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 controlo ao qual se deseja aplicar estilos visuais e uma lista de classes que descreve o tipo do controlo. 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 que não sejam de estilos 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 controlo especificados, ou na fonte atualmente selecionada no contexto do dispositivo (DC).
  5. Quando seu controle receber 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 button 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 peças 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 diferentes partes. 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çãoDrawThemeTextEx. 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 do 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");

Habilitando estilos visuais

Estilos Visuais