搭配自定義和擁有者繪製控件使用可視化樣式
本主題描述如何使用可視化樣式 API,將視覺樣式套用至自定義控件或擁有者繪製的控件。
使用可視化樣式繪製控件
ComCtrl32.dll第 6 版和更新版本支援可視化樣式。 如果您的應用程式設定為使用第 6 版和更新版本ComCtrl32.dll,且系統上有該版本可用,則目前可視化樣式會自動套用至您應用程式中的所有通用控件。 不過,目前的可視化樣式不會自動套用至自定義控件或擁有者繪製的控件。 您的應用程式必須包含程式代碼,以檢查視覺效果樣式是否可用,如果是的話,請使用可視化樣式 API,將目前選取的可視化樣式套用至自定義和擁有者繪製的控件。
若要檢查可視化樣式是否可用,請呼叫 IsAppThemed 函式。 如果無法使用可視化樣式,請使用後援程式代碼來繪製控件。
如果有可用的可視化樣式,您可以使用 DrawThemeText 之類的可視化樣式函式來轉譯控件。 請注意, DrawThemeTextEx 可讓您自定義文字的外觀,並保留主題字型的某些屬性,同時修改其他屬性。
若要在目前可視化樣式中繪製控件
- 呼叫 OpenThemeData,傳遞 您想要套用視覺樣式的控件 hwnd ,以及描述控件類型的類別清單。 類別定義於 Vssym32.h 中。 OpenThemeData 會傳回 HTHEME 句柄,但如果停用可視化樣式管理員,或目前的可視化樣式未提供指定控件的特定資訊,則函式會 傳回 NULL。 如果傳回值為 NULL,請使用非視覺樣式的繪圖函式。
- 若要繪製控件背景,請呼叫 DrawThemeBackground 或 DrawThemeBackgroundEx。
- 若要判斷內容矩形的位置,請呼叫 GetThemeBackgroundContentRect。
- 若要轉譯文字,請使用 DrawThemeText 或 DrawThemeTextEx,以 GetThemeBackgroundContentRect 傳回的矩形座標為基礎。 這些函式可以在主題的字型中轉譯文字,以指定控件部分和狀態,或目前在裝置內容中選取的字型中轉譯文字。
- 當您的控件收到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");
相關主題