02. win32消息机制
win32消息机制
消息机制
-
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); //第四个参数: //PM_REMOVE:消息在处理PeekMessage后从队列中删除。 //PM_NOREMOVE:消息在PeekMessage处理后不会从队列中删除。
发送消息
-
SendMessage
可以理解为递归(插队),直接把消息投递给该窗口对应的消息处理函数
SendMessage(hWnd,WM_KEYDOWN,0,0);
-
PostMessage
可以理解为排队,把消息投递给这个窗口对应的消息队列,以供下一次去得到消息
PostMessage(hWnd, WM_KEYDOWN, 0, 0);
基本消息
- 基本消息一般在
WndProc()
函数中以switch—case来循环判断 - 因此,要注意如果在case中有变量的声明,应该用大括号将case内容括起来,否则会报错,下文 激活消息 中的示例正是这一点的体现
- 还要注意在写case时就应加上break,养成好习惯!
创建窗口消息
-
WM_CREATE
-
创建窗口时被发送给应用程序,该消息只被发送一次。理解为类的构造
-
注意:以下语句
case WM_CREATE: MessageBox(0, 0, 0, 0);//弹窗 break;
WM_CREATE消息是先出现弹窗,处理完弹窗后在出现窗口
因为InitInstance(HINSTANCE hInstance, int nCmdShow)函数中先进行CreateWindowW再ShowWindow(hWnd, nCmdShow);UpdateWindow(hWnd);
-
销毁窗口消息
- WM_DESTROY
- 当关闭窗口时或者开发人员在程序中调用了DestroyWindow函数时,WM_DESTROY消息会被发送给应 用程序。理解为类的析构
激活消息
-
WM_ACTIVATE
-
该消息在以下3种情况时被发送:
-
- 鼠标单击激活。wParam参数被标记为WA_CLICKACTIVE
- 非鼠标激活。wParam参数被标记为WA_ACTIVE
- 非激活。wParam参数被标记为WA_INACTIVE
-
case WM_ACTIVATE: { //#define LOWORD(l) ((WORD)(l)) int wmId = LOWORD(wParam);//有变量声明,给case的内容加上大括号 switch (wmId) { case WA_CLICKACTIVE: MessageBox(hWnd, _T("鼠标点击激活"), L"提示", MB_OK| MB_ICONINFORMATION); break; } } break;
-
系统命令消息
-
WM_SYSCOMMAND
-
在关闭、最大化、最小化、还原窗口时被发送给应用程序。
- 当wParam参数为SC_CLOSE时表示窗口进行了关闭操作
- 当wParam参数为SC_MAXIMIZE时,表示窗口进行了最大化操作
- 当wParam参数为SC_MINIMIZE时,表示窗口进行了最小化操作
- 当wParam参数为SC_RESTORE时,表示将窗口恢复到其正常位置和大小。
-
case WM_SYSCOMMAND: { switch (wParam) { case SC_CLOSE: //_T("关闭")使用的是宽字节字符(_T("")在unicode下所有字符均为2字节) //也可以使用 L"提示" 将内容转化为宽字节 if (IDOK == MessageBox(hWnd, _T("关闭"), L"提示", MB_OK)) { PostQuitMessage(0); } break; default: return DefWindowProc(hWnd, message, wParam, lParam); } } break;
-
命令消息
-
WM_COMMAND
-
当用户从菜单选中一个命令项目、当一个控件发送通知消息给去父窗口或者按下一个快捷键将发送 WM_COMMAND 消息
-
case WM_COMMAND: { int wmId = LOWORD(wParam); // 分析菜单选择: switch (wmId) { case IDM_ABOUT: DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); break; case IDM_EXIT: if(IDOK == MessageBox(hWnd, _T("是否关闭窗口"), L"提示", MB_OKCANCEL)) DestroyWindow(hWnd); break; case ID_32771: MessageBox(hWnd, _T("新建"), L"提示", MB_OK); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } } break;
-
常用消息
按键消息
- 键盘是用户的标准输入设备,键盘的按键事件以消息的方式提供给应用程序
- 当按下一个键时Windows会产生WM_KEYDOWN或者WM_SYSKEYDOWN消息,当释放一个键时, Windows会产生WM_KEYUP或者WM_SYSKEYUP消息
- windows为按键的一个真实键值准备一个虚拟键值,对于ascii码中有的数据用ascii码来做为虚拟键值, 如果在ascii码中没有,vk_键名
- 虚拟键值可在Win32API参考手册 (yfvb.com) -> 附录 -> 虚拟键码 中查询
-
WM_KEYDOWN
- 按键按下
-
WM_KEYUP
- 按键抬起
-
WM_SYSKEYDOWN
-
系统按键按下。
-
ALT或F10键
-
ALT+组合键
-
-
-
WM_SYSKEYUP
-
系统按键抬起 注意:按键消息响应VK_虚拟键名,如果是ASCII码则响应大写
-
//WM_SYSKEYUP不会区分大小写,无论是否开启大写,响应的都是A case WM_SYSKEYUP://F10 ALT+ { switch (wParam) { case 'A': MessageBox(hWnd, _T("A"), L"提示", MB_OK); break; case 'a': MessageBox(hWnd, _T("a"), L"提示", MB_OK); break; } } break;
-
-
WM_CHAR
-
TranslateMessage函数会对消息进行一部分预处理将键消息根据窗口当前状态翻译成对应的字符输入信 息,产生WM_CHAR消息
-
如果同时输入了多个字符,则WM_CHAR消息将被发送多次
-
字符消息可以响应大小写字符
-
//WM_CHAR会区分大小写,开启大写后小写的不会响应,关闭大写后大写不会响应,按住 ALT+其他键 的字符同样可以响应 case WM_CHAR://区分大小写 判断字符 { switch (wParam) { case 's': MessageBox(hWnd, _T("s"), L"提示", MB_OK); break; case 'W': MessageBox(hWnd, _T("W"), L"提示", MB_OK); break; case '@': MessageBox(hWnd, _T("@"), L"提示", MB_OK); break; } }
-
鼠标消息
左键:
-
WM_LBUTTONDOWN
-
WM_LBUTTONUP
-
WM_LBUTTONDBLCLK
中键:
-
WM_MBUTTONDOWN
-
WM_MBUTTONUP
-
WM_MBUTTONDBLCLK
右键:
-
WM_RBUTTONDOWN
-
WM_RBUTTONUP
-
WM_RBUTTONDBLCLK
光标:
- WM_MOUSEMOVE
滚轮
- WM_MOUSEWHEEL
得到鼠标当前坐标
- GET_X_LPARAM(lParam)
- GET_Y_LPARAM(lParam)
得到鼠标滚轮前后滚动
- HIWORD(wParam)
- 朝前是120,朝后是-120 (均以滚动一格为衡量条件)
计时器消息
设置计时器
SetTimer(hWnd, //窗口句柄
1003, //计时器id
3000, //计时器间隔时间,单位:毫秒
(TIMERPROC)MyTimeFun);//计时器的回调函数
//注意第四个参数,所需类型是TIMERPROC,因此需要强转
响应计时器
-
如果设置计时器时,第4个参数为NULL,在WM_TIMER响应消息,通过wParam来匹配计时器id
-
如果设置计时器时,第4个参数有回调函数,则在回调函数中响应,也就是调用这个函数
销毁计时器
KillTimer(hWnd, 1003);//销毁哪个窗口的哪个计时器