Windows编程02_注册窗口类,窗口创建,消息基础,常见消息,消息循环的原理

01 注册窗口类

1.窗口类的概念

  • 窗口类包含了窗口的各种参数信息的数据结构。
  • 每个窗口都具有窗口类,基于窗口类创建窗口。
  • 每个窗口类都具有一个名称,使用前必须注册到系统。

2.窗口类的分类

  • 系统窗口类
    系统已经定义好的窗口类,所有应用程序都可以直接使用。
  • 应用程序全局窗口类
    由用户自己定义,当前应用程序所有模块都可以使用。
  • 应用程序局部窗口类
    由用户自己定义,当前应用程序中本模块可以使用。

3.系统窗口类

  • 不需要注册,直接使用窗口类即可。系统已经注册好了。
    例如:
    按钮 -BUTTON
    编辑框 -EDIT
#include<windows.h>
//入口函数
int CALLBACK WinMain(HINSTANCE hIns, HINSTANCE hPreIns, LPSTR lpCmdLine, int nCmdShow)
{
	//在内存创建窗口
	HWND hWnd = CreateWindow("Button", "window", WS_OVERLAPPEDWINDOW, 100, 100, 500, 500, NULL, NULL, hIns, NULL);
	//显示窗口
	ShowWindow(hWnd, SW_SHOW);
	UpdateWindow(hWnd);
	//消息循环
	MSG nMsg = { 0 };
	while (GetMessage(&nMsg, NULL, 0, 0))
	{
		TranslateMessage(&nMsg);
		DispatchMessage(&nMsg);//将消息交给窗口处理函数来处理
	}
	return 0;
}

整个大框一个按钮:
在这里插入图片描述

4.全局及局部窗口类

  • 注册窗口类的函数
    ATOM RegisterClass(
    CONST WNDCLASS *lpWndClass //窗口类的数据
    );注册成功后,返回一个数字标识

  • 注册窗口类的结构体
    typedef struct _WNDCLASS{
    UINT style; //窗口类的风格
    WNDPROC lpfnWndProc;//窗口处理函数
    int cbClsExtra;//窗口类的附加数据buff的大小
    int cbWndExtra;//窗口的附加数据buff的大小
    HINSTANCE hInstance;//当前模块的实例句柄
    HICON hIcon;//窗口图标句柄
    HCURSOR hCursor;//鼠标的句柄
    HBRUSH hbrBackground;//绘制窗口背景的画刷句柄
    LPCTSTR lpszMenuName;//窗口菜单的资源ID字符串
    LPCTSTR lpseClassName;//窗口类的名称
    }WNDCLASS,*PWNDCLASS;

  • style窗口类风格
    应用程序全局窗口类的注册,需要在窗口类的风格中的增加CS_GLOBALCLASS.
    例如:
    WNDCLASS wce = {0};
    wce.style = …|CS_GLOBALCLASS;
    应用程序局部窗口类:在注册窗口类时,不添加CS_GLOBALCLASS风格

    CS_HREDRAW -当窗口水平变化时,窗口重新绘制
    CS_VREDRAW -当窗口垂直变化时,窗口重新绘制
    CS_DBLCLKS -允许窗口接收鼠标双击
    CS_NOCLOSE -窗口没有关闭按钮

02 窗口创建

1.窗口创建

  • CreateWindow/CreateWindowEx

    HWND CreateWindowEx(
    DWORD dwExStyle, //窗口的扩展风格 (CreateWindow没有)
    LPCTSTR lpClassName, //已经注册的窗口类名称
    LPCTSTR lpWindowName, //窗口标题栏的名字
    DWORD dwStyle, //窗口的基本风格
    int x, //窗口左上角水平坐标位置
    int y, //窗口左上角垂直坐标位置
    int nWidth, //窗口的宽度
    int nHeight, //窗口的高度
    HWND hWndParent, //窗口的父窗口句柄
    HMENU hMenu, //窗口菜单句柄
    HINSTANCE hInstance, //应用程序实例句柄
    LPVOID lpParam //窗口创建时附加参数
    );//创建成功返回窗口句柄

