一、窗口类
窗口类包含了窗口的各种参数信息的数据结构,每个窗口都具有窗口类,基于窗口类创建窗口,每个窗口类都具有一个名称,使用前必须注册到系统。
二、窗口类分类
1、系统窗口类 ,比如按钮button,编辑框edit
系统已经定义好的窗口类,所有应用程序都可以直接使用。
2、应用程序全局窗口类
由用户自己定义,当前应用程序所有模块都可以使用。
3、应用程序局部窗口类(建议多用局部)
由用户自己定义,当前应用程序中本模块可以使用
三、代码实现
1、创建入口函数
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevIns, LPSTR lpCmdLine, int nCmdShow) { g_hInstance = hInstance;//定义全局变量,随时能用 SysReg(); return 0; }
2、窗口注册函数
HINSTANCE g_hInstance = 0; void SysReg() { //系统窗口类不需要用户注册 //创建窗口 HWND hWnd= CreateWindow("button","点击",WS_OVERLAPPEDWINDOW,100,100,300,300,NULL,NULL,g_hInstance,NULL); //显示窗口 ShowWindow(hWnd, SW_SHOW); //消息循环 MSG nMsG = { 0 }; while (GetMessage(&nMsG, NULL, 0, 0)) { TranslateMessage(&nMsG); DispatchMessage(&nMsG); } }
3、运行结果
四、窗口类风格
CS_GLOBALCLASS - 应用程序全局窗口类
CS_BYTEALIGNCLIENT - 窗口客户区的水平位置8倍数对齐
CS_BYTEALIGNWINDOW - 窗口的水平位置8倍数对齐
CS_HREDRAW - 当窗口水平变化时,窗口重新绘制
CS_VREDRAW - 当窗口垂直变化时,窗口重新绘制
CS_CLASSDC - 该类型的窗口,都是有同一个绘图(DC)设备
CS_PARENTDC - 该类型的窗口,使用它的父窗口的绘图(DC)设备
CS_OWNDC - 该类型的窗口,每个窗口都使用自己的绘图(DC)设备
CS_SAVEBITS - 允许窗口保存成图(位图),提高窗口的绘图效率,但是耗费内存资源
CS_DBLCLKS - 允许窗口接收鼠标双击
CS_NOCLOSE - 窗口没有关闭按钮
五、窗口创建
CreateWindow/CreateWindowEx,返回句柄 HWND CreateWindowEx( DWORD dwExStyle, LPCTSTR lpClassName, LPCTSTR lpWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam)
第一个参数:窗口的扩展风格
第二个参数: 已经注册的窗口类名称
第三个参数:窗口标题栏的名字
第四个参数:窗口的基本风格
第五-八个参数:窗口的坐标
第九个参数:窗口的父窗口句柄,没有父类写NULL
第十个参数:窗口的菜单句柄,没有写null
第十一个参数:应用程序实例句柄
第十二个参数:窗口创建时附加参数
六、窗口类的查找过程
局部(类名,实例hInstance)--全局(类名)--系统(类名)
1 系统根据传入的窗口类名称,在应用程序局部窗口类中查找,如果找到执行2,如果未找到执行3。
2 比较局部窗口类与创建窗口时传入的HINSTANCE变量。如果发现相等,创建和注册的窗口类在同一模块,创建窗口返回。如果不相等,继续执行3。
3 在应用程序全局窗口类,如果找到,执行4,如果未找到执行5。
4 使用找到的窗口类的信息,创建窗口返回。
5 在系统窗口类中查找,如果找到创建窗口返回,否则创建窗口失败。
七、代码实现
#include <windows.h> HINSTANCE g_hInstance = 0;//接收当前程序实例句柄 //2、消息处理函数 LRESULT CALLBACK WndProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam) { //7、处理消息 switch (msgID) { case WM_DESTROY: PostQuitMessage(0);//销毁窗口 break; } return DefWindowProc(hWnd, msgID, wParam, lParam); } //3、注册函数,第一个参数,窗口类名称,第二个参数,指向窗口处理函数的函数指针 void Register(LPSTR lpClassName,WNDPROC winProc) { WNDCLASSEX wc = { 0 }; wc.cbSize = sizeof(wc);//结构体大小 wc.cbClsExtra = 0;//窗口类的申请缓存区,0表示不开启缓存 wc.cbWndExtra = 0;//窗口的申请缓存区,0表示不开启缓存 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);//背景颜色,一般白色 wc.hCursor = NULL;//设置光标。null表示默认 wc.hIcon = NULL;//默认左上角的图标 wc.hInstance = g_hInstance;//第一个参数实例句柄,可以找到进程在那块内存 wc.lpfnWndProc = winProc; //lp 一般都是指针,处理函数名或指针 wc.lpszClassName = lpClassName;//窗口类名称,比如公司名字 wc.lpszMenuName = NULL;//没有菜单用null wc.style = CS_HREDRAW | CS_VREDRAW;//窗口变化,会重绘,窗口类的一般风格 RegisterClassEx(&wc); } //4、创建窗口,(窗口类名称,窗口标题栏名称) HWND CreateMain(LPSTR lpClassName, LPSTR lpWindowName) { HWND hWnd= CreateWindowEx(0, lpClassName, lpWindowName, WS_OVERLAPPEDWINDOW, 100, 100, 500, 600, NULL, NULL, g_hInstance, NULL); return hWnd; } //5、显示窗口(窗口句柄) void Display(HWND hWnd) { ShowWindow(hWnd, SW_SHOW);//句柄,显示方式 UpdateWindow(hWnd);//调用一次刷新窗口 } //6、消息循环 void Message() { MSG nMsg = {0}; while (GetMessage(&nMsg,nullptr,0,0)) { TranslateMessage(&nMsg); DispatchMessage(&nMsg); } } //1、入口函数 int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevIns, LPSTR lpCmdLine, int nCmdShow) { g_hInstance = hInstance; Register(LPSTR("主"),WndProc); HWND hWnd = CreateMain(LPSTR("主"),LPSTR("主窗口")); Display(hWnd); Message(); return 0; }
八、子窗口创建
1、创建时要设置父窗口句柄
2、创建风格要增加 WS_CHILD|WS_VISIBLE
HWND CreateChild(LPSTR lpClassName,LPSTR lpWndName,HWND hWnd) { HWND hChild = CreateWindowEx(0, lpClassName, lpWndName, WS_OVERLAPPEDWINDOW | WS_CHILD | WS_VISIBLE, 0, 0, 50, 50, hWnd, NULL, g_hInstance, NULL); return hChild; }
主函数调用
Register(LPSTR("子"),WndProc); HWND hWnd1 = CreateChild(LPSTR("子"), LPSTR("子窗口1"),hWnd); HWND hWnd2 = CreateChild(LPSTR("子"), LPSTR("子窗口2"), hWnd); Display(hWnd1); Display(hWnd2);
或者
Register(LPSTR("子"),DefWindowProc); CreateChild(LPSTR("子"), LPSTR("子窗口1"),hWnd); CreateChild(LPSTR("子"), LPSTR("子窗口2"), hWnd);
九、移动窗口
BOOL MoveWindow( __in HWND hWnd, // 窗口句柄 __in int X, // 左上角x坐标 __in int Y, // 左上角y坐标 __in int nWidth, // 宽 __in int nHeight, // 高 __in BOOL bRepaint // 是否重绘 一般给TRUE ); MoveWindow(hWnd1, 100, 100, 100, 100, TRUE); MoveWindow(hWnd2, 0, 0, 100, 100, TRUE);
运行结果