今天,咱們還是接著玩“控件斗地主”,這是我原創的超級游戲,有益身心健康,玩一朝,十年少 。
哦,對,腦細胞極速運動了一下,想起了一個問題,這個破問題雖然網上有很多種解決方案 ,但是,並沒有讓所有人都解決問題。
不知道大家有沒有調用過LoadIconMetric函數,這個函 數在靜態庫Comctl32.lib中有定義(當然,動態庫也有),不過,創建項目的時候,默認並沒有引用它 的,於是,大家知道,解決調用的方法就是在代碼中加上:
#pragma comment(lib, "Comctl32.lib")
我一般習慣這種方法,這樣不必去修改項目屬性。但是, 很多朋友說過,在Win 7以後的系統,依然沒有成功,我也嘗到了調用失敗的“甜頭”,我一直在想, 這是為什麼呢?
於是,我又試了另一種方法,就是用LoadLibrary加載Comctl32.dll,然後通過 函數指針去調用它:
typedef LRESULT (WINAPI * pLoadICMT)(.......);
但結果還是沒 成功,GetProcAddress返回的地址為0,又一次嘗到了失敗帶來的“刺激”感。
直到某一天,我 在寫某程序時,從上一文中大家都看到,那個按鈕的視覺風格和Win9x/2000差不多,似乎沒有XP那種充 滿美學水准的效果。其實,這是因為我們的程序沒有啟用視覺效果,默認情況下,使用版本5中的控件 ,而要有XP以上的風格,是在版本6的控件內庫中才有。
當然方法可以很多人都知道,就是定義 一個用於視覺效果的清單文件,本質是XML格式。不過我用的開發工具是VS 2005之後的版本,就不用弄 個XML文件那麼麻煩了,直接到MSDN上復制粘貼這段代碼放到你的代碼文件(.cpp)中,就是這個,直 接抄過來就行了,適當的時候,要巧用MSDN上的資源。
// 開啟視覺效果 Copy from MSDN #pragma comment(linker,"\"/manifestdependency:type='win32' \ name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \ processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
version是版本號,要有好看的效果,記得要6,不要寫用低版本的。processorArchitecture是處理 器平台,x86或amd64,用*號最好,通殺。
真是巧啊,原來這麼一來,噗,LoadIconMetric也能 調用了。總的來說,就是在代碼文件加上以下內容:
#include <CommCtrl.h> //包含頭文件 // 導入靜態庫 #pragma comment(lib, "Comctl32.lib") // 開啟視覺效果 Copy from MSDN #pragma comment(linker,"\"/manifestdependency:type='win32' \ name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \ processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
這問題干掉了,開始今天的吹牛大行動。
單選按鈕,是的,在WinForm裡面你肯定知道, RadioButto,復選框就是CheckBox。不過那個時候.NET還沒那麼猛,那個時代,就是玩VB6,所以我知 道VB裡面,單選按鈕叫Option吧。
然後找遍了Win32的控件庫,怎麼沒見Radio和CheckBox,於 是,我陷入了萬分痛苦之中。不久後閱讀MSDN文檔,我就明白了,其實這兩個玩意兒都是BUTTON類的, 只是應用了不同的style罷了。
好的,咱們先來弄一個單選的吧。
case WM_CREATE: { CreateWindow(L"Button",L"這玩意兒好", BS_RADIOBUTTON | WS_CHILD | WS_VISIBLE, 10,10,150,28, hwnd, (HMENU)IDC_RADBTN1, (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE), NULL); } return 0;
應用BS_RADIOBUTTON樣式,就可以使按鈕變成單選按鈕,不過,別忘了 WS_CHILD | WS_VISIBLE。
運行一下。
不過,當你點擊它的時候,會發現它並不會選中,那是因為BS_RADIOBUTTON樣式不會自動讓 它選上。我們換一種可以自動處理的樣式,帶AUTO打頭的。
就是用 BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE,如下圖的預覽結果。
接下來,我們多創建幾個吧。
/*--------------------------------------- --------------------------*/ //控件ID #define IDC_RADBTN1 50001 #define IDC_RADBTN2 50002 #define IDC_RADBTN3 50003 #define IDC_RADBTNBLUE 51001 #define IDC_RADBTNRED 51002 #define IDC_RADBTNGREEN 51003 /*-----------------------------------------------------------------*/ // 消息處理函數 LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_CREATE: { // 獲取當前實例句柄 HINSTANCE hthisapp = (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE); // 縱坐標,控件將以此作為基准, // 排列時依次增加 int yLoc = 0; // 用來顯示文本 yLoc += 10; CreateWindow(L"Static",L"請問你的性別是:", SS_SIMPLE | WS_CHILD | WS_VISIBLE, 10,yLoc,160,18, hwnd, NULL, hthisapp, NULL); // 第一組單選按鈕 yLoc += 22; CreateWindow(L"Button",L"男", WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON | WS_GROUP, 12, yLoc, 60, 16, hwnd, (HMENU)IDC_RADBTN1, hthisapp,NULL); yLoc += 20; CreateWindow(L"Button",L"女", WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON, 12,yLoc, 60, 16, hwnd,(HMENU)IDC_RADBTN2,hthisapp,NULL); yLoc += 20; CreateWindow(L"Button",L"人妖",WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON, 12,yLoc,60,16,hwnd,(HMENU)IDC_RADBTN3,hthisapp,NULL); // 顯示文本 yLoc += 38; CreateWindow(L"Static",L"你喜歡哪一種顏色?", WS_CHILD | WS_VISIBLE | SS_SIMPLE, 10,yLoc,150,18,hwnd,NULL,hthisapp,NULL); //第二組單選按鈕 yLoc += 22; CreateWindow(L"Button",L"藍色",WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON | WS_GROUP, 12,yLoc,60,16,hwnd,(HMENU)IDC_RADBTNBLUE,hthisapp,NULL); yLoc += 20; CreateWindow(L"Button",L"紅色",WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON, 12,yLoc,60,16,hwnd,(HMENU)IDC_RADBTNRED,hthisapp,NULL); yLoc += 20; CreateWindow(L"Button",L"綠色",WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON, 12,yLoc,60,16,hwnd,(HMENU)IDC_RADBTNGREEN,hthisapp,NULL); } return 0; case WM_DESTROY: PostQuitMessage(0); //平安退出 return 0; default: return DefWindowProc(hwnd,msg,wParam,lParam); } return 0; }
在創建單選框中,為什麼有些加了WS_GROUP樣式,而有些未加呢?
其實是這樣的, 既然單選按鈕是單選的,那麼,任何一個單選按鈕都與其他的單選按鈕是互斥的關系。所以,在同一個 容器(本例是同一個窗口)中就需要把單選按鈕進行分組。
同一組中的單選按鈕相互排斥,他 的分組方法:
順序,以Tab鍵順序為參考,這個不用我介紹,你隨便打開一個窗口,然後多按幾 下Tab鍵你就懂了,如果不懂,那你真的無可救藥了。
凡是設置了WS_GROUP的單選框做為一組中 的首元素,隨後的所有單選按鈕都和它在同一組,直到下一個設置了WS_GROUP樣式的單選按鈕。用上面 的例子來說吧。
性別一組中,第一個應用了WS_GROUP的是“男”,隨後的“女”和“人妖”都 與“男”在同一組,因為後面一個“藍色”設置了WS_GROUP樣式。所以,
第一組為:男,女, 人妖;
第二組為:藍色,紅色,綠色。
顯然,用了BS_AUTORADIOBUTTON後,系統就會自 動處理選擇狀態了。
完整的代碼清單如下:
#include <Windows.h> #include <WindowsX.h> #include <CommCtrl.h> //包含頭文件 // 導入靜態庫 #pragma comment(lib, "Comctl32.lib") // 開啟視覺效果 Copy from MSDN #pragma comment(linker,"\"/manifestdependency:type='win32' \ name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \ processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") // 先聲明一個WindowProc回調 LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); // 入口點 int WINAPI wWinMain(HINSTANCE hTheApp, HINSTANCE hPrevApp, LPWSTR lpCmd, int nShow) { PCWSTR cn = L"My"; // 窗口名 PCWSTR tt = L"應用程序"; // 窗口標題 // 設計窗口類 WNDCLASS wc = { sizeof(WNDCLASS) }; wc.hbrBackground = (HBRUSH)COLOR_WINDOW; wc.lpfnWndProc = WindowProc; wc.style = CS_HREDRAW | CS_VREDRAW; LoadIconMetric(hTheApp, IDI_APPLICATION, LIM_SMALL, &wc.hIcon); wc.lpszClassName = cn; wc.hInstance = hTheApp; RegisterClass(&wc); // 注冊窗口類 // 創建窗口 HWND hwnd = CreateWindow(cn, tt,WS_OVERLAPPEDWINDOW, 28,34,400,330,NULL,NULL,hTheApp,NULL); if( !hwnd) { /* 如果窗口創建失敗, 那繼續執行也沒有意義 長痛不如短痛,結束吧。 */ return 0; } ShowWindow(hwnd,nShow); //顯示窗口 UpdateWindow(hwnd); //更新窗口 // 消息循環 MSG msg; while(GetMessage(&msg,NULL,0,0)) { TranslateMessage(&msg); DispatchMessage(&msg); //調度消息到WindowProc回調 } return 0; } /*-----------------------------------------------------------------*/ //控件ID #define IDC_RADBTN1 50001 #define IDC_RADBTN2 50002 #define IDC_RADBTN3 50003 #define IDC_RADBTNBLUE 51001 #define IDC_RADBTNRED 51002 #define IDC_RADBTNGREEN 51003 #define IDC_BTN_OK 1107 //確定按鈕ID /*-----------------------------------------------------------------*/ // 消息處理函數 LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_CREATE: { // 獲取當前實例句柄 HINSTANCE hthisapp = (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE); // 縱坐標,控件將以此作為基准, // 排列時依次增加 int yLoc = 0; // 用來顯示文本 yLoc += 10; CreateWindow(L"Static",L"請問你的性別是:", SS_SIMPLE | WS_CHILD | WS_VISIBLE, 10,yLoc,160,18, hwnd, NULL, hthisapp, NULL); // 第一組單選按鈕 yLoc += 22; CreateWindow(L"Button",L"男", WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON | WS_GROUP, 12, yLoc, 60, 16, hwnd, (HMENU)IDC_RADBTN1, hthisapp,NULL); yLoc += 20; CreateWindow(L"Button",L"女", WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON, 12,yLoc, 60, 16, hwnd,(HMENU)IDC_RADBTN2,hthisapp,NULL); yLoc += 20; CreateWindow(L"Button",L"人妖",WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON, 12,yLoc,60,16,hwnd,(HMENU)IDC_RADBTN3,hthisapp,NULL); // 顯示文本 yLoc += 38; CreateWindow(L"Static",L"你喜歡哪一種顏色?", WS_CHILD | WS_VISIBLE | SS_SIMPLE, 10,yLoc,150,18,hwnd,NULL,hthisapp,NULL); //第二組單選按鈕 yLoc += 22; CreateWindow(L"Button",L"藍色",WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON | WS_GROUP, 12,yLoc,60,16,hwnd,(HMENU)IDC_RADBTNBLUE,hthisapp,NULL); yLoc += 20; CreateWindow(L"Button",L"紅色",WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON, 12,yLoc,60,16,hwnd,(HMENU)IDC_RADBTNRED,hthisapp,NULL); yLoc += 20; CreateWindow(L"Button",L"綠色",WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON, 12,yLoc,60,16,hwnd,(HMENU)IDC_RADBTNGREEN,hthisapp,NULL); // 創建一個確定按鈕 CreateWindow(L"Button",L"確定",WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, 230,180,80,27,hwnd,(HMENU)IDC_BTN_OK,hthisapp,NULL); } return 0; case WM_DESTROY: PostQuitMessage(0); //平安退出 return 0; default: return DefWindowProc(hwnd,msg,wParam,lParam); } return 0; }