Windows窗口

Windows窗口

Unit01注册窗口类

01窗口类的概念

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

02窗口类的分类

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

03系统窗口

  • 不需要注册,直接使用窗口类即可。系统已经注册好了
    例如:

    • 按钮: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;
}

在这里插入图片描述

04全局及局部窗口类

  • 注册窗口类的函数
ATON RegisterClass(
	CONST WNDCLASS *lpWndClass//窗口类的数据
);//注册成功后,返回一个数字标识(返回0注册失败,非0注册成功)
  • 注册窗口类的结构体
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 lpszClassName//窗口类的名称
}WNDCLASS,*PWNDCLASS;
  • style窗口类风格
    • 应用程序全局窗口类的注册,需要在窗口类的风格中增加CS_GLOBALCLASS
      例如:
    WNDCLASS wce = {0};
    wce.style = ...|CS_GLOBALCLASS;
    
    • 应用程序局部窗口类:在注册窗口类时,不添加CS_GLOBALCLASS风格
    • 其他窗口类风格:
      • CS_HREDREAW:当窗口水平发生变化时,窗口重新绘制
      • CS_VREDREAW:当窗口垂直发生变化时,窗口重新绘制
      • CS_DBLCLKS:允许窗口接收鼠标双击
      • CS_NOCLOSE:窗口没有关闭按钮

Unit02窗口创建

01窗口创建

  • CreateWindow/CreateWindowEx
HWND CreateWindowEx{
	DWORD dwExStyle,//窗口的扩建风格
	LPCTSTR lpClassName,//已经注册的窗口类名称
	LPCTSTR lpWindowName,//窗口标题栏的名字
	DWORD dwStyle,//窗口的基本风格
	int x,//窗口左上角水平坐标位置
	int y,//窗口左上角的垂直坐标位置
	int nWidth,//窗口的宽度
	int nHeight,//窗口的高度
	HWND hWndParent,//窗口的父窗口句柄
	HMENU hMenu,//窗口菜单句柄
	HINSTANCE hInstance,//应用程序实例句柄
	LPVOID lpParam//窗口创建时俯角参数
};//创建成功返回窗口句柄
#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);
	//显示窗口
	ShowWindow(hWnd,SW_SHOW);
	UpdateWindow(hWnd);
	//消息循环
	MSG nMsg = {0};
	while(GetMessage(&nMsg,NULL,0,0))
	{
		TranslateMessage(&nMsg);
		DispatchMessage(&nMsg);//将消息交给窗口处理函数来处理
	}
	return 0;
}

02窗口创建执行过程

  • 1.系统(CreateWindowEx函数内部)根据传入的窗口类名称,在因用程序局部窗口类中查找,如果找到执行第2步,否则执行第3步
  • 2.比较局部窗口类与创建时传入的HINSTANCE变量。如果发现相等,创建和注册的窗口类在同一模块,创建窗口返回。如果不相等,继续执行第3步
  • 3.在应用程序全局窗口类,如果找到执行第4步,否则执行第5步
  • 4.使用找到的窗口类的信息,创建窗口返回
  • 5.在系统窗口类中查找,如果找到创建窗口返回,否则创建窗口失败
    在这里插入图片描述
    解决遗留问题:点击窗口的关闭按钮可以完全退出进程,不用在任务管理器中杀死进程
#include <windows.h>

//窗口处理函数(自定义,处理函数)
LRESULT CALLBACK WndProc(HWND hWnd,UINT msgID,WPARAM wParam,LPARAM lParam)
{
	switch(msgID){
	case WM_DESTROY:
		PostQuitMessage(0);//可以使GetMessage函数返回0
		break;
	}
	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);
	//显示窗口
	ShowWindow(hWnd,SW_SHOW);
	UpdateWindow(hWnd);
	//消息循环
	MSG nMsg = {0};
	while(GetMessage(&nMsg,NULL,0,0))
	{
		TranslateMessage(&nMsg);
		DispatchMessage(&nMsg);//将消息交给窗口处理函数来处理
	}
	return 0;
}

03 子窗口创建

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

