Uso di stili di visualizzazione con controlli personalizzati e disegnati dal proprietario

In questo argomento viene descritto come usare l'API degli stili di visualizzazione per applicare stili di visualizzazione a controlli personalizzati o controlli disegnati dal proprietario.

Disegno di controlli con stili di visualizzazione

Gli stili di visualizzazione sono supportati da ComCtrl32.dll versione 6 e successive. Se l'applicazione è configurata per l'uso di ComCtrl32.dll versione 6 e successive e, se tale versione è disponibile nel sistema, gli stili di visualizzazione correnti vengono applicati automaticamente a tutti i controlli comuni nell'applicazione. Tuttavia, gli stili di visualizzazione correnti non vengono applicati automaticamente ai controlli personalizzati o ai controlli disegnati dal proprietario. L'applicazione deve includere codice che controlla se gli stili di visualizzazione sono disponibili e, in tal caso, usa l'API degli stili di visualizzazione per applicare gli stili di visualizzazione attualmente selezionati ai controlli personalizzati e disegnati dal proprietario.

Per verificare se gli stili di visualizzazione sono disponibili, chiamare la funzione IsAppThemed. Se gli stili di visualizzazione non sono disponibili, usare il codice di fallback per disegnare il controllo.

Se sono disponibili stili di visualizzazione, è possibile usare funzioni di stili di visualizzazione come DrawThemeText per eseguire il rendering del controllo. Si noti che DrawThemeTextEx consente di personalizzare l'aspetto del testo, mantenendo alcune proprietà del tipo di carattere del tema durante la modifica di altre.

Per disegnare un controllo nello stile di visualizzazione corrente

  1. Chiamare OpenThemeData, passando l'oggetto hwnd del controllo a cui si desidera applicare gli stili di visualizzazione e un elenco di classi che descrive il tipo del controllo. Le classi sono definite in Vssym32.h. OpenThemeData restituisce un handle HTHEME, ma se il gestore stili di visualizzazione è disabilitato o lo stile di visualizzazione corrente non fornisce informazioni specifiche per un determinato controllo, la funzione restituisce NULL. Se il valore restituito è NULL, utilizzare funzioni di disegno non visive.
  2. Per disegnare lo sfondo del controllo, chiamare DrawThemeBackground o DrawThemeBackgroundEx.
  3. Per determinare la posizione del rettangolo di contenuto, chiamare GetThemeBackgroundContentRect.
  4. Per eseguire il rendering del testo, utilizzare DrawThemeText o DrawThemeTextEx, basando le coordinate sul rettangolo restituito da GetThemeBackgroundContentRect. Queste funzioni possono eseguire il rendering del testo nel tipo di carattere del tema per una parte e uno stato del controllo specificati oppure nel tipo di carattere attualmente selezionato nel contesto del dispositivo (DC).
  5. Quando il controllo riceve un messaggio di WM_DESTROY, chiama CloseThemeData per rilasciare l'handle del tema restituito quando hai chiamato OpenThemeData.

Il codice di esempio seguente illustra un modo per disegnare un controllo pulsante nello stile di visualizzazione corrente.

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

Il codice di esempio seguente si trova nel gestore di messaggi WM_PAINT per un controllo pulsante sottoclassato. Il testo per il controllo viene disegnato nel tipo di carattere degli stili di visualizzazione, ma il colore è definito dall'applicazione a seconda dello stato del controllo.

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

È possibile usare parti di altri controlli ed eseguire il rendering di ogni parte separatamente. Ad esempio, per un controllo calendario costituito da una griglia, è possibile trattare ogni quadrato formato dalla griglia come pulsante della barra degli strumenti, ottenendo l'handle del tema come segue:

OpenThemeData(hwnd, L"Toolbar");

È possibile combinare e associare parti di controllo chiamando OpenThemeData più volte per un determinato controllo e usando l'handle del tema appropriato per disegnare parti diverse. In alcuni stili di visualizzazione, tuttavia, alcune parti potrebbero non essere compatibili con altre parti.

Un altro approccio al rendering dei controlli nello stile di visualizzazione attivo consiste nell'usare i colori di sistema. Ad esempio, è possibile utilizzare i colori di sistema per impostare il colore del testo quando si chiama la funzione DrawThemeTextEx. La maggior parte dei colori di sistema viene impostata quando viene applicato un file di stile di visualizzazione.

Risposta alle modifiche del tema

Quando il controllo riceve un messaggio di WM_THEMECHANGED e mantiene un handle globale per il tema, deve eseguire le operazioni seguenti:

  • Chiamare CloseThemeData per chiudere l'handle del tema esistente.
  • Chiama OpenThemeData per ottenere l'handle del tema allo stile di visualizzazione appena caricato.

Nell'esempio seguente vengono illustrate le due chiamate.

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

Enabling Visual Styles (Abilitazione degli stili di visualizzazione)

Stili di visualizzazione