创建一个窗口的过程
1:创建一个窗口首先要注册一个窗口类,用一个窗口过程处理窗口消息;
2:windows的程序调用
LoadIcon:加载图标
LoadCursor:加载鼠标指针
GetStockObject:获取图形对象
RigisterClass:为程序窗口注册窗口类
MessageBox:显示消息框
CreateWindow:根据窗口类创建一个窗口
ShowWindow:在屏幕上显示窗口
UpdateWindow:指示窗口刷新自身
GetMessage:从消息队列中获取消息
TranslateMessage:转换某些键盘信息
DispatchMessage:将消息发送给窗口过程
PlaySound:播放一个声音文件
BeginPaint:开始窗口绘制
GetClientRect:获取窗口客户区的尺寸
DrawText:显示文本串
EndPaint:结束窗口绘制;
PostQuitMessage:消息队列中插入一条 退出信息
DefWindowProc:执行默认的消息处理
3:大写标识符的前缀表示的含义
CS:类风格选项
CW:创建窗口选项
DT:绘制文本选项
IDI:图标ID号
IDC:光标ID号
MB:消息框选项
SND声音选项
WM:窗口消息
WS:窗口风格
4:新的数据类型
在源程序中的其他标识符是新的数据类型,在Windows头文件中使用typedef语句加以定义;
UINT:一个unsigned int(无符号整数)32位
PSTR:指向一个字符串的指针(char*)
WPARAM:定义成一个UINT(32位无符号整数)
LPARAM:定义成一个LONG(32位有符号整数)
LRESULT:是WndProc函数的返回值,定义成一个LONG
WINAPI:WinMain函数的类型,头文件中的所有Windows函数都被指定成这个类型
CLASSBACK:WndProc指定为该类型(WINAPI和CLASSBACK均为__stdcall类型,指在Windows本身和用户的应用程序之间发生的函数调用的特殊调用序列)
5:Windows头文件定义的四种数据结构
MSG:消息结构
WNDCLASS:窗口类结构
PAINTSTRUCT:绘图结构
RECT:矩形结构
6:三个句柄
句柄是一个32位的数,代表一个对象;程序通过调用Windows函数获取句柄,在Windows函数中引用句柄,以引用它所代表的对象,句柄的实际值对程序无关紧要,
但Windows模块知道如何使用它来引用相应的对象。
HINSTANCE:实例句柄(程序自身)
HWND:窗口句柄
HDCP:设备描述句柄
7:匈牙利表示法(变量名既能描述变量的作用,又描述了其数据类型,这就能比较容易的避免产生数据类型不搭配的错误)
在Windows程序中,使用匈牙利表示法给变量命名,变量名以一个或者多个小写字母开始,这些字母表示变量的数据类型;
sz 表示以零结尾的字符串
hInstance,hPrevInstance中的h前缀表示句柄
iCmdShow中的i前缀表示 整数
wPraram 更适合叫uiPraram(无符号整数)
c:char活WHAR或TCHAR的前缀
by:BYTE(无符号字符)的前缀
n:short的前缀
i:int的前缀
x,y:int分别用作x坐标或y坐标
cx,cy:int分别用作x长度,和y的长度;c代表count;
b,f:b代表bool;f代表flag;
w:WORD(无符号short);
l:LONG(长整数)
dw:DWORD(无符号长整数)
fn:function(函数)
s:string(串)
sz:以零字节结尾的串
lpfn:只想函数的长指针
h:句柄
p:指针
cb:字节数
hbr:一个刷子的句柄
8:结构的命名
可以用结构名的小写,或结构名缩写的小写给结构名命名;
9:注册窗口类
窗口总是在窗口类的基础上创建的,窗口类用以标示处理窗口信息的消息过程。
(1)首先注册一个窗口类WNDCLASS wndclass
在程序创建窗口之前,必须首先调用RegisterCLASS注册一个窗口类;
该函数只要一个参数,即一个指向类型为WNDCLASS的结构指针。
补充:WNDCLASS结构简介
此结构包括两个指向字符串的域,因此结构在WINUSER.H头文件中定义了两种不用的方式。(ASCII版本和Unicode版本)
ASCII版本的WNDCLASSA
typedef struct tagWNDCLASSA
{
UINT style; 类风格
WNDPROC lpfnWndPROC; 基于这个类创建的窗口所使用的窗口过程的地址;
int cbClsExtra;
int cbWndExtra; 类结构和窗口结构中预留一些额外空间,程序可以根据需要使用预留的空间
HINSTANCE hinstance; 程序的实例句柄,是WinMain的参数之一
HICON hicon; 为所有基于这个窗口类建立的窗口设置一个图标,图标是一个小的位图图像
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCSTR lpszMinuName;
LPCSTR lpszClassName; 窗口类的文本名
}
WNDCLASS,*PWNDCLASSA,NEAR *NPWNDLASSA,FAR *LPWINDCLASSA;
补充:WINUSER.H定义了WNDCLASS和指向WNDCLASS的结构体,及一些向后兼容的代码
(2)初始化wndclass中的各个域
wnd.style = CS_HREDRAW|CS_VREDRAW;
wnd.lpfnWndProc = WndProc;
将窗口类的窗口过程设置为WndProc,及HEELLOWIN.H中的第二个函数,用于处理基于这个窗口类创建的所有窗口的全部消息。WndProc是函数的指针;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
设置程序的实例句柄
wndclass.hIcon = LOADIcon(NULL,IDI_APPLICATION)
此函数返回图标的句柄,用于设置hIcon的值,第一个参数设置为Null,来获取预先定义的图标句柄;第二个参数设置为IDI_APPLICATION(为图标的标识符,在WINUSER.H中定义)
wndclass.hCusor = LoadCursor(null, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHIT_BRUSH);
指定这个类创建的窗口背景的颜色;
补充:刷子,刷子是图形学上的一个术语,指用来填充一个域的着色像素模式。Windows有几个标准刷子;GetStockObject调用返回一个白色刷子句柄 wndclass.lpszMenuName = NULL;指定窗口类菜单
wndclass.lpszClassName = szAppName;给出类名,该串由ASCII字符组成还是有Unicode字符组成取决于是否定义了UNICODE标识符
(3)调用RigisterClass来注册这个窗口类;
Register(&wndclass)这个函数只有一个参数,即指向WNDCLASS的指针
补充:许多windows函数需要分配内存,如RegisterClass函数需要分配内存,以保存关于窗口类的信息。
(4)创建窗口
窗口类定义了窗口的一般特征,因此可以使用同一窗口类创建许多不同的窗口,调用CreateWindow创建窗口时,可能指定窗口有关的更详细的信息;
补充:窗口类及窗口的区别,以及createWindow函数和RegisterClass函数的区别
传给RegisterClass的函数信息在一个数据结构中说明,传递给CreateWindows的函数的信息作为函数的单独参数。
补充:HWMD hwnd;创建一个窗口的句柄,存放在变量hwnd中,HWND为窗口句柄类型,Windows中每个窗口都有一个句柄,程序用句柄引用窗口。许多windows函数需要使用hwnd作为参数,这样,Windows才能知道函数是针对那个窗口的,如果一个程序创建了很多窗口,则每个窗口均有一个句柄。(窗口句柄是Windows程序处理的最重要的句柄之一);
窗口风格:WS_OVERLAPPEDWINDOW是一个标准风格的函数
(5)显示窗口
ShowWindow(hwnd, iCmdShow);
UpateWindow(hwnd);
(6)消息循环
调用UpdateWindow之后,窗口就出现在视频显示器上,程序现在必须准备读入用户用键盘和鼠标输入的数据。Windows 为当前运行的每个Windows程序维护一个消息队列。当发生输入事件之后,Windows将事件转换为一个消息,并将消息放在程序的消息队列中。
程序通过执行一块被成为消息循环的代码从消息队列中取出消息
while(GetMessage(&msg,NULL,0,0))
{
TracslateMessage(&msg);
DispatchMessage(&msg);
}
补充:msg变量是类型为MSG的结构,MSG类型在WINUSER.H中定义如下:
type struct tagMSG
{
HWND hwnd; 该程序拥有的唯一窗口
UINT message; 消息标示符。是一个数值,用来标示消息。对于每个消息,均有一个标识符与之对应。这些标示符定义在Windows头文件中。以前缀WM开头。
例如:用户将鼠标光标放在客户区域之内,并按下左键,则Windows在消息队列中放入一消息,该消息的message域等于WM_LBUTTONDOWN(是一个常量);
WPARAM wParam;32的消息参数,其含义和数值根据消息的不同而不同;
LPARAM IParam;一个32位的消息参数,其含义与消息有关
DWORD time; 消息放入消息队列的时间
POINT pt; 消息放入队列的鼠标坐标
}
typedef struct tagPOINT
{
LONG X;
LONG Y;
}
发生输入事件后,Windows将其转换为一个消息放入消息队列中,程序从消息队列取出消息,只要从消息队列取出消息的message域不为WM_QUIT,则GetMessage就返回一个非零值;
TranslateMessage(&msg);将msg结构传给Windows,
DispatchMessage(&msg);
又将msg结构回传给Windows。然后Windows将该消息发送给适当的窗口过程,让它进行处理。
注:Windows调用窗口过程,这个窗口过程是WndPro函数,处理完消息后,WndProc返回到Windows,此时Windows还停留在DispatchMessage调用中,在结束DispatchMessage调用的处理之后,Windows回到HELLOWIN中,并且从下一个GetMessage调用开始循环消息;
(7)窗口过程
注:准备性工作,注册窗口类-》创建窗口-》显示窗口-》程序进入消息循环-》从消息队列中取出一条消息-》窗口过程进行处理
窗口过程确定了在窗口的客户区域中显示些什么,以及窗口怎么响应用户输入;
一个WINDOWS程序可以包含多个窗口过程,一个窗口过程总是于调用RigisterClass注册的特定窗口类相关联。CreateWindow函数根据特定的窗口类创建一个窗口。但基于一个窗口类可以创建多个窗口。
窗口过程的定义:
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM iParam)
程序通常不直接调用窗口调用,窗口调用通常有WINDOWS本身调用。通过SendMessage函数,程序能够直接调用它自己的窗口过程
(8)处理消息
窗口过程接受的每个消息均是用一个数值来标示的,也就是传给窗口过程的message参数。WINDOWS头文件WINUSER.H为每个消息参数定义为WM为前缀的标识符;
WINDOWS程序员使用switch和case结构来确定窗口过程接受的是什么消息,以及如何适当的处理它,窗口过程在处理消息时必须返回零,窗口过程不予处理的所有消息应该被传给名为DefWindowProc的WINDOWS函数。从DefWindowProc返回的值必须有窗口过程返回。
补充:调用DefWindowProc来为窗口过程不予处理的所有消息提供默认处理。
(9)播放声音文件
窗口过程接受的第一个消息,WM_CREATE,也是WndProc选择处理的第一个消息。
接受消息的机制:
当程序调用CreateWindow函数时,WINDOWS调用Wndproc,将其第一个参数设置为句柄,第二个参数设置为wm_create;
WndProc处理WM_CREATE消息,并将控制返回给WINDOWS;
WINDOWS从CreateWindow调用中返回到程序,继续下一步的处理。
(10) WM_PAINT消息
这个消息在Windows程序设计中很重要,当窗口客户区域的一部分或全部变为无效时,以至于必须重新刷新时,将有这个消息通知程序;
补充:最初创建窗口时,整个客户区都是无效的,因为程序还没有在窗口上画什么东西。第一个WM_PAINT消息指示窗口过程在客户区域上画些东西;
用户改变窗口大小时,客户区重新变得无效,然后窗口过程将收到一个wm_paint消息
对wm_paint的处理总是从一个BeginPaint调用开始,以一个EndPaint调用哪个结束;这两个调用中,第一个参数是程序的窗口句柄,第二个参数是指向类型为PAINTSTRUCT的结构指针(该结构中包含一些窗口过程,用来刷新客户区域的指针);BeginPain调用使整个客户区有效,并返回一个设备描述表句柄。设备描述表是指物理输出设备及其他设备驱动程序。在窗口的客户区域显示文本和图形需要设备描述表句柄(不能用从BeginPaint返回的设备描述表句柄在客户区域之外绘图);EndPaint释放设备描述表句柄,使之不在有效;
调用完BeginPaint之后,WndProc接着调用GetClientRect;其第一个参数是程序窗口的句柄,第二个参数是一个指向RECT结构类型的指针;
补充:rectangle结构有四个LONG域,分别为left,top,right,botton。表示窗口客户区域的尺寸,left和top设置为0,right和bottom设置为客户区域的宽度和高度。(像素点数);
将RECT指针作为DrawText的第四个参数传递,不在做其他处理;当客户区变得无效,WndProc就接受一个新的wm_paint消息,WndProc通过调用GetClientRect获取变化后的窗口大小,并在新窗体的中央现实文本。
(11)WM_DESTROY消息
该消息提示,WINDOWS正在根据用户输入的命令来清楚窗口。(用户单击CLoce按钮或者在程序的系统菜单上选择close时发生);程序通过调用PostQuitMessage以标准方式响应WM_DESTROY消息;该函数在程序的消息队列中插入一个WM_QUIT消息,当GetMessage取得一个wm_quit消息时,返回0,这将导致WinMain退出消息循环并终止程序;
(12)Window编程的难点
在HELLOWIN中,WinMain包含了注册窗口类,创建窗口,从消息队列中取得消息和发送消息等相关的代码;
程序所有的动作均在窗口过程中发生,实际上,WINDOWS程序所做的一切都是响应发送给窗口过程的消息;
(13)别调用我,我会调用你
在WINDOWS程序设计中,WINDOWS有1000个以上的函数可供程序调用,但WINDOWS也在调用用户程序;例如前面定义的窗口过程WndProc,窗口过程与一个窗口类相关联,窗口类是程序调用RegisterCLASS注册的。基于该类创建的窗口使用这个窗口过程来处理窗口的所有消息,WINDOWS通过调用窗口过程来给窗口发送一个消息;
所有的WndProc调用都以消息的方式进行,大多数WINDOWS程序中,程序的主要部分都用来处理消息;(WINDOWS可以发送给窗口过程的消息通常都以WM打头的标识符,并且都在WINUSER.H中定义);在WINDOWS中窗口中发生的一切都以消息的形式传给窗口过程,然后窗口过程以某种方式响应这个消息;
注:一个窗口过程能处理基于同一个窗口创建的多个窗口的消息,参数hwnd让窗口过程知道那个窗口接受消息;
(14)WinProc窗口过程的各个参数
LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM IParam)
参数message是WM_SIZW,消息WM_SIZE的参数wParam
参数wPARAM在WINUSER.H中定义为数字0到4表明窗口是非最小化还是非最大化
参数IParam包含新窗口的大小;
注:有时候,DefWindowProc处理完消息后会产生其他消息;窗口过程用来处理消息;