8.1.4 按鈕
在BTNLOOK中顯示的前兩個按鈕是“按鍵”按鈕(push button)。此類按鈕是一種帶有 文本的矩形,這些文本是在CreateWindow調用的窗口文本參數中提供的。而CreateWindow 或MoveWindow調用中指定的寬度和高度則確定了矩形的大小。文本顯示在矩形的中心。
按鍵按鈕控件主要用于立即啟動某些行動而不必保留任何類型的開/關指示。有兩種類 型的按鍵按鈕控件,它們的窗口樣式分別是BS_PUSHBUTTON和BS_DEFPUSHBUTTON。 BS_DEFPUSHBUTTON的“DEF”表示“默認值”。在被用于設計對話框時, BS_PUSHBUTTON控件和BS_DEFPUSHBUTTON控件功能是完全不同的。但在被用作子窗口控件時,兩種類型按鈕的表現基本相同,雖然BS_DEFPUSHBUTTON會有一個較重的輪廓。
按鍵按鈕的最佳視覺高度是字符高度的7/4,這是我們在BTNLOOK中使用的高度。這種按鈕的寬度至少需要容納文本的寬度,外加兩個額外的字符寬度。
當鼠標指針顯示在按鈕內部時,按下鼠標按鈕將會導致按鈕用三維樣式的陰影重繪自 己,仿佛它被按下似的。當釋放鼠標,按鈕會恢復原貌,并發出一個通知碼為BN_CLICKED 的WM_COMMAND消息到父窗口。像其他按鈕類型一樣,當一個按鈕有輸入焦點時,文本會被虛線包圍。按下和釋放空格鍵的效果同按下和釋放鼠標一樣。默認情況下,DefWindowProc函數為所有者繪制的列表框項目繪制焦點矩形。
通過給Windows發送一個BM_SETSTATE消息,可以模擬按鍵按鈕的狀態變化。下面的語句將導致按鈕看上去被按住一樣:
SendMessage (hwndButton, BM_SETSTATE, 1, 0);
調用下面的函數則會讓按鈕回到正常狀態:
SendMessage (hwndButCon, BM_SETSTATE, 0, 0);
窗口句柄hwndButton是CreateWindow調用的返回值。
也可以給按鍵按鈕發送一個BM_GETSTATE消息。子窗口控件返回當前按鈕的狀態:如果按鍵是按下的,則返回TRUE;如果沒有被按下,則返回FALSE。然而大多數應用程序不需要此信息。而因為這種按鈕不保留任何開/關信息,所以BM_SETCHECK和 BM_GETCHECK消息沒有被用到。
■復選框
復選框(check box)是一個帶文本的正方形框,文本通常出現在復選框的右側。(如果在創建按鈕時包括BS_LEFTTEXT樣式,則文本會出現在按鈕左側:還可以組合使用 BS_RIGHT樣式使文本右對齊。)復選框通常用在應用程序中,以允許用戶選擇多個選項。復選框的常見職能是作為切換開關:單擊方框即可選中此功能選項(出現一個選中標記), 再單擊方框即可取消此功能選項(選中標記消失)。
復選框最常見的兩類樣式是BS_CHECKBOX和BS_AUTOCHECKBOX。在使用 BS_CHECKBOX樣式時,必須自己給控件發送一個BM_SETCHECK消息來設置其選中標記。wParam參數設置為1會創建一個選中標記,設置為0則清除標記。可以向控件發送 BM_GETCHECK信息來獲取復選框當前的被選狀態。在處理來自控件的 WM_COMMAND消息時,可使用下面的代碼切換選中標記:
SendMessage ((HWND) IParam, BM_SETCHECK, (WPARAM)
????????????? !SendMessage ( (HWND) IParam, BM_GETCHECK, 0, 0), 0);
【注意】在第二行中,SendMessage函數前面有個操作符!。IParam值是 WM_COMMAND消息傳遞給窗口過程的子窗口句柄。以后需要知道按鈕狀態的時候,可以發送另一條BM_GETCHECK消息。或者,可以把當前的選擇狀態保存在窗口過程的靜態變量中。也可以發送一條BM_SETCHECK信息,借此將BS_CHECKBOX復選框初始化為選中狀態。
對于BS_AUTOCHECKBOX樣式,按鈕控件本身負責切換選定和取消標記。窗口過程可以忽略WM_COMMAND消息。在需要當前按鈕的狀態時,可以向控件發送 BM_GETCHECK 消息:
iCheck = (int) SendMessage (hwndButton, BM_GETCHECK, 0, 0);
如果復選框被選中,iCheck的值就為TRUE或非零。如果沒有被選中,則為FALSE或0。
其他兩個復選框樣式分別為BS_3STATE和BS_AUTO3STATE。正如其名稱所表明的,這些樣式可以顯示第二種狀態一個灰色的復選框。這發生在向控件發送BM_SETCHECK消息(wParam被設為2)時。灰色復選框告訴用戶,選擇是不確定的或無關緊要的。
CreateWindow函數調用指定了控件矩形的大小,復選框會在矩形的左邊緣對齊,并在 矩形的頂端和底部居中。單擊矩形內的任何地方都會導致WM_COMMAND消息被發送到父窗口。復選框的域低高度是一個字符的高度。最小寬度是現有字符數再加2個字符的寬度。
樣式 | 狀態 |
BS_CHECKBOX | 1、SendMessage(hwndButton,BM_SETCHECK,1,0); //選中 2、SendMessage(hwndButton,BM_SETCHECK,0,0); //取消選中 3、SendMessage((HWND)lParam,BM_SETCHECK,(WPARAM)?? //切換 !SendMessage((HWND)lParam,BM_GETCHECK,0,0),0); |
BS_AUTOCHECKBOX | 1、自動切換 2、獲取狀態:iCheck = (int)SendMessage(hwndButton,BM_GETCHECK,0,0); |
BS_3STATE | SendMessage(hwndButton,BM_SETCHECK,2,0); //第3種狀態 |
BS_AUTO3STATE | //自動切換 |
●寬度和高度:最低高度——1個字符的高度,最小寬度——字符數+2個字符的寬度。
●復選框中的文本位置及文本對齊。
?????? ■單選按鈕
單選按鈕的名稱來源于汽車收音機的一排選擇按鈕,它曾風靡一時。汽車收音機的每個按鈕設定為不同的電臺。在任意時刻只有一個按鈕可以被按下。在對話框中,一組申選按鈕依據約定用于相互排斥的選項。不同于復選框,單選按鈕沒有狀態切換,也就是說,如果單擊按鈕第二次,其狀態仍保持不變。
單選按鈕很像一個復選框,但它包含一個小圓圈,而不是一個方框。圓圈內有一個大黑點表明該單選按鈕已被選中。單選按鈕的窗口樣式為BS_RADIOBUTTON或 BS_AUTORADIOBUTTON,但后者只用于對話框。
在收到來自單選按鈕的WM_COMMAND消息時,應通過向它發送一條wParam等于1的BM_SETCHECK消息來顯示其選中標記:
SendMessage (hwndButton, BM_SETCHECK, 1, 0);
而對于其他在同一組中的所有單選按鈕,則可以通過向它們發送wParam設置為0的 BM_SETCHECK消息來取消其選中標記:
SendMessage (hwndButton, BM_SETCHECK, 0, 0);
?■組合框
帶有BS_GROUPBOX樣式的組合框,是一個古怪的按鈕類。它既不處理鼠標或鍵盤輸入也不發送消息到WM_COMMAND父窗口。組合框是一種矩形外框,窗口文本顯示在矩形頂部。組合框常常被用來包容其他按鈕控件。
?■改變按鈕文本
可以調用SetWindowText來改變按鈕中的文本:
SetWindowText (hwnd, pszString);
這里的hwnd是要被改變文本的窗口的句柄,pszString是一個指向以零結尾的字符串的指針。對于普通窗口來說,該文本就是指窗口標題欄中的文本。而對于按鈕控件來說,該文 本是和按鈕一起顯示的文本。
也可以獲得一個窗口的當前文本,如下所示:
iLength = GetWindowText (hwnd, pszBuffer, iMaxLengCh);
這里的iMaxLength指定了 pszBuffer所指向的緩沖區所能接收的最大字符串長度。函數會 返回被復制的字符串長度。可以事先調用如下函數,使程序對可接收的特定文本長度有所 準備;
iLength = GetWindowTextLength (hwnd);
■可見按鈕和啟動按鈕
要接收鼠標和鍵盤輸入,子窗口必須是可見的(顯示)并且是啟用的。如果一個子窗口 是可見的,但沒有啟用,那么文本在窗口中的顯示是灰色的,而不是黑色的。
如果在創建子窗口時在窗口類中沒有包括WS_VISIBLE,子窗口將不會顯示,除非調用 ShowWindow:
ShowWindow(hwndChild, SW_SHOWNORMAL);
但如果在窗口類中包含了 WS_VISIBLE,就無需調用ShowWindow。不過,可以調用以下 ShowWindow來隱藏這個子窗口:
ShowWindow (hwndGhild, SW_HIDE);
可以調用以下函數來判斷窗口是否可見:
IsWindowVisible (hwndChild);
還可以啟用或者禁用一個子窗口。在默認情況下,窗口是處于啟用狀態的。可以調用下面的函數來禁用子窗口:
EnableWindow (hwndChild, FALSE);
對于按鈕控件,此函數可以把按鈕的文本字符串變成灰色。按鈕不再響應鼠標或鍵盤輸入。 這是表明按鈕選項目前無法使用的最佳方法。
通過如下調用可以重新啟用子窗口 :
EnableWindow(hChildWnd, TRUE);
可以調用以下函數了解子窗口是否已被啟用:
IsMindowEnab1ed (hwndChild);
?■按鈕和輸入焦點
當我們用鼠標單擊時,按鍵按鈕、復選框、復選按鈕、自繪按鈕得到輸入焦點。如果按鈕上的文本被虛線包圍,則表明它已經獲得輸入焦點。子窗口控件得到輸入焦點后,父窗口便會失去輸入焦點。之后所有的鍵盤輸入將送到控件子窗口而不是其父窗口。然而,子窗口控件只對空格鍵做出響應,空格鍵現在的功能類似于鼠標。 這種情況引發一個明顯的問題:程序已經失去了對鍵盤處理的控制。讓我們看看如何解決這個問題。
正如我在第六章討論的,在Windows把輸入焦點從一個窗口(如父窗口)切換到另一個 窗口(如子窗口控件)時,它首先會向將要失去輸入焦點的窗口發送一條消息 WM_KILLFOCUS。相應的wParam參數是將要獲得輸入焦點的窗口的句柄。Windows然后向要接收輸入焦點的窗口發送WM_SETFOCUS消息,用wParam指定失去輸入焦點的窗口的句柄。(在這兩種情況wParam都可能是NULL,表明沒有窗口具有或正在接收輸入焦點。)
父窗口可以通過對WM_KILLFOCUS消息的處理來阻止子窗口控件獲得輸入焦點。假定數組hwndChild包含所有子窗口的窗口句柄。(這些句柄都是在調用CreateWindow創建窗口時保存在數組中的。)NUM是子窗口的數目。
case WM_KILLFOCUS :
?????? for ( i = 0 ; i < NUM ; i++) {
????????????? if (hwndChild [i] == (HWND) wParam)
????????????? {
???????????????????? SetFocus (hwnd) ;
???????????????????? break ;
????????????? }
?????? }
return 0 ;
在此代碼中,當父窗口檢測到它將失去輸入焦點并將焦點轉給它的一個子窗口控件時,它調用SetFocus來重新獲得本身的輸入焦點。
下面有一個更簡單(但不太明顯)的方法來實現我們的想法:
case WM_KILLFOCUS :
?????? if (hwnd == GecParent ((HWND) wParam))
????????????? SetFocus (hwnd);
return 0;
但這兩種方法都有一個缺陷,就是他們會使按鈕不再回應空格鍵,因為按鈕從未得到輸入焦點。一個更好的辦法是讓按鈕獲得輸入焦點,而且還能讓用戶用Tab鍵從一個按鈕移動到另外一個按鈕。這乍聽起來好像不可能,但我會在本章后面的COLORS1程序中指出如何用“窗口子類”這一技術來實現它。
8.1.5 控件和顏色
?????? 許多按鈕的顯示看起來不太對。按鍵按鈕還好,但其他按鈕都有一個本不該有的長方形灰色背景。這是因為按鈕是被設計用于在對話框中顯示的,而Windows 98中的對話框的表面是灰色的。我們的窗口表面是白色的,因為這是我們在WNDCLASS 結構中已經定義好的:
wndclass.hbrBackground = (HBRUSH) GetStoekObject (WHITE_BRUSH);
我們之所以這樣設置,是因為我們常常要在客戶區顯示文本,GDI使用了定義在默認設備環境中的文本顏色與背景顏色。這些顏色總是黑色和白色。為了使這些按鈕更耐看。我們必須要么改變客戶區的顏色,讓它與按鈕的背景顏色相同,要么就更改按鈕的背景顏色為白色。
要解決這個問題,首先要理解Windows是如何使用系統顏色的。
■系統顏色
Windows有29種系統顏色來支持各部分的顯示。可以使用GetSysColor和 SetSysColors獲取并設置這些顏色。定義在Windows頭文件中的標識符指定了系統顏色。 用SetSysColors設置系統顏色僅僅影響到當前的窗口會話。
可以用Windows控制面板的【顯示】工具來改變某些(但不是所有的)系統顏色。選定 的顏色分別存儲在Windows NT的注冊表(Registry)中或Windows 98的WIN.INI文件中。 注冊表和WIN.INI文件使用關鍵字來表示29種系統顏色(這些關鍵字不同于GetSysColor 和SetSysColors的標識符),緊接著是范圍0?255的紅、綠、藍RGB值。下表列出了29 種系統顏色的定義,它使用GetSysColor、SetSysColors的常量和WIN.INI中的關鍵字。
GetSysColor和SetSysColors | 注冊表鍵值或WIN.INI標識符 | 默認RGB值 |
COLOR_SCROLLBAR | Scrollbar | C0-C0-C0 |
COLOR_BACKGROUND | Background | 00-80-80 |
COLOR_ACTIVECAPTION | ActiveTitle | 00-00-80 |
COLOR_INACTIVECAPTION | InactiveTitle | 80-80-80 |
COLOR_MENU | Menu | C0-C0-C0 |
COLOR_WINDOW | Window | FF-FF-FF |
COLOR_WINDOWFRAME | WindowFrame | 00-00-00 |
COLOR_MENUTEXT | MenuText | C0-C0-C0 |
COLOR_WINDOWTEXT | WindowText | 00-00-00 |
COLOR_CAPTIONTEXT | TitleText | FF-FF-FF |
COLOR_ACTIVEBORDER | ActiveBorder | C0-C0-C0 |
COLOR_INACTIVEBORDER | InactiveBorder | C0-C0-C0 |
COLOR_APPWORKSPACE | App Workspace | 80-80-80 |
COLOR_HIGHLIGHT | Highlight | 00-00-80 |
COLOR_HIGHLIGHTTEXT | HighlightText | FF-FF-FF |
COLOR_BTNFACE | ButtonFace | C0-C0-C0 |
COLOR_BTNSHADOW | ButtonShadow | 80-80-80 |
COLOR_BTNTEXT | ButtonText | 00-00-00 |
COLOR_INACTINVECAPTIONTEXT | InactiveTitleText | C0-C0-C0 |
COLOR_BTNHIGHLIGHT | ButtonHighlight | FF-FF-FF |
COLOR_3DDKSHADOW | ButtonDKShadow | 00-00-00 |
COLOR_3DLIGHT | ButtonLight | C0-C0-C0 |
COLOR_INFOTEXT | InfoText | 00-00-00 |
COLOR_INFOBK | InfoWindow | FF-FF-FF |
[沒有標識符,使用值25] | ButtonAlternateFace | B8-B4-B8 |
COLOR_HOTLIGHT | HotTrackingColor | 00-00-FF |
COLOR_GRADIENTACTIVECAPTION | GradientActiveTitle | 00-00-80 |
COLOR_GRADIENTINACTIVECAPTION | GradientInactiveTitle | 80-80-80 |
這29種顏色的默認值是由顯示驅動程序提供的,在不同機器上顏色可能稍有不同。
?????? ■按鈕顏色
顏色 | 說明 |
COLOR_BTNFACE | 按鈕主表面顏色或其他按鈕的背景顏色 |
COLOR_BTNSHADOW | 按鈕右側和底部的陰影顏色 |
COLOR_BTNTEXT | 對按鍵按鈕而言的,為上面的文本顏色 |
COLOR_WINDOWTEXT | 其他控件的文本顏色 |
這個問題對按鈕而言尤為明顯,因為每種按鈕都要用到多種顏色。COLOR_BTNFACE 用于按鍵按鈕的主表面顏色和其他按鈕的背景顏色。(這也是對話框和消息框使用的系統顏 色。)COLOR_BTNSHADOW用在按鍵按鈕的右側和底部、復選框方塊的內部和單選按鈕的圓圈內,用來表示陰影。對于按鍵按鈕,COLOR_BTNTEXT用于文本的顏色;其他控件的文本顏色使用的則是COLOR_WINDOWTEXT。還有好幾種其他系統顏色也用于按鈕的設計。
因此,如果我們要在客戶區表面顯示按鈕,一個避免顏色沖突的途徑就是使用這些系統顏色。首先,在設計窗口類時,使用COLOR_BTNFACE作為客戶區的背景顏色:
wndclass.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1) ;
可以在BTNLOOK程序中自行嘗試一下這種做法。Windows知道,在WNDCLASS結構中hbrBackground值很低時,它實際上指的是系統顏色,而不是一個實際的句柄。 Windows要求在使用這些標識符時,要加上1,并在WNDCLASS結構的hbrBackground 字段中加以指定,但這樣做并沒有什么深遠的目的,只是為了防止出現空值(NULL)。如果系統顏色發生了改變,而你的程序正在運行,那么客戶區表面會變為無效,Windows將使用新的COLOR_BTNFACE值。但現在我們又引發了另一個問題。在使用TextOut 表示文本時,Windows使用設備環境中定義的值來作為文本的背景顏色(它清除了文本的背景)和文本的顏色。預設值是白色(背景)和黑色(文本),而不管系統顏色或是窗口類結構的 hbrBackground定義的顏色。所以需要使用SetTextColor和SetBkColor改變文本和文本背景顏色以匹配系統顏色。可以在獲得設備環境的句柄之后做這件事情:
SetBkColor (hdc, GetSysColor (COLOR_btnfaCE));
SetTextColor (hdc, GetSysColor (COLOR_WINDOWTEXT));
現在,客戶區的背景、文本背景和文本顏色與按鈕的顏色都是一致的。但是,當程序正在運行時,如果用戶更改了系統顏色,則需要更改文本的背景顏色和文本顏色。為此,使用以下代碼即可:
case WM_SYSCOLORCHANGE:
?????? InvalidateRect (hwnd, NULL, TRUE) ;
?????? break ;
■WM_CTLCOLORBTN 消息
前面介紹了如何調整客戶區的顏色和文本顏色以匹配按鈕背景顏色。這是否意味著可 以在程序中把按鈕的顏色也相應調為自己喜歡的顏色呢?在理論上是可以的,但在實際中 有問題。最好不要用SetSysColors改變按鈕的外觀。這將影響到Windows環境下正在運行 的所有程序,用戶不會喜歡這樣的。
一個更好的辦法(也是理論上如此)是處理WM_CTLCOLORBTN消息。當子窗口即將重繪其客戶區時,按鈕控件會把這個消息發送給其父窗口的窗口過程。父窗口可以利用這個機會來改變子窗口的背景顏色。
當父窗口的窗口過程收到WM_CTLCOLORBTN消息時,wParam消息參數是按鈕的設備環境的句柄,IParam是按鈕的窗口句柄。當父窗口的窗口過程收到此消息,按鈕控件便已經取得其設備環境。當在窗口過程中處理WM_CTLCOLORBTN信息時,可以選擇以做法:
●使用SetTextColor設置文本顏色。
●使用SetBkColor設置文本的背景顏色。
●返回子窗口的畫刷句柄。
從理論上講,子窗口使用這個畫刷來著色背景。在不再需要畫刷時,你需要負責銷毀畫刷。
這里有一個關于WM_CTLCOLORBTN的問題:只有按鍵按鈕和自繪按鈕會發送 WM_CTLCOLORBTN到它們的父窗口,而只有自繪按鈕需要對父窗口使用畫刷繪制背景的消息處理過程作出反應。這是相當沒有必要的,因為父窗口負責繪制自繪按鈕。
在本章后面,我們將討論類似于WM_CTLCOLORBTN的消息的有用情況,不過這些消息是應用于其他類型控件的。
8.1.6 第49練:單選框和復選框狀態的判斷
/*------------------------------------------------------------------
049? WIN32 API 每日一練
??? ?第49個例子BTNSTATE.C:單選框和復選框狀態的判斷
??? ?CreateFont函數
??? ?GetWindowText函數
(c) www.bcdaren.com, 2020
----------------------------------------------------------------*/
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE hInst;//全局變量
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
??? PSTR szCmdLine, int iCmdShow)
{
??? static TCHAR szAppName[] = TEXT("Button State");
??? …(略)
??? return msg.wParam;
}
//窗口過程
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
??? int wmId, wmEvent;
??? PAINTSTRUCT ps;
??? HDC hdc;
??? //設置緩沖區
??? static TCHAR szBufSex[10];
??? static TCHAR szBufMarriage[10];
??? static TCHAR szBufPet[20];
??? static TCHAR szBufSubmit[100];
??? static TCHAR szBufTmp[10];
??? static HFONT hFont;????? //邏輯字體
??? //一組單選按鈕---BS_AUTORADIOBUTTON
??? static HWND labSex;????? //靜態文本框--性別
??? static HWND radioMale;?? //單選按鈕--男
??? static HWND radioFemale; //單選按鈕--女
??? //一組單選按鈕---BS_AUTORADIOBUTTON
??? static HWND labMarriage;? //靜態文本框--婚姻狀況
??? static HWND radioMarried; //單選按鈕--已婚
??? static HWND radioSingle;? //單選按鈕--未婚
??? static HWND radioSecrecy; //單選按鈕--保密
??? //一組復選框---BS_AUTOCHECKBOX
??? static HWND labPet;????? //靜態文本框--你的寵物
??? static HWND checkboxDog; //復選框--狗
??? static HWND checkboxCat; //復選框--貓
??? static HWND checkboxFish;//復選框--魚
??? static HWND checkboxOther;//復選框--其他
??? static HWND btnSubmit;? //按鈕控件
??? switch (message) {
??? case? WM_CREATE:
??????? hFont = CreateFont(
??????????? -14, -7, 0, 0, 400,
??????????? FALSE, FALSE, FALSE, DEFAULT_CHARSET,
??????????? OUT_CHARACTER_PRECIS, CLIP_CHARACTER_PRECIS, DEFAULT_QUALITY,
??????????? FF_DONTCARE, TEXT("微軟雅黑")
??????? );
??????? //選擇性別
??????? labSex = CreateWindow(
??????????? TEXT("static"), TEXT("你的性別:"),
??????????? WS_CHILD | WS_VISIBLE | SS_CENTERIMAGE | SS_RIGHT/*文字居右*/,
??????????? 10, 10, 80, 26,
??????????? hWnd, (HMENU)1, hInst, NULL
??????? );
??????? radioMale = CreateWindow(
??????????? TEXT("button"), TEXT("男"),
??????????? WS_CHILD | WS_VISIBLE | BS_LEFT/*文字居左*/
| BS_AUTORADIOBUTTON /*單選按鈕*/
??????????? | WS_GROUP/*一組控件中的第一個控件。*/,
??????????? 95, 10, 50, 26,
??????????? hWnd, (HMENU)2, hInst, NULL
??????? );
??????? radioFemale = CreateWindow(
??????????? TEXT("button"), TEXT("女"),
??????????? WS_CHILD | WS_VISIBLE | BS_LEFT | BS_AUTORADIOBUTTON,
??????????? 150, 10, 50, 26,
??????????? hWnd, (HMENU)3, hInst, NULL
??????? );
??????? //選擇婚姻狀況
??????? labMarriage = CreateWindow(
??????????? TEXT("static"), TEXT("婚姻狀況:"),
??????????? WS_CHILD | WS_VISIBLE | SS_CENTERIMAGE | SS_RIGHT,
??????????? 10, 40, 80, 26,
??????????? hWnd, (HMENU)4, hInst, NULL
??????? );
??????? radioMarried = CreateWindow(
??????????? TEXT("button"), TEXT("已婚"),
??????????? WS_CHILD | WS_VISIBLE | BS_LEFT | BS_AUTORADIOBUTTON | WS_GROUP,
??????????? 95, 40, 65, 26,
??????????? hWnd, (HMENU)5, hInst, NULL
??????? );
??????? radioSingle = CreateWindow(
??????????? TEXT("button"), TEXT("未婚"),
??????????? WS_CHILD | WS_VISIBLE | BS_LEFT | BS_AUTORADIOBUTTON,
??????????? 165, 40, 65, 26,
??????????? hWnd, (HMENU)6, hInst, NULL
??????? );
??????? radioSecrecy = CreateWindow(
??????????? TEXT("button"), TEXT("保密"),
??????????? WS_CHILD | WS_VISIBLE | BS_LEFT | BS_AUTORADIOBUTTON,
??????????? 235, 40, 100, 26,
??????????? hWnd, (HMENU)7, hInst, NULL
??????? );
??????? //你的寵物
??????? labPet = CreateWindow(
??????????? TEXT("static"), TEXT("你的寵物:"),
??????????? WS_CHILD | WS_VISIBLE | SS_CENTERIMAGE | SS_RIGHT,
??????????? 10, 70, 80, 26,
??????????? hWnd, (HMENU)8, hInst, NULL
??????? );
??????? checkboxDog = CreateWindow(
??????????? TEXT("button"), TEXT("狗"),
??????????? WS_CHILD | WS_VISIBLE | BS_LEFT | BS_AUTOCHECKBOX/*復選框*/,
??????????? 95, 70, 50, 26,
??????????? hWnd, (HMENU)9, hInst, NULL
??????? );
??????? checkboxCat = CreateWindow(
??????????? TEXT("button"), TEXT("貓"),
??????????? WS_CHILD | WS_VISIBLE | BS_LEFT | BS_AUTOCHECKBOX,
??????????? 150, 70, 50, 26,
??????????? hWnd, (HMENU)10, hInst, NULL
??????? );
??????? checkboxFish = CreateWindow(
??????????? TEXT("button"), TEXT("魚"),
??????????? WS_CHILD | WS_VISIBLE | BS_LEFT | BS_AUTOCHECKBOX,
??????????? 205, 70, 50, 26,
??????????? hWnd, (HMENU)11, hInst, NULL
??????? );
??????? checkboxOther = CreateWindow(
??????????? TEXT("button"), TEXT("其他"),
??????????? WS_CHILD | WS_VISIBLE | BS_LEFT | BS_AUTOCHECKBOX,
??????????? 260, 70, 65, 26,
??????????? hWnd, (HMENU)12, hInst, NULL
??????? );
??????? //創建按鈕控件
??????? btnSubmit = CreateWindow(TEXT("button"), TEXT("提 交"),
??????????? WS_CHILD | WS_VISIBLE | WS_BORDER | BS_FLAT,
??????????? 95, 110, 200, 36,
??????????? hWnd, (HMENU)13, hInst, NULL
??????? );
??????? SendMessage(labSex, WM_SETFONT, (WPARAM)hFont, 0);
??????? SendMessage(radioMale, WM_SETFONT, (WPARAM)hFont, 0);
??????? SendMessage(radioFemale, WM_SETFONT, (WPARAM)hFont, 0);
??????? SendMessage(labMarriage, WM_SETFONT, (WPARAM)hFont, 0);
??????? SendMessage(radioMarried, WM_SETFONT, (WPARAM)hFont, 0);
??????? SendMessage(radioSingle, WM_SETFONT, (WPARAM)hFont, 0);
??????? SendMessage(radioSecrecy, WM_SETFONT, (WPARAM)hFont, 0);
??????? SendMessage(labPet, WM_SETFONT, (WPARAM)hFont, 0);
??????? SendMessage(checkboxDog, WM_SETFONT, (WPARAM)hFont, 0);
??????? SendMessage(checkboxCat, WM_SETFONT, (WPARAM)hFont, 0);
??????? SendMessage(checkboxFish, WM_SETFONT, (WPARAM)hFont, 0);
??????? SendMessage(checkboxOther, WM_SETFONT, (WPARAM)hFont, 0);
??????? SendMessage(btnSubmit, WM_SETFONT, (WPARAM)hFont, 0);
??????? break;
??? case WM_COMMAND:
??????? wmId = LOWORD(wParam);
??????? wmEvent = HIWORD(wParam);
??????? if (wmEvent == BN_CLICKED) {
??????????? switch (wmId) {
??????????????? //獲取性別
??????????? case 2:
??????????? case 3:
??????????????? GetWindowText((HWND)lParam, szBufSex, 10);
??????????????? break;
??????????????? //獲取婚姻狀況
??????????? case 5:
??????????? case 6:
??????????? case 7:
??????????????? GetWindowText((HWND)lParam, szBufMarriage, 10);
??????????????? break;
??????????????? //獲取寵物
??????????? case 9:
??????????? case 10:
??????????? case 11:
??????????? case 12:
??????????? ??? //memset(szBufPet, 0, sizeof(szBufPet));
??????????????? RtlZeroMemory(szBufPet, 20);
??????????????? //是否選中狗
??????????????? if (SendMessage(checkboxDog, BM_GETCHECK, 0, 0) == BST_CHECKED)
{
??????????????????? GetWindowText(checkboxDog, szBufTmp, 10);
??????????????????? wsprintf(szBufPet, TEXT("%s? %s"), szBufPet, szBufTmp);
??????????????????? RtlZeroMemory(szBufTmp, 10);
??????????????? }
??????????????? //是否選中貓
??????????????? if (SendMessage(checkboxCat, BM_GETCHECK, 0, 0) == BST_CHECKED)
{
??????????????????? GetWindowText(checkboxCat, szBufTmp, 10);
??????????????????? wsprintf(szBufPet, TEXT("%s? %s"), szBufPet, szBufTmp);
??????????????????? RtlZeroMemory(szBufTmp, 10);
??????????????? }
??????????????? //是否選中魚
??????????????? if (SendMessage(checkboxFish,
BM_GETCHECK, 0, 0) == BST_CHECKED)
{
??????????????????? GetWindowText(checkboxFish, szBufTmp, 10);
??????????????????? wsprintf(szBufPet, TEXT("%s? %s"), szBufPet, szBufTmp);
??????????????????? RtlZeroMemory(szBufTmp, 10);
??????????????? }
??????????????? //是否選中其他
??????????????? if (SendMessage(checkboxOther, BM_GETCHECK, 0, 0)
== BST_CHECKED)
{
??????????????????? GetWindowText(checkboxOther, szBufTmp, 10);
??????????????????? wsprintf(szBufPet, TEXT("%s? %s"), szBufPet, szBufTmp);
??????????????????? RtlZeroMemory(szBufTmp, 10);
??????????????? }
??????????????? break;
??????????? case 13:
??????????????? wsprintf(szBufSubmit,
TEXT("你的性別:%s\n婚姻狀況:%s\r\n你的寵物:%s"), szBufSex, szBufMarriage, szBufPet);
??????????????? MessageBox(hWnd, szBufSubmit, TEXT("信息提示"),
MB_ICONINFORMATION);
??????????????? break;
??????????? }
??????? }
??????? return 0;
??? case WM_PAINT:
??????? hdc = BeginPaint(hWnd, &ps);
??????? //繪制...
??????? EndPaint(hWnd, &ps);
??????? break;
??? case WM_DESTROY:
??????? DeleteObject(hFont);
??????? PostQuitMessage(0);
??????? break;
??? default:
??????? return DefWindowProc(hWnd, message, wParam, lParam);
??? }
??? return 0;
}
/******************************************************************************
CreateFont函數:創建具有指定特性的邏輯字體。隨后可以將邏輯字體選擇為任何設備的字體。
HFONT CreateFontA(
? int??? cHeight,??????? //字體的字符單元格或字符的高度(以邏輯單位為單位)。
? int??? cWidth,???????? //所請求字體中字符的平均寬度(以邏輯單位表示)
? int ???cEscapement,??? //擒縱矢量和設備x軸之間的角度,以十分之一度為單位。擒縱向量平行于一行文本的基線。
? int??? cOrientation,?? //每個字符的基線和設備的x軸之間的角度,以十分之一度為單位。
? int??? cWeight,??????? //字體的權重范圍為0到1000。例如,正常時為400,粗體為700。如果該值為零,則使用默認權重。
? DWORD? bItalic,??????? //如果設置為TRUE,則指定斜體字體。
? DWORD? bUnderline,???? //如果設置為TRUE,則指定帶下劃線的字體。
? DWORD? bStrikeOut,???? //刪除線字體,如果設置為TRUE。
? DWORD? iCharSet,?????? //字符集。DEFAULT_CHARSET
? DWORD? iOutPrecision,? //輸出精度OUT_CHARACTER_PRECIS
? DWORD? iClipPrecision, //裁剪精度OUT_CHARACTER_PRECIS
? DWORD? iQuality,?????? //輸出質量。DEFAULT_QUALITY
? DWORD? iPitchAndFamily,//字體的間距和系列。FF_DONTCARE
? LPCSTR pszFaceName???? //指向以空字符結尾的字符串的指針,該字符串指定字體的字體名稱。
);
*******************************************************************************
GetWindowText函數:將指定窗口標題欄(如果有的話)的文本復制到緩沖區中
int GetWindowTextA(
? HWND? hWnd,?????? //包含文本的窗口或控件的句柄
? LPSTR lpString,?? //將接收文本的緩沖區
? int?? nMaxCount?? //要復制到緩沖區的最大字符數,包括空字符。如果文本超出此限制,則會被截斷
);
*/
運行結果:
?
圖8-2 單選框和復選框狀態判斷
?
總結
?????? 實例BTNSTATE.C繪制了3個靜態文本控件(8.2節詳細講述),兩組單選按鈕控件,一組復選按鈕控件和一個單獨的“提交”按鈕。點擊“提交”按鈕時,會彈出一個MessageBox框,顯示用戶選擇的按鈕控件信息。
?????? 在窗口過程的WM-CREATE消息中,首先調用CreateFont函數創建一個新的邏輯字體,接著調用CreateWindow函數分別創建3個靜態文本控件和10個按鈕控件。然后調用SendMessage函數由主窗口向所有控件子窗口發送WM_SETFONT消息,設置子窗口控件的字體使用新創建的邏輯字體。
?????? 處理WM-COMMAND消息,wParam參數的低字為子窗口控件ID,高字為控件通知碼。如果主窗口捕捉的通知碼為BN_CLICKED時,依據子窗口控件ID分別調用GetWindowText函數獲取子窗口控件文本信息存入緩沖區。
?????? 【注意】如果是復選框按鈕控件,需要先調用SendMessage函數向復選框按鈕控件發送BM_GETCHECK消息獲取選中狀態,如果返回值是BST_CHECKED則表示已選中狀態。
?????? 最后如果點擊“提交”按鈕控件,則調用MessageBox函數在對話框中顯示按鈕控件選中信息。
?????? ●主窗口與子窗口控件的信息交互
??? 主窗口使用SendMessage函數向子窗口控件發送消息,獲取或設置狀態信息。
??? 子窗口控件通過向主窗口過程發送WM_COMMAND消息傳遞信息。通過WM_COMMAND消息的wParam參數低字傳遞控件ID,高字傳遞控件通知碼,lParam參數為控件句柄。
8.1.7 第50練:自定義按鈕控件
/*------------------------------------------------------------------
050? WIN32 API 每日一練
???? 第50個例子OWNDRAW.C:自定義按鈕控件
???? WM_DRAWITEM 消息
???? WM_COMMAND消息
???? BS_OWNERDRAW按鈕控件樣式
???? MoveWindow函數
(c) www.bcdaren.com, 2020
----------------------------------------------------------------*/
#include <windows.h>
#define ID_SMALLER 1
#define ID_LARGER 2
#define BTN_WIDTH ( 8 * cxChar)
#define BTN_HEIGHT ( 4 * cyChar)
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
HINSTANCE hInst ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
?PSTR szCmdLine, int iCmdShow)
{
???? static TCHAR szAppName[] = TEXT("OwnDraw");
??? …(略)
???? return msg.wParam;
}
void Triangle (HDC hdc, POINT pt[]) //繪制三角形
{
???? SelectObject(hdc, GetStockObject(BLACK_BRUSH));
???? Polygon(hdc, pt, 3);
???? SelectObject(hdc, GetStockObject(WHITE_BRUSH));
}
LRESULT CALLBACK WndProc ( HWND hwnd, UINT message, WPARAM wParam,LPARAM lParam)
{
????? static HWND hwndSmaller, hwndLarger ;
????? static int cxClient, cyClient, cxChar, cyChar ;
????? int cx, cy ;
//提供所有者窗口用來確定如何繪制所有者繪制的控件或菜單項的信息
????? LPDRAWITEMSTRUCT pdis ;
????? POINT pt[3] ;
????? RECT rc ;
????? switch (message)
????? {
????? case WM_CREATE :
?????????? cxChar = LOWORD (GetDialogBaseUnits ());//獲取系統默認對話框字體寬度
?????????? cyChar = HIWORD (GetDialogBaseUnits ());//獲取系統默認對話框字體高度
?????????? //? 創建自繪按鈕
?????????? hwndSmaller = CreateWindow (TEXT ("button"), TEXT (""), //無標題
???????????????????? WS_CHILD | WS_VISIBLE | BS_OWNERDRAW, //自繪按鈕控件
???????????????????? 0, 0, BTN_WIDTH, BTN_HEIGHT,
???????????????????? hwnd, (HMENU) ID_SMALLER, hInst, NULL) ;
?????????? hwndLarger = CreateWindow (TEXT ("button"), TEXT (""),
???????????????????? WS_CHILD | WS_VISIBLE | BS_OWNERDRAW,
???????????????????? 0, 0, BTN_WIDTH, BTN_HEIGHT,
???????????????????? hwnd, (HMENU) ID_LARGER, hInst, NULL) ;
?????????? return 0 ;
????? case WM_SIZE :
?????????? cxClient = LOWORD (lParam) ;
?????????? cyClient = HIWORD (lParam) ;
????????? //更改指定窗口的位置和尺寸,將按鈕移動到新中心
?????????? MoveWindow ( hwndSmaller, cxClient / 2 - 3 *
??????????????? BTN_WIDTH / 2,
??????????????? cyClient / 2 - BTN_HEIGHT / 2,
??????????????? BTN_WIDTH, BTN_HEIGHT, TRUE);//指示是否重新繪制窗口
?????????? MoveWindow(hwndLarger, cxClient / 2 + BTN_WIDTH /
??????????????? 2, cyClient / 2 - BTN_HEIGHT / 2,
??????????????? BTN_WIDTH, BTN_HEIGHT, TRUE);//指示是否重新繪制窗口
?????????? return 0 ;
???? //收到點擊按鈕消息
????? case WM_COMMAND :
?????????? GetWindowRect (hwnd, &rc) ;
??????????? //每次10%放大或縮小窗口
?????????? switch (LOWORD(wParam))
?????????? {
?????????? case ID_SMALLER:
??????????????? rc.left += cxClient / 20;??? //左邊縮小5%
??????????????? rc.right -= cxClient / 20;?? //左邊縮小5%
??????????????? rc.top += cyClient / 20;???? //上邊縮小5%
??????????????? rc.bottom -= cyClient / 20;? //下邊縮小5%
??????????????? break;
?????????? case ID_LARGER:
??????????????? rc.left -= cxClient / 20;??? //左邊擴大5%
??????????????? rc.right += cxClient / 20;?? //左邊擴大5%
??????????????? rc.top -= cyClient / 20;???? //上邊擴大5%
??????????????? rc.bottom += cyClient / 20;? //下邊擴大5%
??????????????? break;
?????????? }
????????? //更改指定窗口的位置和尺寸,將按鈕移動到新中心
?????????? MoveWindow ( hwnd, rc.left, rc.top, rc.right - rc.left,
?????????????? rc.bottom - rc.top, TRUE) ;
?????????? return 0 ;
???? //收到按鈕外觀改變消息--自繪按鈕
????? case WM_DRAWITEM :
?????????? pdis = (LPDRAWITEMSTRUCT) lParam ;
????????? //畫白色矩形和黑色邊框?
?????????? FillRect (pdis->hDC, &pdis->rcItem,
?????????? (HBRUSH) GetStockObject (WHITE_BRUSH)) ;?
?????????? FrameRect ( pdis->hDC, &pdis->rcItem,
?????????? ( HBRUSH) GetStockObject (BLACK_BRUSH)) ;
????????? //畫向內和向外的黑色三角形
?????????? cx = pdis->rcItem.right - pdis->rcItem.left ;
?????????? cy = pdis->rcItem.bottom - pdis->rcItem.top ;
?????????? switch (pdis->CtlID)
?????????? {
?????????? case ID_SMALLER:
?????????????? //上邊的三角形
??????????????? pt[0].x = 3 * cx / 8; pt[0].y = 1 * cy / 8;
??????????????? pt[1].x = 5 * cx / 8; pt[1].y = 1 * cy / 8;
??????????????? pt[2].x = 4 * cx / 8; pt[2].y = 3 * cy / 8;
??????????????? Triangle(pdis->hDC, pt);
?????????????? //下邊的三角形
??????????????? pt[0].x = 7 * cx / 8; pt[0].y = 3 * cy / 8;
??????????????? pt[1].x = 7 * cx / 8; pt[1].y = 5 * cy / 8;
??????????????? pt[2].x = 5 * cx / 8; pt[2].y = 4 * cy / 8;
??????????????? Triangle(pdis->hDC, pt);
?????????????? //左邊的三角形
??????????????? pt[0].x = 5 * cx / 8; pt[0].y = 7 * cy / 8;
??????????????? pt[1].x = 3 * cx / 8; pt[1].y = 7 * cy / 8;
??????????????? pt[2].x = 4 * cx / 8; pt[2].y = 5 * cy / 8;
??????????????? Triangle(pdis->hDC, pt);
?????????????? //右邊的三角形
??????????????? pt[0].x = 1 * cx / 8; pt[0].y = 5 * cy / 8;
??????????????? pt[1].x = 1 * cx / 8; pt[1].y = 3 * cy / 8;
??????????????? pt[2].x = 3 * cx / 8; pt[2].y = 4 * cy / 8;
??????????????? Triangle(pdis->hDC, pt);
??????????????? break;
?????????? case ID_LARGER:
?????????????? //上邊的三角形??????????????
??????????????? pt[0].x = 5 * cx / 8; pt[0].y = 3 * cy / 8;
??????????????? pt[1].x = 3 * cx / 8; pt[1].y = 3 * cy / 8;
??????????????? pt[2].x = 4 * cx / 8; pt[2].y = 1 * cy / 8;
??????????????? Triangle(pdis->hDC, pt);
?????????????? //下邊的三角形
??????????????? pt[0].x = 5 * cx / 8; pt[0].y = 5 * cy / 8;
??????????????? pt[1].x = 5 * cx / 8; pt[1].y = 3 * cy / 8;
??????????????? pt[2].x = 7 * cx / 8; pt[2].y = 4 * cy / 8;
??????????????? Triangle(pdis->hDC, pt);
?????????????? //左邊的三角形
??????????????? pt[0].x = 3 * cx / 8; pt[0].y = 5 * cy / 8;
??????????????? pt[1].x = 5 * cx / 8; pt[1].y = 5 * cy / 8;
??????????????? pt[2].x = 4 * cx / 8; pt[2].y = 7 * cy / 8;
??????????????? Triangle(pdis->hDC, pt);
?????????????? //右邊的三角形
??????????????? pt[0].x = 3 * cx / 8; pt[0].y = 3 * cy / 8;
??????????????? pt[1].x = 3 * cx / 8; pt[1].y = 5 * cy / 8;
??????????????? pt[2].x = 1 * cx / 8; pt[2].y = 4 * cy / 8;
??????????????? Triangle(pdis->hDC, pt);
??????????????? break;
?????????? }
????????? //如果按鈕被選中,則反轉矩形
?????????? if (pdis->itemState & ODS_SELECTED)
?????????????? InvertRect (pdis->hDC, &pdis->rcItem) ;
????????? //如果按鈕有焦點,畫一個焦點矩形
?????????? if (pdis->itemState & ODS_FOCUS)
?????????? {
??????????????? pdis->rcItem.left += cx / 16;
??????????????? pdis->rcItem.top += cy / 16;
??????????????? pdis->rcItem.right -= cx / 16;
??????????????? pdis->rcItem.bottom -= cy / 16;
?????????????? //畫一個焦點矩形
??????????????? DrawFocusRect(pdis->hDC, &pdis->rcItem);
?????????? }
?????????? return 0 ;
????? case WM_DESTROY :
?????????? PostQuitMessage(0);
?????????? return 0;
????? }
????? return DefWindowProc (hwnd, message, wParam, lParam) ;
}
/******************************************************************************
LPDRAWITEMSTRUCT pdis ; //提供所有者窗口用來確定如何繪制所有者繪制的控件或菜單項的信息
typedef struct tagDRAWITEMSTRUCT {
? UINT????? CtlType;??? //控件類型
? UINT????? CtlID;????? //組合框、列表框、按鈕或靜態控件的標識符。此成員不用于菜單項。
? UINT????? itemID;???? //菜單項的菜單項標識符或列表框或組合框中的項的索引。
? UINT????? itemAction; //所需的繪圖操作
? UINT????? itemState;? //當前繪制操作發生后項目的視覺狀態
? HWND????? hwndItem;?? //組合框、列表框、按鈕和靜態控件的控件句柄。
? HDC?????? hDC;??????? //設備上下文的句柄;在控件上執行繪圖操作時必須使用此設備上下文。
? RECT????? rcItem;???? //一個矩形,用于定義要繪制的控件的邊界。
? ULONG_PTR itemData;?? //與菜單項關聯的應用程序定義的值。
} DRAWITEMSTRUCT, *PDRAWITEMSTRUCT, *LPDRAWITEMSTRUCT;
******************************************************************************
在WM_DRAWITEM消息中,IParam參數是一個指針,指向一個DRAWITEMSTRUCT 類型的結構。
OWNDRAW程序將這個指針保存在變量pdis中。這個結構存有必要的信息 來幫助程序繪制按鈕。
(相同的結構也可用于自繪制列表框和菜單項。)
這個結構中與按鈕 有非常重要關系的字段是:hDC(按鈕設備環境),
rcItem(RECT結構,提供按鈕的尺寸),
CtllD(控件窗口 ID)和itemState(它顯示按鈕是否按下或有輸入焦點)。
******************************************************************************
MoveWindow函數:更改指定窗口的位置和尺寸。
對于頂級窗口,位置和尺寸是相對于屏幕的左上角的。
對于子窗口,它們相對于父窗口客戶區的左上角。
BOOL MoveWindow(
? HWND hWnd,?? //窗口的句柄。
? int? X,????? //窗口左側的新位置。
? int? Y,????? //窗口頂部的新位置。
? int? nWidth, //窗口的新寬度。
? int? nHeight,//窗口的新高度。
? BOOL bRepaint//指示是否要重新繪制窗口。
);
*/
運行結果:
圖8-3 自定義按鈕控件
?
總結
?????? 實例OWNDRAW.C繪制了兩個自定義按鈕控件。如圖8-3所示,一個用于擴大窗口,一個縮小窗口。
?????? 窗口過程在處理WM_CREATE消息時,首先獲取對話框字體的寬和高,然后調用CreateWindow函數創建兩個自定義按鈕控件,創建的方法非常簡單,在窗口樣式參數中添加BS_OWNERDRAW樣式就可以了。
?????? 在WM_SIZE消息中,將自定義按鈕控件移至窗口中心并重繪。
?????? 在WM_COMMAND消息中,根據子窗口控件ID縮放窗口的寬和高。
?????? 在WM_DRAWITEM消息中,繪制自定義按鈕控件的圖形,分別繪制4個向內的三角形和4個向外的三角形,并填充黑色。當按鈕被選中時,調用InvertRect函數將按鈕矩形顏色反轉,并繪制一個焦點矩形。
●DRAWITEMSTRUCT結構
成員 | 常見值 | 備注 |
CtlType | ODT_BUTTON: ?按鈕控件 ODT_COMBOBOX:組合框控件 ODT_LISTBOX: 列表框控件 ODT_LISTVIEW:列表視圖控件 ODT_MENU:????菜單項 ODT_STATIC:??靜態文本控件 ODT_TAB:???? Tab控件 | 控件類型 |
CtlID | 自繪控件ID,而對于菜單項則不需要使用該成員 | |
itemID | 菜單項ID | |
itemAction | ODA_DRAWENTIRE:要整個控件被繪制,設置該值 ODA_FOCUS: 要在獲得或失去焦點時被繪制。 ODA_SELECT:要在選中狀態改變時被繪制。 | 指定繪制行為,其取值可以為右邊中所示值的一個或者多個的聯合 |
itemState | ODS_CHECKED:要菜單被選中,可設置該值 ODS_COMBOBOXEDIT:只繪制組合框中選擇區域 ODS_DEFAULT:默認值 ODS_DISABLED:禁用控件 ODS_FOCUS:控件需要焦點,則該置該值 ODS_GRAYED:控件被灰色 ODS_SELECTED:選中的菜單項 …… | 所繪項的可見狀態 |
hwndItem | 自繪控件的窗口句柄;如果自繪的對象時菜單項,則表示包含該菜單項的菜單句柄。 | |
hDC | 指定了繪制操作所使用的設備環境 | |
rcItem | 指定了將被繪制的矩形區域 | |
itemData |