//窗口处理函数(自定义,处理函数)
LRESULT CALLBACK WndProc(HWND hWnd,UINT msgID,WPARAM wParam,LPARAM lParam)
{
	switch(msgID){
	case WM_DESTROY:
		PostQuitMessage(0);//可以使GetMessage函数返回0
		break;
	}
	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.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 = "Child";
	wc.lpszMenuName = NULL;
	wc.style = CS_HREDRAW|CS_VREDRAW;
	RegisterClass(&wc);//将以上所有赋值全部写入操作系统内核
	//子窗口1
	HWND hChild1 = CreateWindowEx(0,"Child","c1",WS_OVERLAPPEDWINDOW|WS_CHILD|WS_VISIBLE,0,0,200,200,hWnd,NULL,hIns,NULL);
	//子窗口2
	HWND hChild2 = CreateWindowEx(0,"Child","cc",WS_OVERLAPPEDWINDOW|WS_CHILD|WS_VISIBLE,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;
}

在这里插入图片描述

Unit03消息基础

01消息的概念和作用

  • 消息组成(Windows平台下的消息)
    • 窗口句柄
    • 消息ID
    • 消息的两个参数(两个附带信息)
    • 消息的产生时间
    • 消息产生时的鼠标位置
  • 消息的作用
    • 当系统通知窗口工作时,就采用消息的方式(DispatchMessage)派发给窗口的窗口处理函数
/*
 * Message structure
 */
typedef struct tagMSG {
    HWND        hwnd;
    UINT        message;
    WPARAM      wParam;
    LPARAM      lParam;
    DWORD       time;
    POINT       pt;
#ifdef _MAC
    DWORD       lPrivate;
#endif
} MSG, *PMSG, NEAR *NPMSG, FAR *LPMSG;

在这里插入图片描述

02窗口处理函数

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

03 浅谈消息相关函数

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

在这里插入图片描述

  • TranslateMessage翻译消息,将按键消息,翻译成字符消息
    检查消息是否是按键的消息,如果不是按键消息,不做任何处理,继续执行(该函数只翻译可见字符的按键消息)
BOOL TranslateMessage(
	const MSG* lpMsg//要翻译的消息地址
); 
  • DispatchMessage派发消息
    将消息派发到该消息所属窗口的窗口处理函数上
LONG LONG DispatchMessage(  
	const MSG* lpmsg //要派发的消息
);

Unit04常见消息

01WM_DESTORY

  • 产生时间:窗口被销毁时的消息
  • 附带信息:
    • wParam:0
    • lParam:0
  • 一般用法:常用语在窗口销毁之前,做相应的善后处理,例如资源、内存的释放等
//窗口处理函数(自定义,处理函数)
LRESULT CALLBACK WndProc(HWND hWnd,UINT msgID,WPARAM wParam,LPARAM lParam)
{
	switch(msgID){
	case WM_DESTROY:
		PostQuitMessage(0);//可以使GetMessage函数返回0
		break;
	}
	return DefWindowProc(hWnd, msgID, wParam, lParam);//给各种消息默认处理
} 

02WM_SYSCOMMAND

  • 产生时间:当点击窗口的最大化、最小化、关闭等
  • 附带信息:
    • wParam:具体点击的位置,例如关闭SC_CLOSE
    • lParam:鼠标光标的位置(使用一个long类型的高低位分别存储两个数,使用下面的两个宏定义取出两个数)
      • LOWORD(lParam);//水平位置
      • HIWORD(lParam);//垂直位置
  • 一般用法:常用在窗口关闭时,提示用户处理
#include <windows.h>

//窗口处理函数(自定义,处理函数)
LRESULT CALLBACK WndProc(HWND hWnd,UINT msgID,WPARAM wParam,LPARAM lParam)
{
	switch(msgID){
	case WM_DESTROY:
		PostQuitMessage(0);//可以使GetMessage函数返回0
		break;
	case WM_SYSCOMMAND:
		MessageBox(hWnd,"02WM_SYSCOMMAND","Info",MB_OK);
		break;
	}
	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.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 = "Child";
	wc.lpszMenuName = NULL;
	wc.style = CS_HREDRAW|CS_VREDRAW;
	RegisterClass(&wc);//将以上所有赋值全部写入操作系统内核
	//子窗口1
	HWND hChild1 = CreateWindowEx(0,"Child","c1",WS_OVERLAPPEDWINDOW|WS_CHILD|WS_VISIBLE,0,0,200,200,hWnd,NULL,hIns,NULL);
	//子窗口2
	HWND hChild2 = CreateWindowEx(0,"Child","cc",WS_OVERLAPPEDWINDOW|WS_CHILD|WS_VISIBLE,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;
}

在这里插入图片描述

#include <windows.h>

//窗口处理函数(自定义,处理函数)
LRESULT CALLBACK WndProc(HWND hWnd,UINT msgID,WPARAM wParam,LPARAM lParam)
{
	switch(msgID){
	case WM_DESTROY:
		PostQuitMessage(0);//可以使GetMessage函数返回0
		break;
	case WM_SYSCOMMAND:
		if(wParam == SC_CLOSE){
			MessageBox(hWnd,"是否退出","Info",MB_YESNO);
		}else{
			return 0;
		}
		
		break;
	}
	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.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 = "Child";
	wc.lpszMenuName = NULL;
	wc.style = CS_HREDRAW|CS_VREDRAW;
	RegisterClass(&wc);//将以上所有赋值全部写入操作系统内核
	//子窗口1
	HWND hChild1 = CreateWindowEx(0,"Child","c1",WS_OVERLAPPEDWINDOW|WS_CHILD|WS_VISIBLE,0,0,200,200,hWnd,NULL,hIns,NULL);
	//子窗口2
	HWND hChild2 = CreateWindowEx(0,"Child","cc",WS_OVERLAPPEDWINDOW|WS_CHILD|WS_VISIBLE,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;
}

在这里插入图片描述

03WM_CREATE

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

void onCreate(HWND hWnd, LPARAM lParam){
	CREATESTRUCT* psc = (CREATESTRUCT*)lParam;
	char* pszText = (char*)psc->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);
}
//窗口处理函数(自定义,处理函数)
LRESULT CALLBACK WndProc(HWND hWnd,UINT msgID,WPARAM wParam,LPARAM lParam)
{
	switch(msgID){
	case WM_CREATE:
		onCreate(hWnd, lParam);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);//可以使GetMessage函数返回0
		break;
	case WM_SYSCOMMAND:
		if(wParam == SC_CLOSE){
			MessageBox(hWnd,"是否退出","Info",MB_YESNO);
		}else{
			return 0;
		}
		
		break;
	}
	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);//将以上所有赋值全部写入操作系统内核
	//在内存创建窗口
	char* pszText = "hello data";
	HWND hWnd = CreateWindowEx(0,"Main","window",WS_OVERLAPPEDWINDOW,100,100,500,500,NULL,NULL,hIns,pszText);
	
	//子窗口窗口类
	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 = "Child";
	wc.lpszMenuName = NULL;
	wc.style = CS_HREDRAW|CS_VREDRAW;
	RegisterClass(&wc);//将以上所有赋值全部写入操作系统内核
	//子窗口1
	HWND hChild1 = CreateWindowEx(0,"Child","c1",WS_OVERLAPPEDWINDOW|WS_CHILD|WS_VISIBLE,0,0,200,200,hWnd,NULL,hIns,NULL);
	//子窗口2
	HWND hChild2 = CreateWindowEx(0,"Child","cc",WS_OVERLAPPEDWINDOW|WS_CHILD|WS_VISIBLE,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;
}

04WM_SIZE

  • 产生时间:在窗口的大小发生变化
  • 附带信息:
    • wParam:窗口大小变化的原因
    • lParam:窗口变化后的大小
      • LOWORD(lParam);//水平位置
      • HIWORD(lParam);//垂直位置
  • 一般用法:常用于窗口大小变化后,调整窗口内各个部分的布局
#include <windows.h>
#include <stdio.h>

HANDLE g_hOutput = 0;//接收标准输出句柄
void onSize(HWND hWnd, LPARAM lParam){
	short nWidth = LOWORD(lParam);
	short nHight = HIWORD(lParam);
	char szText[256] = {0};
	sprintf(szText, "WM_SIZE:宽:%d,高:%d\n", nWidth, nHight);
	WriteConsole(g_hOutput, szText,strlen(szText),NULL,NULL);
}

void onCreate(HWND hWnd, LPARAM lParam){
	CREATESTRUCT* psc = (CREATESTRUCT*)lParam;
	char* pszText = (char*)psc->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);
}
//窗口处理函数(自定义,处理函数)
LRESULT CALLBACK WndProc(HWND hWnd,UINT msgID,WPARAM wParam,LPARAM lParam)
{
	switch(msgID){
	case WM_SIZE:
		onSize(hWnd, lParam);
		break;
	case WM_CREATE:
		//onCreate(hWnd, lParam);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);//可以使GetMessage函数返回0
		break;
	case WM_SYSCOMMAND:
		if(wParam == SC_CLOSE){
			MessageBox(hWnd,"是否退出","Info",MB_YESNO);
		}else{
			return 0;
		}
		
		break;
	}
	return DefWindowProc(hWnd, msgID, wParam, lParam);//给各种消息默认处理
}
//入口函数
int CALLBACK WinMain(HINSTANCE hIns, HINSTANCE hPreIns,LPSTR lpCmdLine,int nCmdShow)
{
	AllocConsole();//增加一个DOC窗口
	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);
	
	//子窗口窗口类
	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 = "Child";
	wc.lpszMenuName = NULL;
	wc.style = CS_HREDRAW|CS_VREDRAW;
	RegisterClass(&wc);//将以上所有赋值全部写入操作系统内核
	//子窗口1
	HWND hChild1 = CreateWindowEx(0,"Child","c1",WS_OVERLAPPEDWINDOW|WS_CHILD|WS_VISIBLE,0,0,200,200,hWnd,NULL,hIns,NULL);
	//子窗口2
	HWND hChild2 = CreateWindowEx(0,"Child","cc",WS_OVERLAPPEDWINDOW|WS_CHILD|WS_VISIBLE,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;
}