2.窗口创建执行过程

  • 系统根据传入的窗口类名称,在应用程序局部窗口类中查找,如果找到执行2,如果未找到执行3。
  • 比较局部窗口类与创建窗口时传入的HINSTANCE变量。如果发现相等,创建和注册的窗口类在同一模块,创建窗口返回。如果不相等,继续执行3.
  • 在应用程序全局窗口类,如果找到,执行4,如果未找到执行5。
  • 使用找到的窗口类的信息,创建窗口返回。
  • 在系统窗口类中查找,如果找到创建窗口返回,否则创建窗口失败。

在这里插入图片描述

3.子窗口创建

  • 创建时要设置父窗口句柄
  • 创建风格要增加WS_CHILD|WS_VISIBLE
#include<Windows.h>

LRESULT CALLBACK WndProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)
{
	return DefWindowProc(hWnd, msgID, wParam, lParam);
}

//入口函数
int CALLBACK WinMain(HINSTANCE hIns, HINSTANCE hPreIns, LPSTR lpCmdLine, int nCmdShow)
{
	//注册窗口类
	WNDCLASS wc = { 0 };
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
	wc.hCursor = NULL;
	wc.hIcon = NULL;
	wc.hInstance = hIns;
	wc.lpfnWndProc = WndProc;
	wc.lpszClassName = "Main";
	wc.lpszMenuName = NULL;
	wc.style = CS_HREDRAW | CS_VREDRAW;
	RegisterClass(&wc);//将以上所有赋值全部写入操作系统。
	//在内存创建窗口
	HWND hWnd = CreateWindowEx(0,"Main", "window", WS_OVERLAPPEDWINDOW, 100, 100, 500, 500, NULL, NULL, hIns, NULL);
	
	//注册窗口类
	wc = { 0 };
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
	wc.hCursor = NULL;
	wc.hIcon = NULL;
	wc.hInstance = hIns;
	wc.lpfnWndProc = DefWindowProc;
	wc.lpszClassName = "Child";
	wc.lpszMenuName = NULL;
	wc.style = CS_HREDRAW | CS_VREDRAW;
	RegisterClass(&wc);//将以上所有赋值全部写入操作系统。
	//在内存创建窗口
	HWND hWnd1 = CreateWindowEx(0,"Child", "c1", WS_CHILD | WS_VISIBLE|WS_OVERLAPPEDWINDOW, 0, 0, 200, 200, hWnd, NULL, hIns, NULL);
	HWND hWnd2 = CreateWindowEx(0,"Child", "c2", WS_CHILD | WS_VISIBLE | WS_OVERLAPPEDWINDOW, 200, 0, 200, 200, hWnd, NULL, hIns, NULL);
	//显示窗口
	ShowWindow(hWnd, SW_SHOW);
	UpdateWindow(hWnd);
	//消息循环
	MSG nMsg = { 0 };
	while (GetMessage(&nMsg, NULL, 0, 0))
	{
		TranslateMessage(&nMsg);
		DispatchMessage(&nMsg);//将消息交给窗口处理函数来处理
	}
	return 0;
}

在这里插入图片描述

03 消息基础

1.消息的概念和作用

  • 消息组成(windows平台下)
    窗口句柄
    消息ID
    消息的两个参数(两个附带消息)
    消息产生的时间
    消息产生时的鼠标位置
  • 消息的作用
    当系统通过窗口工作时,就采用消息的方式派发给窗口(窗口处理函数)。
    在这里插入图片描述

