windows编程笔记【四】事件处理函数和主事件循环

本笔记源自windows游戏编程大师技巧第二版2.9章,记做学习随笔。

使用vs2017环境编译。

 在此之前,我们写的Windows类,也就是:

WNDCLASSEX winclass;

中,有一个类的成员变量,他要求填写一个回调函数。这个函数就是我们要写的事件处理函数,他在这里:

#include <Windows.h>
#include <windowsx.h>
 
#define WIN32_LEAN_AND_MEAN
 
int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hprevinstance, LPSTR lpcmdline,int ncmdshow)
{
        WNDCLASSEX winclass;
        .
        .
	winclass.lpfnWndProc = WndProc; //WndProc还没有定义。
        .
        .
	return 0;
}

当你的窗口有了新的事件,Windows就会调用这个回调函数来通知你。

这个回调函数原型如下:

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);

hend——这是一个窗口句柄,当你的程序有多个窗口可以用到。

msg——这是个实际处理消息的标识符。

wparam和lparam——进一步匹配或分析发送到msg参数中的信息。

这张图说明了多窗口的处理,这也是hend句柄处理多窗口的原理。

我们只需要用switch()来处理msg所表示的信息,在此之前先看一下消息标识符表:

WM_ACTIVATE当窗口被激活或成为一个焦点传递
WM_CLOSE当窗口关闭时关闭
WM_CREATE当窗口第一次创建时传递
WM_DESTROY当窗口可能要被销毁时传递
WM_MOVE当窗口移动时传递
WM_MOUSEMOVE当鼠标移动时传递
WM_KEYUP当松开一个键时传递
WM_KEYDOWN当发生定时程序时传递
WM_TIMER允许传递消息
WM_USER允许传递消息
WM_PAINT当一个窗口需要重回时传递
WM_QUIT当Windows应用程序最后结束传递
WM_SIZE当一个窗口改变大小时传递

我们现在只关心三个消息:WM_CREATE,WM_PAINT,WM_DESTROY

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
	PAINTSTRUCT ps;
	HDC hdc;

	switch (msg)
	{
		case WM_CREATE: //窗口第一次创建的消息
		{
			return 0;
		}break;

		case WM_PAINT: //窗口需要重绘的消息
		{
			hdc = BeginPaint(hwnd, &ps);
			EndPaint(hwnd, &ps);
			return 0;
		}break;

		case WM_DESTROY: //窗口销毁的消息
		{
			PostQuitMessage(0);
			return 0;
		}break;

		default:
			break;
	}

	return (DefWindowProc(hwnd, msg, wparam, lparam));
}

我们还无需添加其他功能,所以WM_CREATE直接return 0即可。

WM_PAINT就非常重要了,我们调用了BeginPaint();EndPaint();重绘窗口。(这里有待补充)

WM_DESTROY中调用PostQuitMessage(0);意为终止线程,也就是终止你的应用程序。

现在来看一下我们全部的代码吧:

#include <Windows.h>
#include <windowsx.h>

#define WIN32_LEAN_AND_MEAN

//新加入的代码WndProc函数的定义。
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
	PAINTSTRUCT ps;
	HDC hdc;

	switch (msg)
	{
		case WM_CREATE://窗口第一次创建的消息
		{
			return 0;
		}break;

		case WM_PAINT://窗口需要重绘的消息
		{
			hdc = BeginPaint(hwnd, &ps);
			EndPaint(hwnd, &ps);
			return 0;
		}break;

		case WM_DESTROY://窗口销毁的消息
		{
			PostQuitMessage(0);
			return 0;
		}break;

		default:
			break;
	}

	return (DefWindowProc(hwnd, msg, wparam, lparam));
}