在这里插入图片描述

05WM_QUIT

  • 产生时间:程序员发送
  • 附带信息:
    • wParam:PostQuitMessage函数传递参数
    • lParam:0
  • 一般用法:用于结束消息循环,当GetMessage收到这个消息后,会返回FALSE,结束while处理,退出消息循环

Unit05消息循环的原理

01消息循环的阻塞

  • 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_NOREMOVE或PM_REMOVE
  	 
 ); 

在这里插入图片描述

	while(GetMessage(&nMsg,NULL,0,0))
   {
   	TranslateMessage(&nMsg);
   	DispatchMessage(&nMsg);//将消息交给窗口处理函数来处理
   }
//将处理消息的while循环可以换一种高效的写法了
    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);
   	}
   }

示例:

#include <windows.h>
#include <stdio.h>

HANDLE g_hOutput = 0;//接收标准输出句柄
void onSize(HWND hWnd, LPARAM lParam){
	short nWidth = LOWORD(lParam);
	short nHight = HIWORD(lParam);
	char szText[256] = {0};
	sprintf(szText, "WM_SIZE:宽:%d,高:%d\n", nWidth, nHight);
	WriteConsole(g_hOutput, szText,strlen(szText),NULL,NULL);
}

void onCreate(HWND hWnd, LPARAM lParam){
	CREATESTRUCT* psc = (CREATESTRUCT*)lParam;
	char* pszText = (char*)psc->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);
}
//窗口处理函数(自定义,处理函数)
LRESULT CALLBACK WndProc(HWND hWnd,UINT msgID,WPARAM wParam,LPARAM lParam)
{
	switch(msgID){
	case WM_SIZE:
		onSize(hWnd, lParam);
		break;
	case WM_CREATE:
		//onCreate(hWnd, lParam);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);//可以使GetMessage函数返回0
		break;
	case WM_SYSCOMMAND:
		if(wParam == SC_CLOSE){
			MessageBox(hWnd,"是否退出","Info",MB_YESNO);
		}else{
			return 0;
		}
		
		break;
	}
	return DefWindowProc(hWnd, msgID, wParam, lParam);//给各种消息默认处理
}
//入口函数
int CALLBACK WinMain(HINSTANCE hIns, HINSTANCE hPreIns,LPSTR lpCmdLine,int nCmdShow)
{
	AllocConsole();//增加一个DOC窗口
	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);
	
	//子窗口窗口类
	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 = "Child";
	wc.lpszMenuName = NULL;
	wc.style = CS_HREDRAW|CS_VREDRAW;
	RegisterClass(&wc);//将以上所有赋值全部写入操作系统内核
	//子窗口1
	HWND hChild1 = CreateWindowEx(0,"Child","c1",WS_OVERLAPPEDWINDOW|WS_CHILD|WS_VISIBLE,0,0,200,200,hWnd,NULL,hIns,NULL);
	//子窗口2
	HWND hChild2 = CreateWindowEx(0,"Child","cc",WS_OVERLAPPEDWINDOW|WS_CHILD|WS_VISIBLE,200,0,200,200,hWnd,NULL,hIns,NULL);
	//显示窗口
	ShowWindow(hWnd,SW_SHOW);
	UpdateWindow(hWnd);
	//消息循环
	MSG nMsg = {0};
	 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;
}