2.窗口处理函数

  • 每个窗口都必须具有窗口处理函数
    LRESULT CALLBACK WindowProc(
    HWND hwnd, //窗口句柄
    UINT uMsg, //消息ID
    WPARAM wParam, //消息参数
    LPARAM lParam //消息参数
    );
  • 当系统通知窗口时,会调用窗口处理函数,同时将消息ID和消息参数传递给窗口处理函数。在窗口处理函数中,不处理的消息,使用缺省窗口处理函数。例如:DefWindowProc。

3.浅谈消息相关函数

  • GetMessage -获取消息
    BOOL GetMessage(
    LPMSG lpMsg, //存放获取到的消息BUFF
    HWND hWnd, //窗口句柄
    UINT wMsgFilterMin, //获取消息的最小ID
    UINT wMsgFilterMax //获取消息的最大ID
    );
    lpMsg -当获取到消息后,将消息的参数存放到MSG结构中。
    hWnd -获取到hWnd所指定窗口的消息。NULL:获取所有
    wMsgFilterMin和wMsgFilterMax -只能获取到由它们指定的消息范围内的消息,如果都为0,表示没有范围。

  • TranslateMessage -翻译消息。将按键消息,翻译成字符消息
    BOOL TranslateMessage(
    CONST MSG * lpMsg //要翻译的消息地址
    );

  • 检查消息是否是按键的消息,如果不是按键消息,不做任何处理,继续执行。

04 常见消息

1.WM_DESTROY

  • 产出时间:窗口被销毁时的消息。
  • 附带消息:wParam:为0。
    lParam:为0。
  • 一般用法:常用于在窗口被销毁之前,做相应的善后处理,例如资源,内存等。

2.WM_SYSCOMMAND

  • 产生时间:当点击窗口的最大化,最小化,关闭等。
  • 附带消息:wParam:具体点击的位置,例如关闭SC_CLOSE等。
    lParam:鼠标光标的位置。
    LOWORD(lParam);//水平位置(4字节低2位)
    HIWORD(lParam);//垂直位置(4字节高2位)
  • 一般用法:常用在窗口关闭时,提升用户处理。

3.WM_CREATE

  • 产出时间:在窗口创建成功但还未显示时。
  • 附带消息:wParam:为0。
    lParam:为CREATESTRUCT类型的指针。
    通过这个指针可以获取CreateWindowEx中的全部12个参数的信息。
  • 一般用法:常用于初始化窗口的参数,资源等等,包括创建子窗口等。

4.WM_SIZE

  • 产生时间:在窗口的大小发生变化后。
  • 附带信息:wParam:窗口大小变化的原因。
    lParam:窗口变化后的大小。
    LOWORD(lParam) //变化后的宽度
    HIWORD(lParam)//变化后的高度
  • 一般用法:常用于窗口大小变化后,调整窗口内各个部分的布局。

5.WM_QUIT

  • 产生时间:程序员发送。
  • 附带消息:wParam:PostQuitMessage函数传递的参数
    lParam:0
  • 一般用法:用于结束消息循环,当GetMessage接受到这个消息后,会返回FALSE,结束while处理,退出消息循环。
#include<Windows.h>
#include<stdio.h>

HANDLE g_hOutput = 0;//结束标准输出句柄
void OnCreate(HWND hWnd, LPARAM lParam)
{
	CREATESTRUCT* pcs = (CREATESTRUCT*)lParam;
	char* pszText = (char*)pcs->lpCreateParams;
	MessageBox(NULL, pszText, "Info", MB_OK);

	CreateWindowEx(0, "EDIT", "hello", WS_CHILD|WS_VISIBLE|WS_BORDER, 0, 0, 200, 200, hWnd, NULL, 0, NULL);

}

