3、窗口的创建

窗口应用程序是消息驱动的。用户对窗口的输入最终以消息的形式传递给窗口,窗口间的通信也依赖于消息。所谓“传递给窗口”是指系统调用了我们提供的、被称为窗口过程的函数,窗口过程负责对消息作出响应。窗口过程和窗口类绑定,创建窗口前必须注册窗口类。

1、注册窗口类

调用RegisterClass注册窗口。该函数只需要一个WNDCLASS指针传参。

typedef struct tagWNDCLASSA {
    UINT        style;				// 窗口类样式
    WNDPROC     lpfnWndProc;		// 窗口过程
    int         cbClsExtra;			// 窗口类预留空间
    int         cbWndExtra;			// 窗口预留空间
    HINSTANCE   hInstance;			// 应用程序句柄
    HICON       hIcon;				// 图标句柄
    HCURSOR     hCursor;			// 指针句柄
    HBRUSH      hbrBackground;		// 背景画刷句柄
    LPCSTR      lpszMenuName;		// 窗口菜单
    LPCSTR      lpszClassName;		// 窗口类名称
} WNDCLASSA, *PWNDCLASSA, NEAR *NPWNDCLASSA, FAR *LPWNDCLASSA;

必须指定窗口类名称,创建窗口时正是通过名称来和窗口类绑定。

2、创建窗口

调用CreateWindow创建窗口。

CreateWindow(
    _In_opt_ LPCWSTR lpClassName,				// 窗口类名称
    _In_opt_ LPCWSTR lpWindowName,				// 窗口标题
    _In_ DWORD dwStyle,							// 窗口样式
    _In_ int X,									// 窗口位置x坐标
    _In_ int Y,									// 窗口位置y坐标
    _In_ int nWidth,							// 窗口宽
    _In_ int nHeight,							// 窗口高
    _In_opt_ HWND hWndParent,					// 父窗口句柄
    _In_opt_ HMENU hMenu,						// 窗口菜单句柄
    _In_opt_ HINSTANCE hInstance,				// 应用程序句柄
    _In_opt_ LPVOID lpParam);					// 创建参数

在CreateWindow内部,lpParam参数赋值给一个CREATESTRUCTA结果体的lpCreateParams成员,然后CREATESTRUCTA指针作为WM_CREATE的lParam参数一起被发送到窗口过程。

3、显示窗口

ShowWindow负责把窗口显示在屏幕上。如果需要重绘窗口,还需要调用UpdateWindow,该函数会发送一条WM_PAINT消息到窗口。

4、消息循环

窗口应用程序都应该包含一个“消息循环”代码段。

while (GetMessage(&msg, NULL, 0, 0))
{
	TranslateMessage(&msg);
	DispatchMessage(&msg);
}

GetMessage从消息队列取出消息,TranslateMessage进行一些键盘消息的转换,DispatchMessage把消息发送给合适的窗口过程。

BOOL
WINAPI
GetMessage(
    _Out_ LPMSG lpMsg,			
    _In_opt_ HWND hWnd,					
    _In_ UINT wMsgFilterMin,				
    _In_ UINT wMsgFilterMax);

lpMsg是一个MSG指针

typedef struct tagMSG {
    HWND        hwnd;			// 接收该消息的窗口过程的窗口句柄
    UINT        message;		// 消息标识符
    WPARAM      wParam;			// 消息参数
    LPARAM      lParam;			// 消息参数
    DWORD       time;			// 消息进入消息队列时间
    POINT       pt;				// 消息进入消息队列时鼠标位置
} MSG, *PMSG, NEAR *NPMSG, FAR *LPMSG;

hWnd、wMsgFilterMin、wMsgFilterMax负责消息过滤。GetMessage可以取回[wMsgFilterMin, wMsgFilterMax]范围、目标窗口句柄为hWnd的消息。
当hWnd为NULL时,GetMessage可以取回当前线程的所有窗口消息和线程消息。
当hWnd为-1时,GetMessage可以只能取回当前线程的线程消息。

当GetMessage从消息队列取回WM_QUIT消息时返回0值,反则返回非0值。

5、窗口过程

定义格式:

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);

6、WM_PAINT

窗口出现无效区域时,系统发送WM_PAINT消息到窗口。WM_PAINT消息处理中,重绘工作总是从BeginPaint开始,到EndPaint结束。
如果背景未擦除,BeginPaint负责使用注册窗口时指定的画刷擦除背景,并使整个客户区有效,返回一个客户区的设备环境句柄。
EndPaint负责释放设备环境句柄。

7、关闭窗口

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
	case WM_DESTROY:
		PostQuitMessage(0);				
		return 0;
	}

	return DefWindowProc(hwnd, message, wParam, lParam);
}
  • 单击窗口的关闭按钮时,系统向窗口过程发送WM_SYSCOMMAND消息,窗口过程把 该消息传给DefWindowProc。
  • DefWindowProc又给窗口过程发送WM_CLOSE消息,窗口过程再次把该消息传给DefWindowProc 。
  • DefWindowProc调用DestroyWindow,给窗口过程发送WM_DESTROY消息。
  • 最后我们窗口过程处理WM_DESTROY消息,PostQuitMessage会发送一条WM_QUIT消息,传参作为其wParam参数。
  • GetMessage检索到WM_QUIT后退出消息循环。

8、队列消息和非队列消息

队列消息先被插入到消息队列中,经过消息循环代码段,由GetMessage取出,再由DispatchMessage调用窗口过程。

非队列消息由windows直接调用窗口过程。

队列消息主要由用户输入产生:按键消息(WM_KEYDOWN、WM_KEYUP)、字符消息(WM_CHAR)、鼠标移动(WM_MOUSEMOVE)、鼠标点击(WM_LBUTTONDOWN)等。此外定时器消息(WM_TIMER)、重绘消息(WM_PAINT)和退出消息(WM_QUIT)也是。

非队列消息通常由windows函数产生。

需要注意的是,消息循环和窗口过程不是并发运行的,消息处理是以有序、同步方式进行的。但是,窗口过程处理消息过程中,可能产生另一个非队列消息,窗口过程将第二条消息处理完毕后才能继续处理第一条消息。所以,窗口过程必须是可重入的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值