搭配自定義和 Owner-Drawn 控件使用可視化樣式
本主題描述如何使用可視化樣式 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");
相關主題