void OnSize(HWND hWnd, LPARAM lParam)
{
	short nWidth = LOWORD(lParam);
	short nHight = LOWORD(lParam);
	char szText[256] = { 0 };
	sprintf(szText, "WM_SIZE:宽:%d,高:%d\n", nWidth, nHight);
	WriteConsole(g_hOutput, szText, strlen(szText), NULL, NULL);
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)
{
	switch (msgID)
	{
	case WM_CREATE:
		OnCreate(hWnd, lParam);
		break;
	case WM_SIZE:
		OnSize(hWnd, lParam);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);//可以使用GetMessage函数返回0
		break;
	case WM_SYSCOMMAND:
		if (wParam == SC_CLOSE)
		{
			int nRet = MessageBox(hWnd, "是否退出", "Infor", MB_YESNO);
			if (nRet == IDYES)
			{
				//什么都不写
			}
			else
			{
				return 0;
			}
		}
	}
	return DefWindowProc(hWnd, msgID, wParam, lParam);
}

//入口函数
int CALLBACK WinMain(HINSTANCE hIns, HINSTANCE hPreIns, LPSTR lpCmdLine, int nCmdShow)
{
	AllocConsole();//程序中增加DOS窗口
	g_hOutput = GetStdHandle(STD_OUTPUT_HANDLE);//标准输出句柄
	//注册窗口类
	WNDCLASS wc = { 0 };
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
	wc.hCursor = NULL;
	wc.hIcon = NULL;
	wc.hInstance = hIns;
	wc.lpfnWndProc = WndProc;
	wc.lpszClassName = "Main";
	wc.lpszMenuName = NULL;
	wc.style = CS_HREDRAW | CS_VREDRAW;
	RegisterClass(&wc);//将以上所有赋值全部写入操作系统。
	//在内存创建窗口
	char* pszText = "hello data";
	HWND hWnd = CreateWindowEx(0,"Main", "window", WS_OVERLAPPEDWINDOW, 100, 100, 500, 500, NULL, NULL, hIns, pszText);
	
	//显示窗口
	ShowWindow(hWnd, SW_SHOW);
	UpdateWindow(hWnd);
	//消息循环
	MSG nMsg = { 0 };
	while (GetMessage(&nMsg, NULL, 0, 0))
	{
		TranslateMessage(&nMsg);
		DispatchMessage(&nMsg);//将消息交给窗口处理函数来处理
	}
	return 0;
}

在这里插入图片描述

05 消息循环的原理

1.消息循环的阻塞

  • GetMessage -从系统获取消息,将消息从系统中移除,阻塞消息。当系统无消息时,会等待下一个消息。
  • PeekMessage -以查看的方式从系统获取消息,可以不将消息从系统移除,非阻塞函数。当系统无消息时,返回FALSE,继续执行后续代码。
    BOOL PeekMessage(
    LPMSG lpMsg ,//message information
    HWND hWnd, //handle to window
    UINT wMsgFilterMin, //first message
    UINT wMsgFilterMax, //last message
    UINT wRemoveMsg //移除标记 PM_REMOVE/PM_NOREMOVE
    );

2.发送消息

  • SendMessage -发送消息,会等候消息处理的结果。

  • PostMessage -投递消息,消息发出后立刻返回,不等候消息执行结果。

    BOOL SendMessage/PostMessage(
    HWND hWnd, //消息发送的目的窗口
    UINT Msg, //消息ID
    WPARAM wParam, //消息参数
    LPARAM lParam //消息参数
    );
    在这里插入图片描述

3.消息分类

  • 系统消息 -ID范围 0-0x03FF
    由系统定义好的消息,可以在程序中直接使用。
  • 用户自定义消息 -ID范围 0x0400 -0x7FFF(31743)
    由用户自己定义,满足用户自己的需求。由用户自己发出消息,并响应处理
    自定义消息宏:WM_USER
#include<Windows.h>
#include<stdio.h>

HANDLE g_hOutput = 0;//结束标准输出句柄

#define WM_MYMESSAGE WM_USER+1001