int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hprevinstance, LPSTR lpcmdline,int ncmdshow)
{
	WNDCLASSEX winclass;
	winclass.cbSize = sizeof(WNDCLASSEX);
	winclass.style = CS_VREDRAW | CS_HREDRAW | CS_OWNDC | CS_DBLCLKS;
	winclass.lpfnWndProc = WndProc;
	winclass.cbClsExtra = 0;
	winclass.cbWndExtra = 0;
	winclass.hInstance = hinstance;
	winclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	winclass.hCursor = LoadCursor(NULL, IDC_ARROW);
	winclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
	winclass.lpszMenuName = NULL;
	winclass.lpszClassName = "WINCLASS1";
	winclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

	if (!RegisterClassEx(&winclass))
		return 0;

	//HWND hwnd;
	if (!(hwnd = CreateWindowEx(NULL,
		"WINCLASS1",	//winclass.lpszClassName设置的字符,是类的别名。
		"YouWindows",	//窗口的名称
		WS_OVERLAPPEDWINDOW | WS_VISIBLE,	//一些窗口属性
		0, 0,			//窗口位置
		400, 400,		//窗口宽高
		NULL,			//父窗口句柄
		NULL,			//附属窗口句柄
		hinstance,		//WinMain第一个实参,程序句柄。
		NULL			//null就可以了
			)))
		return 0;


	return 0;
}

 

到目前为止,我们已经很接近完成这个程序了,但是你现在执行虽然不会错报,但是仍不会有任何窗口弹出,他只会一闪而过,因为我们还没写最后的循环程序。

这三个函数并不复杂,就只在代码里注释,函数请查阅文档。

while (GetMessage(&msg,NULL,0,0)) //不断从事件队列里取到消息
{
	TranslateMessage(&msg); //将虚拟消息转化为字符消息
	DispatchMessage(&msg);	//他可以调用回调函数,也就是刚才做的WndProc()处理消息。
}

 

来放出一下全部的代码:

#include <Windows.h>
#include <windowsx.h>

#define WIN32_LEAN_AND_MEAN

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
	PAINTSTRUCT ps;
	HDC hdc;

	switch (msg)
	{
		case WM_CREATE:
		{
			return 0;
		}break;

		case WM_PAINT:
		{
			hdc = BeginPaint(hwnd, &ps);
			EndPaint(hwnd, &ps);
			return 0;
		}break;

		case WM_DESTROY:
		{
			PostQuitMessage(0);
			return 0;
		}break;

		default:
			break;
	}

	return (DefWindowProc(hwnd, msg, wparam, lparam));
}

int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hprevinstance, LPSTR lpcmdline,int ncmdshow)
{
	HWND hwnd;
	MSG msg;

	WNDCLASSEX winclass;					//新建窗口类
	winclass.cbSize = sizeof(WNDCLASSEX);	//填写WNDCLASSEX的大小,方便程序计算
	winclass.style = CS_VREDRAW | CS_HREDRAW | CS_OWNDC | CS_DBLCLKS; //窗口描述属性样式
	winclass.lpfnWndProc = WndProc;			//消息回调函数
	winclass.cbClsExtra = 0;				//为窗口添加附件内存,一般填0
	winclass.cbWndExtra = 0;				//为程序天机附件内容,也是0
	winclass.hInstance = hinstance;			//填写句柄
	winclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);	//装置一个标准程序应用图标
	winclass.hCursor = LoadCursor(NULL, IDC_ARROW);		//装置鼠标样式
	winclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); //设置窗口填充颜色
	winclass.lpszMenuName = NULL;						//用于加载和选用窗口
	winclass.lpszClassName = "WINCLASS1";				//为你的类取一个别名
	winclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION); //他是程序的小图标,用途在任务栏和标题栏实现的图标。

	if (!RegisterClassEx(&winclass))		//把我们新建的窗口类注册上去
		return 0; //失败就返回

	//新加入的代码
	//HWND hwnd;
	if (!(hwnd = CreateWindowEx(NULL,
		"WINCLASS1",	//winclass.lpszClassName设置的字符,是类的别名。
		"YouWindows",	//窗口的名称
		WS_OVERLAPPEDWINDOW | WS_VISIBLE,	//一些窗口属性
		0, 0,			//窗口位置
		400, 400,		//窗口宽高
		NULL,			//父窗口句柄
		NULL,			//附属窗口句柄
		hinstance,		//WinMain第一个实参,程序句柄。
		NULL			//null就可以了
			)))
		return 0;

		while (GetMessage(&msg,NULL,0,0))	//不断从事件队列里取到消息
		{
			TranslateMessage(&msg);			//将虚拟消息转化为字符消息
			DispatchMessage(&msg);			//他可以调用回调函数,也就是刚才做的WndProc()处理消息。
		}
	return(msg.wParam);
}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值