02 发送消息

  • 消息的处理过程
    在这里插入图片描述
  • SendMessage发送消息,会等候消息处理的结果
  • PostMessage投递消息,消息发出后立即返回,不等待消息执行结果
LRESULT SendMessage / PostMessage(  
	HWND hWnd, //消息发送的目的窗口
	UINT Msg,   //消息ID
	WPARAM wParam,//消息参数  
	LPARAM lParam //消息参数
); 
#include <windows.h>
#include <stdio.h>

HANDLE g_hOutput = 0;//接收标准输出句柄
void onSize(HWND hWnd, LPARAM lParam){
	short nWidth = LOWORD(lParam);
	short nHight = HIWORD(lParam);
	char szText[256] = {0};
	sprintf(szText, "WM_SIZE:宽:%d,高:%d\n", nWidth, nHight);
	WriteConsole(g_hOutput, szText,strlen(szText),NULL,NULL);
}

void onCreate(HWND hWnd, LPARAM lParam){
	CREATESTRUCT* psc = (CREATESTRUCT*)lParam;
	char* pszText = (char*)psc->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);
}
//窗口处理函数(自定义,处理函数)
LRESULT CALLBACK WndProc(HWND hWnd,UINT msgID,WPARAM wParam,LPARAM lParam)
{
	switch(msgID){
	case WM_SIZE:
		onSize(hWnd, lParam);
		break;
	case WM_CREATE:
		//onCreate(hWnd, lParam);
		break;
	case WM_DESTROY:
		//PostQuitMessage(0);//可以使GetMessage函数返回0
		//窗口能顺利关闭,说明GetMessage能抓到PostMessage发送的消息
		PostMessage(hWnd, WM_QUIT, 0, 0);//PostQuitMessage内部调用此函数
		//窗口不能顺利关闭,说明GetMessage不能抓到SendMessage发送的消息
		//SendMessage(hWnd, WM_QUIT, 0, 0);
		break;
	case WM_SYSCOMMAND:
		if(wParam == SC_CLOSE){
			MessageBox(hWnd,"是否退出","Info",MB_YESNO);
		}else{
			return 0;
		}
		
		break;
	}
	return DefWindowProc(hWnd, msgID, wParam, lParam);//给各种消息默认处理
}
//入口函数
int CALLBACK WinMain(HINSTANCE hIns, HINSTANCE hPreIns,LPSTR lpCmdLine,int nCmdShow)
{
	AllocConsole();//增加一个DOC窗口
	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);
	
	//子窗口窗口类
	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 = "Child";
	wc.lpszMenuName = NULL;
	wc.style = CS_HREDRAW|CS_VREDRAW;
	RegisterClass(&wc);//将以上所有赋值全部写入操作系统内核
	//子窗口1
	HWND hChild1 = CreateWindowEx(0,"Child","c1",WS_OVERLAPPEDWINDOW|WS_CHILD|WS_VISIBLE,0,0,200,200,hWnd,NULL,hIns,NULL);
	//子窗口2
	HWND hChild2 = CreateWindowEx(0,"Child","cc",WS_OVERLAPPEDWINDOW|WS_CHILD|WS_VISIBLE,200,0,200,200,hWnd,NULL,hIns,NULL);
	//显示窗口
	ShowWindow(hWnd,SW_SHOW);
	UpdateWindow(hWnd);
	//消息循环
	MSG nMsg = {0};
	 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;
}

