在Visual Studio操作环境中的左侧有三个选项,它们包含应用程序的不同视图,FileView(文件视图),ClassView(类视图),ResourceView(资源视图).
窗口的创建:①、设计一个窗口类;②、注册窗口;③、创建窗口;④、显示及更新窗口
Windows程序的入口函数:WinMain函数
int WINAPI WinMain( //WinMain是由操作系统调用 HINSTANCE bInstance,//应用程序的实例句柄,指示当前句柄 HINSTANCE bPrevInstance,//指示先前句柄 LPSTR IpCmdLine,//字符串类型,相当于char *类型; int nCmdSbow );
句柄是资源的标识,按照资源的类型可以分为:图标句柄(HICON),光标句柄(HCURSOR),窗口句柄(HWND),应用程序实例句柄(HINSTANCE).
设计窗口类:
typedef struct_WNDCLASS{ UINT style;//相当于c语言中的unsigned int,无符号整形,style是指定类风格,例CS_VREDRAW: 当垂直长度改变或移动窗口时,重画整个窗口 WNDPROC lpfnWndProc;//指向窗口过程,也称为回调函数 int cbClsExtra;//指定紧随在WNDCLASS数据结构后分配的字节数,系统将其初始化为零 int cbWndExtra;//指定紧随在窗口实例之后分配的字节数,系统将其初始化为零 HANDLE hInstance;//标识了该窗口类的窗口过程所在的模块实例的句柄,不能为NULL HICON hIcon;//标识了该窗口类的图标.hIcon字段必须是一个图标的句柄;若hIcon字段为NULL,则无论何时用户把应用程序缩至最小时,应用程序必须画一个图标 HCURSOR hCursor;//标识该窗口类的光标,它是一个光标资源的句柄,若hCursor字段为NULL,则无论何时鼠标移到应用程序窗口时,应用程序必须显式设置光标形状 HBRUSH hbrBackground;//标识了该窗口类的背景画笔。 LPCTSTR lpszMenuName;//指向NULL结束的字符串,该字符串描述菜单的资源名,如同在资源文件里显示的名字一样 LPCTSTR lpszClassName;// 指向NULL结束的字符串,或者是一个原型(atom) }WNDCLASS;
窗口风格CS:
CS_BYTEALIGNCLIENT: 在字节边界上(在x方向上)定位窗口的用户区域的位置
CS_BYTEALIGNWINDOW: 在字节边界上(在x方向上)定位窗口的位置
CS_CLASSDC: 该窗口类的所有窗口实例都共享一个窗口类DC
CS_DBLCLKS: 允许向窗口发送双击鼠标键的消息
CS_GLOBALCLASS: 当调用CreateWindow 或 CreateWindowEx 函数来创建窗口时允许它的hInstance参数和注册窗口类时传递给RegisterClass 的 hInstance参数不同。如果不指定该风格,则这两个hInstance 必须相同。
CS_HREDRAW: 当水平长度改变或移动窗口时,重画整个窗口
CS_NOCLOSE: 禁止系统菜单的关闭选项
CS_OWNDC: 给予每个窗口实例它本身的DC。注意,尽管这样是很方便,但它必须慎重使用,因为每个DC大约要占800个字节的内存。
CS_PARENTDC: 将子窗口的裁剪区域设置到父窗口的DC中去,这样子窗口便可以在父窗口上绘制自身。注意,这是子窗口还是从系统缓存中获取DC,而不是使用父窗口的DC。使用该风格可以提高系统性能。
CS_SAVEBITS: 以位图形式保存被该窗口遮挡的屏幕部分,这样当给窗口移动以后,系统便可以用该保存的位图恢复屏幕移动的相应部分,从而系统不用向被该窗口遮挡的窗口发送 WM_PAINT 消息。该特性对于菜单类型的窗口比较合适,因为它通常是简短的显示一下之后便消失。设置该特性将增加显示该窗口的时间,因为它通常要先分配保存位图的内存。
CS_VREDRAW: 当垂直长度改变或移动窗口时,重画整个窗口
下面为一个初始化实例:
WNDCLASS wndclass;//定义窗口类的变量 wndclass.style=CS_HREDRAW|CS_VREDRAW;/*其中CS_HREDRAW:当水平长度改变或移动窗口时,重画整个窗口,CS_VREDRAW:当垂直长度改变或移动窗口时,重画整个窗口,'|'是c语言中的或运算,如果我们希望某一变量既具有CS_HREDRAW和CS_VREDRAW特性我们可以用或运算,如果我们要去掉某一特性,可以用进行取反后再进行与运算,如:style&~CS_VREDRAW*/ wndclass.lpfnWndProc=WndProc; //定义窗口处理函数,WndProc是一个函数指针 wndclass.cbClsExtra=0; //设为0即可 wndclass.cbWndExtra=0; //设为0即可 wndclass.hInstance=hInstance; //当前实例句柄 wndclass.hIcon=LoadIcon(NULL,IDI_APPLICATION);//窗口的最小化图标为缺省图标 /********************** HICON LoadIcon{ HINSTANCE hInstance, //设为NULL,若要设置一个标准的图标则这个值必须附值为NULL LPCTSTR lpIconName //图标,可以更改,如IDI-ERROR(图标为一个红色的x)等~ }; **********************/ wndclass.hCursor=LoadCursor(NULL,IDC_ARROW); //窗口采用箭头光标,可以更改,如:IDI_CROSS为十字形光标 /********************* HCURSOR LoadCusor{ HINSTANCE hINstance,//同样若要设置一个标准的光标则这个值必须为NULL LPCTSTR lpIconName//光标 }; *********************/ wndclass.hbrBackground=(HBRUSH)(GetStockObject(WHITE_BRUSH)); //窗口背景为白色,HBRUSH为强制类型转换,可以更改如:BLACK_BRUSH的窗口背景为黑色 /******************** HGDIOBJ GetStockObject{ int fnObject }; ********************/ wndclass.lpszMenuName=NULL; //窗口无菜单 wndclass.lpszClassName=lpszClassName; //窗口类名,可以自己定义lpszclassName的名字,如wndclass.lpszClassName="xuzengqiang";
当我们设置完一个窗口类,我们就需要对这个窗口进行注册,我们可以理解为向操作系统注册,注册方法:需要用到RegisterClass 函数,该函数的模型为:
ATOM RegisterClass( CONST WNDCLASS *lpWndClass//为窗口类的一个指针 );
对于上例中我们已经定义了一个WNDCLASS wndclass变量,所以注册的方法就是:
RegisterClass(&wndclass);
注册成功后我们得创建一个窗口了,用到CreateWindow函数:
HWND CreateWindow( LPCTSTR lpClassName, //注册的类名,这里一定要基于以前注册之后的一个类名去设定 LPCTSTR lpWindowName,//窗口的名字, DWORD dwStyle, //窗口的类型,有很多的风格,如:WS_BORDER:创建一个单边框的窗口;WS_HSCROLL:创建一个有水平滚动条的窗口等~同样这个窗口要具有多种类型可以利用或运算 int x, //窗口的水平坐标,窗口的左上角坐标 int y, //窗口的垂直坐标, int nWidth,//窗口的宽度 int nHeigh,//窗口的高度 HWND hWndParent, //指示为副窗口句柄,若只有一个窗口,则赋为NULL HMENU hMenu, //菜单句柄,若没有菜单则设为NULL HANDLE hlnstance, //当前实例的一个句柄 LPVOID lpParam /*指向一个值的指针,该值传递给窗口WM_CREATE消息.该值通过在IParam参数中的CREATESTRUCT结构传递,如果应用程序调用CreateWindow创建 一个MDI客户窗口,则lpParam必须指向一个CLIENTCREATESTRUCT结构.用不到设为NULL*/ );
窗口类型(Windows Style):
WS_BORDER 有边框窗口
WS_CAPTION 必须和WS_BORDER风格配合,但不能与WS_DLGFRAME风格一起使用。指示窗口包含标题要部分。
WS_CHILD 说明窗口为子窗口,不能应用于弹出式窗口风格(WS_POPUP)。
WS_CHILDWINDOW 同WS_CHILD。
WS_CLIPCHILDREN 绘制父窗口时,不绘制子窗口的裁剪区域。使用在建立父窗口时。
WS_CLIPSIBLINGS 剪裁相关的子窗口,这意味着,当一个特定的子窗口接收到重绘消息时,WS_CLIPSIBLINGS风格将在子窗口要重画的区域中去掉与其它子窗口重叠的部分。(如果没有指定WS_CLIPSIBLINGS风格,并且子窗口有重叠,当你在一个子窗口的客户区绘图时,它可能会画在相邻的子窗口的客户区中。)只与WS_CHILD风格一起使用。
WS_DISABLED 创建一个初始状态为禁止的窗口。
WS_DLGFRAME 创建一个窗口,具有双重边界,但是没有标题条。
WS_GROUP 指定一组控件中的第一个,用户可以用箭头键在这组控件中移动。在第一个控件后面把WS_GROUP风格设置为FALSE的控件都属于这一组。下一个具有WS_GROUP风格的控件将开始下一组(这意味着一个组在下一组的开始处结束)。
WS_HSCROLL 创建一个具有水平滚动条的窗口。
WS_ICONIC:创建一个初始状态为最小化状态的窗口。与WS_MINIMIZE风格相同。
WS_MAXIMIZE 创建一个最大化的窗口。
WS_MAXIMIZEBOX 创建一个具有最大化按钮的窗口。
WS_MINIMIZE 创建一个初始状态为最小化的窗口。仅与WS_OVERLAPPED风格一起使用。
WS_MINIMIZEBOX 创建一个具有最小化按钮的窗口。
WS_OVERLAPPED 创建一个重叠窗口。重叠窗口通常具有标题条和边界。
WS_OVERLAPPEDWINDOW 创建一个具有WS_OVERLAPPED,WS_CAPTION,WS_SYSMENU,WS_THICKFRAME,WS_MINIMIZEBOX和WS_MAXIMIZEBOX风格的重叠式窗口。
WS_POPUP 创建一个弹出式窗口,不能与WS_CHILD风格一起使用。
WS_POPUPWINDOW 创建一个具有WS_BORDER,WS_POPUP和WS_SYSMENU风格的弹出窗口。为了使控制菜单可见,必须与WS_POPUPWINDOW一起使用WS_CAPTION风格。
WS_SIZEBOX:创建一个可调边框的窗口,与WS_THICKFRAME风格相同。
WS_SYSMENU 创建一个在标题条上具有控制菜单的窗口。仅对带标题条的窗口使用。
WS_TABSTOP 指定了一些控件中的一个,用户可以通过TAB键来移过它。TAB键使用户移动到下一个用WS_TABSTOP风格定义的控件。
WS_THICKFRAME 创建一个具有厚边框的窗口,可以通过厚边框来改变窗口大小。
WS_TILED:产生一个层叠的窗口。一个层叠的窗口有一个标题和一个边框。与WS_OVERLAPPED风格相同。
WS_TILEDWINDOW:创建一个具有WS_OVERLAPPED,WS_CAPTION,WS_SYSMENU,MS_THICKFRAME风格的窗口。
WS_VISIBLE 创建一个最初可见的窗口。
WS_VSCROLL 创建一个具有垂直滚动条的窗口。
当然我们在创建一个窗口时得先创建一个句柄:
HWND hwnd; hWnd=CreateWindow("xuzengqiang","许增强",WS_SYSMENU|WS_VISIBLE,CW_USEDEFAULT,CW_USEDEFAULT,400,300,NULL,NULL,0,NULL);
窗口创建完成后我们得将窗口显示出来,用到ShowWindow函数
BOOL ShowWindow( HWND hWnd, int nCmdShow//显示的状态,例如:SW_MAXIMIZE:最大化指定的窗口,SW_SHOWMAXIMIZED:激活窗口并将其最大化 );
例如:
ShowWindow(hwnd,SW_SHOWMAXIZED);
显示窗口后我们还得做一个更新窗口的函数:UpdateWindow函数 //其实这个函数可有可无
BOOL UpdateWindow( HWND hWnd // 窗口的句柄 );
例如:UpdateWindow(hwnd);
消息循环:
MSG msg; while(GetMessage(&msg,NULL,0,0)) //消息循环 { TranslateMessage(&msg); //转化虚拟按键到字符消息,对取到的消息队进行转换,生成字符消息WM_CHAR DispatchMessage(&msg); //分派消息调用回调函数,将消息路由给操作系统 }
Getmessage函数
BOOL GetMessage( LPMSG lpMsg,//指向MSG结构的指针,该结构从线程的消息队列里接收消息信息。 HWND hWnd,//取得其消息的窗口的句柄,这是一个有特殊含义的值(NULL),GetMessage为任何属于调用线程的窗口检索消息,线程消息通过PostThreadMessage寄送给调用线程。 UINT wMsgFilterMin,//指定被检索的最小消息值的整数 UINT wMsgFilterMax //指定被检索的最大消息值的整数 );
MSG结构体:
typedef struct tagMSG { HWND hwnd; UINT message; WPARAM wParam; LPARAM lParam; DWORD time; POINT pt; } MSG;
现在主要分析下窗口类中的回调函数(WNDPROC lpfnWndProc;)
LRESULT CALLBACK WndProc( //WndProc名称可自由定义,参数的类型不能更改 HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
MessageBox函数:弹出一个窗口,创建、显示、和操作一个消息框。消息框含有应用程序定义的消息和标题,加上预定义图标与Push(下按)按钮的任何组合。
int MessageBox( HWND hWnd, LPCTSTR lpText,//指向一个以NULL结尾的、含有将被显示的消息的字符串的指针,即显示在窗口的内容 LPCTSTR lpCaption,//指向一个以NULL结尾的、用于对话框标题的字符串的指针.窗口的标题 UINT UType//指定一个决定对话框的内容和行为的位标志集,例如:MB_OKCANCEL:消息框含有两个按钮:OK和Cancel。它是消息框的一个类型,有很多~例:MB_YES,会出现一个OK的button. );
下面是一个完整的编译过程,打开VC/新建/Win32 Application/设置位置和工程名字后按确定,新建/c++ source File后敲入代码即可.
#include<windows.h> #include<stdio.h> LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ); int WINAPI WinMain( HINSTANCE bInstance, HINSTANCE bPrevInstance, LPSTR IpCmdLine, int nCmdShow ) { WNDCLASS wndclass; char lpszClassName[]="xuzengqiang"; wndclass.style=CS_HREDRAW|CS_VREDRAW; wndclass.lpfnWndProc=WndProc; wndclass.cbClsExtra=0; wndclass.cbWndExtra=0; wndclass.hInstance=0; wndclass.hIcon=LoadIcon(NULL,IDI_ERROR); wndclass.hCursor=LoadCursor(NULL,IDC_CROSS); wndclass.hbrBackground=(HBRUSH)(GetStockObject(WHITE_BRUSH)); wndclass.lpszMenuName=NULL; wndclass.lpszClassName=lpszClassName; RegisterClass(&wndclass);//一定要记得注册一个窗口 HWND hwnd; hwnd=CreateWindow("xuzengqiang","许增强",WS_SYSMENU|WS_VISIBLE|WS_MAXIMIZEBOX|WS_MINIMIZEBOX|WS_SIZEBOX,CW_USEDEFAULT,CW_USEDEFAULT,400,200,NULL,NULL,0,NULL); ShowWindow(hwnd,nCmdShow);//这里的nCmdShow得与WinMain中设置的参数一致 UpdateWindow(hwnd); MSG msg; while(GetMessage(&msg,NULL,0,0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return 0; } LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ) { HDC hdc;//HDC是一个DC句柄,类似于一个指针的类型,DC全称为Device Contexts,设备上下文。 PAINTSTRUCT ps; switch(message)//下面是针对不同的消息作出响应 { case WM_CHAR: //用户按下了键盘上的某个键 char szchar[20]; sprintf(szchar,"char is %d",wParam); MessageBox(hwnd,szchar,"xuzengqiang",0); break; case WM_LBUTTONDOWN: //当用户在window客户区域点击鼠标左键的时候发送 MessageBox(hwnd,"mouse click","xuzengqiang",0);//若是只需要一个确定按钮,可以直接设为0-转换为16进制就代表MB_OK hdc=GetDC(hwnd);//获取DC的句柄 TextOut(hdc,0,20,"许增强",strlen("许增强")); ReleaseDC(hwnd,hdc); //释放DC,由于DC是系统内部维护的一个数据结构,也会占内存,所以一定要注意,当我们的到一个DC的时候,如果我们忘了释放DC的话就会造成内存的泄漏 break; case WM_PAINT://要求一个窗口重绘自己 hdc=BeginPaint(hwnd,&ps);//获取DC的句柄,它会填充一个PAINTSTRUT的结构体 TextOut(hdc,0,0,"许增强",strlen("许增强"));//文本输出函数,往窗口上输出一串文本 /*********************************** BOOL TextOut( HDC hdc, // 设备描述表句柄 int nXStart, // 字符串的开始位置 x坐标 int nYStart, // 字符串的开始位置 y坐标 LPCTSTR lpString, // 字符串 int cbString // 字符串中字符的个数 ); ***********************************/ EndPaint(hwnd,&ps);//释放DC break; case WM_CLOSE://当一个程序和应用程序要关闭是发出一个信号 if(IDYES==MessageBox(hwnd,"是否退出程序?","xuzengqiang",MB_YESNO)) //消息框包含两个按钮,YES和NO,Message具有返回值,IDYES是返回值,当点击YES时返回YES,若是点击NO,则返回IDNO { DestroyWindow(hwnd);//销毁窗口,它会返回一个WM_DESTORY消息,下面的一个case语句 } break; case WM_DESTROY://一个窗口被销毁 PostQuitMessage(0);//通知系统线程请求终止 break; default://不能删~~~ return DefWindowProc(hwnd,message,wParam,lParam);//返回一个缺省的窗口过程,对不感兴趣的消息提供一个缺省处理 } return 0; }
效果图:点击鼠标左键:
关闭时:
当然还有很多东西没有列上来,建议下个MSDN library,里面的东西很全~~