一.消息机制
windows操作系统最大的特色是良好的用户交互性,这种交互性是通过优秀的图形界面来是心啊的
Windows操作系统将用户对应用程序窗口的的所有操作(键盘按键,鼠标点击,窗口最大化最小化等等)转化为Windows雄安锡并分发给应用程序,应用程序对这些消息进行响应,从而实现用户对操作系统以及应用程序的控制。
这种产生消息,传递消息,处理消息的过程被称为Windows消息机制。
Windows操作系统位没一个正在运行的应用程序维护一个消息队列。应用程序的消息循环将接收和处理这些消息,从而对相关事件做出响应。
-
得到消息
-
GetMessage
从消息队列取消息,如果消息队列没有消息时,函数阻塞,等待消息,如果得到了消息,这个消息是
wm_quit消息,立马返回false,如果不是wm_quit消息,返回true
GetMessage(&msg, NULL, 0, 0);
-
PeekMessage
从消息队列取消息,如果消息队列有消息,且这个消息是任何消息,返回true,如果没有消息返回false
PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
-
发送消息
-
SendMessage
可以理解为递归,直接把消息投递给该窗口对应的消息处理函数
SendMessage(hWnd,WM_KEYDOWN,0,0);
-
PostMessage
PostMessage(hWnd, WM_KEYDOWN, 0, 0);
可以理解为排队,把消息投递给这个窗口对应的消息队列,以供下一次去得到消息
二.基本消息
创建窗口消息
WM_CREATE
创建窗口时被发送给应用程序,该消息只被发送一次。理解为类的构造
GetMessage(&msg, NULL, 0, 0);
PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
SendMessage(hWnd,WM_KEYDOWN,0,0);
PostMessage(hWnd, WM_KEYDOWN, 0, 0);
销毁窗口消息
WM_DESTROY
当关闭窗口时或者开发人员在程序中调用了DestroyWindow函数时,WM_DESTROY消息会被发送给应
用程序。理解为类的析构
激活消息
WM_ACTIVATE
该消息在以下3种情况时被发送:
1、鼠标单击激活。wParam参数被标记为WA_CLICKACTIVE
2、非鼠标激活。wParam参数被标记为WA_ACTIVE //比如同时启动了多个应用程序最上面的最小化了那么它下面的就被动激活了
-
非激活。wParam参数被标记为WA_INACTIVE
系统命令消息
WM_SYSCOMMAND
在关闭、最大化、最小化、还原窗口时被发送给应用程序。
1、当wParam参数为SC_CLOSE时表示窗口进行了关闭操作
2、当wParam参数为SC_MAXIMIZE时,表示窗口进行了最大化操作
3、当wParam参数为SC_MINIMIZE时,表示窗口进行了最小化操作
4、当wParam参数为SC_RESTORE时,表示窗口进行了最小化操作
命令消息
WM_COMMAND
当用户从菜单选中一个命令项目、当一个控件发送通知消息给去父窗口或者按下一个快捷键将发送
WM_COMMAND 消息
三.重要消息
按键消息----键盘是按下就发送了消息,但是鼠标要按下再松开的时候才发送消息
键盘是用户的标准输入设备,键盘的按键事件以消息的方式提供给应用程序
当按下一个键时Windows会产生WM_KEYDOWN或者WM_SYSKEYDOWN消息,当释放一个键时,
Windows会产生WM_KEYUP或者WM_SYSKEYUP消息
windows为按键的一个真实键值准备一个虚拟键值,对于ascii码中有的数据用ascii码来做为虚拟键值,
如果在ascii码中没有,vk_键名
WM_KEYDOWN
按键按下WM_KEYUP
按键抬起
WM_SYSKEYDOWN
系统按键按下。1、ALT或F10键;2、ALT+组合键
WM_SYSKEYUP
系统按键抬起
注意:按键消息响应VK_虚拟键名,如果是ASCII码则响应大写
WM_CHAR
TranslateMessage函数会对消息进行一部分预处理将键消息根据窗口当前状态翻译成对应的字符输入信
息,产生WM_CHAR消息
如果同时输入了多个字符,则WM_CHAR消息将被发送多次
字符消息可以响应大小写字符
鼠标消息
1、WM_LBUTTONDOWN
2、WM_LBUTTONUP
3、WM_LBUTTONDBLCLK
4、WM_MBUTTONDOWN
5、WM_MBUTTONUP
6、WM_MBUTTONDBLCLK
7、WM_RBUTTONDOWN
8、WM_RBUTTONUP
9、WM_RBUTTONDBLCLK
10、WM_MOUSEMOVE
11、WM_MOUSEWHEEL
得到鼠标当前坐标
GET_X_LPARAM(lParam)
GET_Y_LPARAM(lParam)
得到鼠标滚轮前后滚动
HIWORD(wParam)
朝前是120,朝后是-120
计时器消息设置计时器
响应计时器
1、如果设置计时器时,第4个参数为NULL,在WM_TIMER响应消息,通过wParam来匹配计时器id
2、如果设置计时器时,第4个参数有回调函数,则在回调函数中响应,也就是调用这个函数
销毁计时器
SetTimer(hWnd, //窗口句柄
1003, //计时器id
3000, //计时器间隔时间,单位:毫秒
(TIMERPROC)MyTimeFun);//计时器的回调函数
KillTimer(hWnd, 1003);//销毁哪个窗口的哪个计时器
下面是一些简单的操作,大家可以试着实现一下
// win32基本框架.cpp : 定义应用程序的入口点。
//
#include "stdafx.h"
#include "win32基本框架.h"
#define MAX_LOADSTRING 100
// 全局变量:
HINSTANCE hInst; // 当前实例
TCHAR szTitle[MAX_LOADSTRING]; // 标题栏文本
TCHAR szWindowClass[MAX_LOADSTRING]; // 主窗口类名
// 此代码模块中包含的函数的前向声明:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,//应用程序实例句柄 句柄类似于身份证具有唯一性
_In_opt_ HINSTANCE hPrevInstance,//父应用程序实例句柄 比如画图 我打开了一个画图之后又打开了一个画图 先打开的就是父应用程序 后打开的是子应用程序
_In_ LPTSTR lpCmdLine,//命令行参数 在启动这个应用程序后可以给这个程序从命令行传递一些参数
_In_ int nCmdShow)//窗口的显示风格 打开的时候窗口的显示风格 最大化 最小化 ...........
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: 在此放置代码。
MSG msg;
HACCEL hAccelTable;
// 初始化全局字符串
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_WIN32, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// 执行应用程序初始化:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
//加载快捷键资源 暂时用不上
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WIN32));
// 主消息循环:
while (GetMessage(&msg, NULL, 0, 0))//阻塞函数
{
/*这里有两种得到消息的函数 1是Getmessage (&mag,NULL.0,0)*/
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
//
// 函数: MyRegisterClass()
//
// 目的: 注册窗口类。
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WIN32));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_WIN32);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassEx(&wcex);
}
//
// 函数: InitInstance(HINSTANCE, int)
//
// 目的: 保存实例句柄并创建主窗口
//
// 注释:
//
// 在此函数中,我们在全局变量中保存实例句柄并
// 创建和显示主程序窗口。
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hInst = hInstance; // 将实例句柄存储在全局变量中
hWnd = CreateWindow(szWindowClass, _T("pp的第一窗口"),WS_OVERLAPPEDWINDOW/*窗口样式*/,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,/*窗口坐标 左上角 右下角*/
NULL,//父窗口句柄
NULL, //菜单
hInstance,
NULL);//窗口的辅助信息
if (!hWnd)//判断窗口是否创建成功
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);//绘制窗口
UpdateWindow(hWnd);//更新窗口
return TRUE;
}
//
// 函数: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// 目的: 处理主窗口的消息。
//
// WM_COMMAND - 处理应用程序菜单
// WM_PAINT - 绘制主窗口
// WM_DESTROY - 发送退出消息并返回
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent, nVirtKey = (int)wParam,wPa/*虚拟键代码*/;
PAINTSTRUCT ps;
HDC hdc;
static int j = 0;
switch (message)
{
case WM_CREATE:
//创建计时器
SetTimer(hWnd, 10010, 2000, NULL);//两个数字分别是id 和时间间隔(单位:毫秒)
break;
case WM_TIMER:
wPa = wParam;
switch (wPa)
{
case 10010:
j++;
if (j == 3)
KillTimer(hWnd, 10010);
MessageBox(hWnd,_T("10010"), _T("提示"), MB_OK);
break;
}
case WM_SYSKEYDOWN://按键消息
switch (nVirtKey)
{
case VK_MENU:
MessageBox(hWnd, _T("ALT"),_T("提示"),MB_OK);
default:
break;
}
case WM_CHAR://字符消息
wmId = wParam;
switch (wmId)
{
case 'a':
case 'A':
MessageBox(hWnd, _T("a or A"), _T("提示"), 0);
break;
default:
break;
}
case WM_SYSCOMMAND://系统命令
wmId = wParam;
switch (wmId)
{
case SC_CLOSE:
if (IDOK==MessageBox(hWnd, _T("确定要退出吗?"), 0, 0))
{
//PostMessage(hWnd, WM_DESTROY, 0, 0);
PostQuitMessage(0);//两种退出的方式都可以
}
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// 分析菜单选择:
switch (wmId)
{
case IDM_ABOUT:
//DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, //About);
MessageBox(hWnd, _T("第一个窗口:2023/01/17"), _T("关于窗口"), MB_OK);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: 在此添加任意绘图代码...
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// “关于”框的消息处理程序。
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}