03消息分类

  • 系统消息:ID范围0-0x3FF,由系统定义好的消息,可以在程序中直接使用(注意系统消息要么程序员只负责处理不负责发送,如WM_SIZE,要么只负责发送不负责处理,如WM_QUIT)
  • 用户自定义消息:ID范围0x0400-0x7FFF(31743)'
    • 由用户自己定义,满足用户自己的需求,由用户自己发出消息,并相应处理
    • 自定义消息宏:WM_USER

自定义消息示例

#include <windows.h>
#include <stdio.h>
//自定义消息
#define WM_MYMESSAGE WM_USER+1001

HANDLE g_hOutput = 0;//接收标准输出句柄
void onSize(HWND hWnd, LPARAM lParam){
	short nWidth = LOWORD(lParam);
	short nHight = HIWORD(lParam);
	char szText[256] = {0};
	sprintf(szText, "WM_SIZE:宽:%d,高:%d\n", nWidth, nHight);
	WriteConsole(g_hOutput, szText,strlen(szText),NULL,NULL);
}

void onCreate(HWND hWnd, LPARAM lParam){
	CREATESTRUCT* psc = (CREATESTRUCT*)lParam;
	char* pszText = (char*)psc->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 onMyMessage(HWND hWnd, WPARAM wParam, LPARAM lParam){
	char szText[256] = {0};
	sprintf(szText,"自定义消息被处理:wParam=%d,lParam=%d\n", wParam, lParam);
	MessageBox(hWnd, szText, "Infor", 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_SIZE:
		onSize(hWnd, lParam);
		break;
	case WM_CREATE:
		//onCreate(hWnd, lParam);
		break;
	case WM_DESTROY:
		//PostQuitMessage(0);//可以使GetMessage函数返回0
		//窗口能顺利关闭,说明GetMessage能抓到PostMessage发送的消息
		PostMessage(hWnd, WM_QUIT, 0, 0);//PostQuitMessage内部调用此函数
		//窗口不能顺利关闭,说明GetMessage不能抓到SendMessage发送的消息
		//SendMessage(hWnd, WM_QUIT, 0, 0);
		break;
	case WM_SYSCOMMAND:
		if(wParam == SC_CLOSE){
			MessageBox(hWnd,"是否退出","Info",MB_YESNO);
		}else{
			return 0;
		}
		
		break;
	}
	return DefWindowProc(hWnd, msgID, wParam, lParam);//给各种消息默认处理
}
//入口函数
int CALLBACK WinMain(HINSTANCE hIns, HINSTANCE hPreIns,LPSTR lpCmdLine,int nCmdShow)
{
	AllocConsole();//增加一个DOC窗口
	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);
	
	//子窗口窗口类
	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 = "Child";
	wc.lpszMenuName = NULL;
	wc.style = CS_HREDRAW|CS_VREDRAW;
	RegisterClass(&wc);//将以上所有赋值全部写入操作系统内核
	//子窗口1
	HWND hChild1 = CreateWindowEx(0,"Child","c1",WS_OVERLAPPEDWINDOW|WS_CHILD|WS_VISIBLE,0,0,200,200,hWnd,NULL,hIns,NULL);
	//子窗口2
	HWND hChild2 = CreateWindowEx(0,"Child","cc",WS_OVERLAPPEDWINDOW|WS_CHILD|WS_VISIBLE,200,0,200,200,hWnd,NULL,hIns,NULL);
	//显示窗口
	ShowWindow(hWnd,SW_SHOW);
	UpdateWindow(hWnd);
	//消息循环
	MSG nMsg = {0};
	 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;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值