void OnCreate(HWND hWnd, LPARAM lParam)
{
	CREATESTRUCT* pcs = (CREATESTRUCT*)lParam;
	char* pszText = (char*)pcs->lpCreateParams;
	MessageBox(NULL, pszText, "Info", MB_OK);
	PostMessage(hWnd, WM_MYMESSAGE, 1, 2);
	CreateWindowEx(0, "EDIT", "hello", WS_CHILD|WS_VISIBLE|WS_BORDER, 0, 0, 200, 200, hWnd, NULL, 0, NULL);

}

void OnSize(HWND hWnd, LPARAM lParam)
{
	short nWidth = LOWORD(lParam);
	short nHight = LOWORD(lParam);
	char szText[256] = { 0 };
	sprintf(szText, "WM_SIZE:宽:%d,高:%d\n", nWidth, nHight);
	WriteConsole(g_hOutput, szText, strlen(szText), NULL, NULL);
}

void OnMyMessage(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	char szText[256] = { 0 };
	sprintf(szText, "自定义消息被处理:wParam:%d,lParam:%d\n", wParam, lParam);
	MessageBox(hWnd, szText, "Info", MB_OK);
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)
{
	switch (msgID)
	{
	case WM_MYMESSAGE:
		OnMyMessage(hWnd, wParam, lParam);
		break;
	case WM_CREATE:
		OnCreate(hWnd, lParam);
		break;
	case WM_SIZE:
		OnSize(hWnd, lParam);
		break;
	case WM_DESTROY:
		//PostQuitMessage(0);//可以使用GetMessage函数返回0
		//SendMessage(hWnd, WM_QUIT, 0, 0);
		PostMessage(hWnd, WM_QUIT, 0, 0);
		break;
	case WM_SYSCOMMAND:
		if (wParam == SC_CLOSE)
		{
			int nRet = MessageBox(hWnd, "是否退出", "Infor", MB_YESNO);
			if (nRet == IDYES)
			{
				//什么都不写
			}
			else
			{
				return 0;
			}
		}
	}
	return DefWindowProc(hWnd, msgID, wParam, lParam);
}

//入口函数
int CALLBACK WinMain(HINSTANCE hIns, HINSTANCE hPreIns, LPSTR lpCmdLine, int nCmdShow)
{
	AllocConsole();//程序中增加DOS窗口
	g_hOutput = GetStdHandle(STD_OUTPUT_HANDLE);//标准输出句柄
	//注册窗口类
	WNDCLASS wc = { 0 };
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
	wc.hCursor = NULL;
	wc.hIcon = NULL;
	wc.hInstance = hIns;
	wc.lpfnWndProc = WndProc;
	wc.lpszClassName = "Main";
	wc.lpszMenuName = NULL;
	wc.style = CS_HREDRAW | CS_VREDRAW;
	RegisterClass(&wc);//将以上所有赋值全部写入操作系统。
	//在内存创建窗口
	char* pszText = "hello data";
	HWND hWnd = CreateWindowEx(0,"Main", "window", WS_OVERLAPPEDWINDOW, 100, 100, 500, 500, NULL, NULL, hIns, pszText);
	
	//显示窗口
	ShowWindow(hWnd, SW_SHOW);
	UpdateWindow(hWnd);
	//消息循环
	MSG nMsg = { 0 };
	/*while (GetMessage(&nMsg, NULL, 0, 0))
	{
		TranslateMessage(&nMsg);
		DispatchMessage(&nMsg);//将消息交给窗口处理函数来处理
	}*/

	while (1)
	{
		if (PeekMessage(&nMsg, NULL, 0, 0, PM_NOREMOVE))
		{
			//有消息
			if (GetMessage(&nMsg, NULL, 0, 0))
			{
				TranslateMessage(&nMsg);
				DispatchMessage(&nMsg);
			}
			else {
				return 0;
			}
		}
		else {
			//空闲处理
			WriteConsole(g_hOutput, "OnIdle", strlen("OnIdle"), NULL, NULL);
		}
	}
	return 0;
}

在这里插入图片描述

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值