学习win32 API 编程,我们应该善于利用微软给我们提供的一些辅助工具,例如大家都知道的MSDN、SPY++等等。
今天在讲述之前呢,先给大家介绍一个很有用的工具——Control Spy——它的用途和SPY++有点儿类似,它能查看对应控件所属的风格、能响应的消息以及响应的通知码。
有了它,加上msdn,你基本上就能很快掌握这些控件的用法了——都是基于消息驱动来完成响应的工作
OK,先来讲一下这个小工具的用法(包含个人的学习心得):
(1)在左边子窗口中,选择你想学习的控件,这里我就选择Button
(2)在中间子窗口中你就能预览这个控件的样式
(3)我们知道,这些控件其实本质上都是窗口,因此他们都可以用CreateWindow或者CreateWindowEx函数来创建
下面,我详细讲一下创建的过程(为了帮助说明,我将以CreateWindow函数为例,并贴出该函数的原型声明)
HWND CreateWindow( LPCTSTR lpClassName, // registered class name LPCTSTR lpWindowName, // window name DWORD dwStyle, // window style int x, // horizontal position of window int y, // vertical position of window int nWidth, // window width int nHeight, // window height HWND hWndParent, // handle to parent or owner window HMENU hMenu, // menu handle or child identifier HINSTANCE hInstance, // handle to application instance LPVOID lpParam // window-creation data );我只列出需要注意的几个特别参数的设法
1>窗口类的名称lpClassName——微软帮预设了对应控件所关联的窗口类名称——因此,你只需要将它设为TEXT("控件的英文名称")
例如,我这里选择按钮Button,你就可以写为TEXT("button");如果选择组合框ComboBox,就写为TEXT("combobox")
注:名称不区分大小写,因此你在创建主窗口的时候,就不能将主窗口的窗口类名称设为这些控件的名称,免得覆盖了微软预设的控件窗口类名称
2>窗口的风格dwStyle——这时刚刚提到的小工具就起作用了,你可以在它的子窗口Style中,查找对应的类型:
不过类型WS_CHILD是必须添加的,如果你想让改控件一创建就可见,那么就应该还加上WS_VISIBLE
3>父窗口hWndParent,由于这些控件都是子窗口,所以父窗口一定不能为空,这个之情况而定
4>菜单句柄hMenu,这个需要设定为控件的ID号(ID一般就是用宏定义的一些常量,例如:IDB_BUTTON 按钮ID号)
为了类型的匹配,你需要强制转换一下类型:(HMENU)IDB_BUTTON
5>实例句柄hInstance,如果你是在主窗口的WM_CREATE消息中创建控件,那么可以这样设定:((LPCREATESTRUCT)lParam)->hInstance
(4)了解控件能响应的消息:
(5)你还可以操作,这个控件来看看它所响应的消息以及对应的通知码
消息:
通知码:
好了,这个小工具的大致使用方法就介绍到这里,如果你还是不怎么清楚它的用法,可以参见资源下载中提供的英文版帮助文档
光说不练是假把式,还是用程序代码来证明一切
昨天讲了按钮的创建以及使用方法,今天儿就讲一下组合框的使用方法。
还是先来看看实现的效果:
可以看见,我还是使用WinXP以来微软提供的新控件,毕竟要美观些
***************************************************进入代码阶段******************************************************
先在头文件做一些相应的声明
//WINDOW_XP_STYLE.H #include<windows.h> //组合框的ID #define IDCB_COMBOBOX_1 100 #define IDCB_COMBOBOX_2 101 #define IDCB_COMBOBOX_3 103 //组合框的个数 #define NUMS 3 //一些字符串数组,用于显示 TCHAR* tchSmall[] = {TEXT("小美女"), TEXT("小帅哥"), TEXT("小可爱")}; TCHAR* tchBig[] = {TEXT("大美女"), TEXT("大帅哥"), TEXT("小顽皮")}; TCHAR* tchNone[] = {TEXT("漂亮"), TEXT("帅气"), TEXT("可爱")}; //使用WinXP以来提供的心控件 #pragma comment(linker,""/manifestdependency:type='win32' " "name='Microsoft.Windows.Common-Controls' " "version='6.0.0.0' processorArchitecture='*' " "publicKeyToken='6595b64144ccf1df' language='*'"")
因为大部分技术都是在前面博文中讲述过的,这里我就仅仅将完整代码贴出来,内含一定的注释,只要各位有一定的基础,应该是能看懂的^_^
//ComboBox.c #include<windows.h> #include"Window_Xp_Style.h" LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static TCHAR szAppName[] = TEXT("ComboBox View");//注意这里不能写为ComboBox 因为这样会覆盖微软预设的控件窗口类名称 HWND hwnd; MSG msg; WNDCLASS wndclass; int cxScreen, cyScreen; wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = szAppName; if(!RegisterClass(&wndclass)) { MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR); return 0; } cxScreen = GetSystemMetrics(SM_CXSCREEN); cyScreen = GetSystemMetrics(SM_CYSCREEN); hwnd = CreateWindow(szAppName, TEXT("ComboBox Demo"), WS_OVERLAPPEDWINDOW, cxScreen * 7 / 20, cyScreen / 4, cxScreen * 3 / 10, cyScreen / 2, NULL, NULL, hInstance, NULL); ShowWindow(hwnd, iCmdShow); UpdateWindow(hwnd); while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static HWND hComboBox[NUMS];//组合框窗口句柄数组(有3个) int iCombID[] = {IDCB_COMBOBOX_1, IDCB_COMBOBOX_2, IDCB_COMBOBOX_3};//组合框ID数组 HFONT hFont;//字体句柄 LOGFONT lf; int i, xPos, yDiv;//循环变量、组合框x坐标、y坐标上的间距 switch(message) { case WM_CREATE: //创建组合框 for(i=0; i<NUMS; i++) { hComboBox[i] = CreateWindow(TEXT("combobox"), TEXT(""), WS_CHILD | WS_VISIBLE | CBS_DROPDOWN | CBS_HASSTRINGS | CBS_SIMPLE, 0, 0, 0, 0, hwnd, (HMENU)iCombID[i], ((LPCREATESTRUCT)lParam)->hInstance, NULL); } //添加子项 for(i=0; i<NUMS; i++) SendMessage(hComboBox[0], CB_ADDSTRING, 0, (LPARAM)tchSmall[i]); for(i=0; i<NUMS; i++) SendMessage(hComboBox[1], CB_ADDSTRING, 0, (LPARAM)tchBig[i]); for(i=0; i<NUMS; i++) SendMessage(hComboBox[2], CB_ADDSTRING, 0, (LPARAM)tchNone[i]); //设置初始状态选中的子项 for(i=0; i<NUMS; i++) SendMessage(hComboBox[i], CB_SETCURSEL, (WPARAM)0, 0); //创建字体 ZeroMemory(&lf, sizeof(LOGFONT)); lf.lfHeight = -10; hFont = CreateFontIndirect(&lf); //修改当前的字体 for(i=0; i<NUMS; i++) SendMessage(hComboBox[i], WM_SETFONT, (WPARAM)hFont, 0); return 0; case WM_SIZE: //随着窗口大小的改变而移动组合框 xPos = (LOWORD(lParam) - 100) / 2; yDiv = HIWORD(lParam) / (NUMS + 2); for(i=0; i<NUMS; i++) MoveWindow(hComboBox[i], xPos, yDiv * (i + 1), 100, 20, TRUE); return 0; //响应组合框子项选择的消息 case WM_COMMAND: //判断控件的ID switch(LOWORD(wParam)) { case IDCB_COMBOBOX_1: //判断当前控件对应的通知码 if(HIWORD(wParam) == CBN_SELENDOK)//选择了组合框的子项 { LRESULT index; index = SendMessage(hComboBox[0], CB_GETCURSEL, 0, 0); if(CB_ERR != index) MessageBox(hwnd, tchSmall[(int)index], TEXT("提示"), MB_OK); } break; case IDCB_COMBOBOX_2: //判断当前控件对应的通知码 if(HIWORD(wParam) == CBN_SELENDOK) { LRESULT index; index = SendMessage(hComboBox[1], CB_GETCURSEL, 0, 0); if(CB_ERR != index) MessageBox(hwnd, tchBig[(int)index], TEXT("提示"), MB_OK); } break; case IDCB_COMBOBOX_3: //判断当前控件对应的通知码 if(HIWORD(wParam) == CBN_SELENDOK) { LRESULT index; index = SendMessage(hComboBox[2], CB_GETCURSEL, 0, 0); if(CB_ERR != index) MessageBox(hwnd, tchNone[(int)index], TEXT("提示"), MB_OK); } break; } return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); }