Win32 一个最简单的窗口,到底涉及了多少事件
【摘要】 绑定消息处理器首先,在注册窗体类时,会将自定义消息处理函数绑定到 WNDCLASSEXW结构体的lpfnWndProc属性上//// 函数: MyRegisterClass()//// 目标: 注册窗口类。//ATOM MyRegisterClass(HINSTANCE hInstance){ WNDCLASSEXW wcex; wcex.cbSize = sizeof(W...
绑定消息处理器
首先,在注册窗体类时,会将自定义消息处理函数绑定到 WNDCLASSEXW
结构体的lpfnWndProc
属性上
//
// 函数: MyRegisterClass()
//
// 目标: 注册窗口类。
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW | DS_CENTER;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WINDOWSPROJECT1));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
//wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_WINDOWSPROJECT1);
lstrcpy(szWindowClass, L"test");
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassExW(&wcex);
}
WNDCLASSEXW
的结构体如下
typedef struct tagWNDCLASSEXW {
UINT cbSize;
/* Win 3.x */
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HINSTANCE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCWSTR lpszMenuName;
LPCWSTR lpszClassName;
/* Win 4.0 */
HICON hIconSm;
} WNDCLASSEXW, *PWNDCLASSEXW, NEAR *NPWNDCLASSEXW, FAR *LPWNDCLASSEXW;
结构体tagWNDCLASSEXW
的成员变量lpfnWndProc
实际上是一个函数指针,因此可以直接将原型相同的函数赋值给它
typedef LRESULT (CALLBACK* WNDPROC)(HWND, UINT, WPARAM, LPARAM);
消息处理函数
WndProc
是具体的窗口消息处理函数,定义如下
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
message
常见的事件
事件 | 含义 |
---|---|
WM_CREATE | 应用程序创建一个窗口 |
WM_DESTROY | 窗口被销毁 |
WM_MOVING | 当窗口正在移动时触发 |
WM_MOVE | 窗口移动 |
WM_SIZING | 当窗口大小正在被调整时触发 |
WM_SIZE | 窗口大小改变 |
WM_ACTIVATE | 窗口被激活或失去激活状态 |
WM_SETFOCUS | 获取焦点 |
WM_KILLFOCUS | 失去焦点 |
WM_ENABLE | 改变enable状态 |
WM_PAINT | 窗口重绘 |
WM_TIMER | 发生了定时器事件 |
WM_COMMAND | 点击菜单, 点击加速键(键盘快捷键,是一个或几个按键的组合,它用于激活特定的命令,使用加速键不需要费力移动鼠标就能激活菜单项),点击窗口按钮,点击工具栏按钮 |
WM_KEYDOWN | 按下一个按键 |
WM_KEYUP | 释放一个按键 |
WM_CHAR | 按下某键,并已发出WM_KEYDOWN,WM_KEYUP消息 |
WM_MOUSEMOVE | 移动鼠标 |
WM_LBUTTONDOWN | 按下鼠标左键 |
WM_LBUTTONUP | 释放鼠标左键 |
WM_LBUTTONDBLCLK | 双击鼠标左键 |
WM_RBUTTONDOWN | 按下鼠标右键 |
WM_RBUTTONUP | 释放鼠标右键 |
WM_RBUTTONDBLCLK | 双击鼠标右键 |
WM_MBUTTONDOWN | 按下鼠标中键 |
WM_MBUTTONUP | 释放鼠标中键 |
WM_MBUTTONDBLCLK | 双击鼠标中键 |
WM_MOUSEWHEEL | 鼠标滚轮滚动 |
最常被触发的事件
事件 | 码值 | 含义 |
---|---|---|
WM_SETCURSOR | 0x0020 | 如果鼠标导致光标在窗口中移动,并且未捕获鼠标输入,则发送到窗口 |
WM_NCHITTEST | 0x0084 | 发送到窗口以确定窗口的哪个部分对应于特定的屏幕坐标。 例如,当光标移动、按下或释放鼠标按钮或响应对 WindowFromPoint 等函数的调用时,可能会发生这种情况 |
NC事件
非显示区域鼠标消息几乎完全与显示区域鼠标消息相对应。消息中含有字母“NC”以表示是非显示区域消息。如果鼠标在窗口的非显示区域中移动,那么窗口消息处理程序会接收到WM_NCMOUSEMOVE消息。鼠标按键产生如表所示的消息:
键 | 按下 | 释放 | 按下(双击) |
---|---|---|---|
左 | WM_NCLBUTTONDOWN | WM_NCLBUTTONUP | WM_NCLBUTTONDBLCLK |
中 | WM_NCMBUTTONDOWN | WM_NCMBUTTONUP | WM_NCMBUTTONDBLCLK |
右 | WM_NCRBUTTONDOWN | WM_NCRBUTTONUP | WM_NCRBUTTONDBLCLK |
此外还有鼠标移动事件 WM_NCMOUSEMOVE
测试代码
首先,还是打开控制台
#include <stdio.h>
void ShowConsole()
{
AllocConsole();
FILE* stream;
freopen_s(&stream, "CON", "r", stdin);//重定向输入流
freopen_s(&stream, "CON", "w", stdout);//重定向输入流
}
接着,自定义打印事件的方法,并对事件函数WndProc
进行打印
void PrintFormat(const char* enName, const char* chName)
{
printf("%s\t\t%s\n", enName, chName);
}
//
// 函数: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// 目标: 处理主窗口的消息。
//
// WM_COMMAND - 处理应用程序菜单
// WM_PAINT - 绘制主窗口
// WM_DESTROY - 发送退出消息并返回
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
PrintFormat("WM_CREATE", "创建");
break;
case WM_DESTROY:
PrintFormat("WM_DESTROY", "销毁");
PostQuitMessage(0);
break;
case WM_PAINT:
{
PrintFormat("WM_PAINT", "重绘");
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: 在此处添加使用 hdc 的任何绘图代码...
EndPaint(hWnd, &ps);
}
break;
case WM_TIMER:
PrintFormat("WM_TIMER", "定时器");
break;
case WM_COMMAND:
PrintFormat("WM_COMMAND", "菜单事件");
break;
case WM_MOVING:
PrintFormat("WM_MOVING", "移动中");
break;
case WM_MOVE:
PrintFormat("WM_MOVE", "移动");
break;
case WM_SIZING:
PrintFormat("WM_SIZING", "大小改变中");
break;
case WM_SIZE:
PrintFormat("WM_SIZE", "大小改变");
break;
case WM_ACTIVATE:
PrintFormat("WM_ACTIVATE", "被激活或失去激活");
break;
case WM_SETFOCUS:
PrintFormat("WM_SETFOCUS", "获取焦点");
break;
case WM_KILLFOCUS:
PrintFormat("WM_KILLFOCUS", "失去焦点");
break;
case WM_ENABLE:
PrintFormat("WM_ENABLE", "启用或禁用");
break;
case WM_SETCURSOR:
//PrintFormat("WM_SETCURSOR", "设置鼠标");
break;
case WM_NCHITTEST:
//PrintFormat("WM_NCHITTEST", "确定位置");
break;
case WM_KEYDOWN:
PrintFormat("WM_KEYDOWN", "按下按键");
break;
case WM_KEYUP:
PrintFormat("WM_KEYUP", "释放按键");
break;
case WM_CHAR:
PrintFormat("WM_CHAR", "按下某键,并已发出WM_KEYDOWN,WM_KEYUP消息");
break;
//非显示区域
case WM_NCMOUSEMOVE:
break;
case WM_NCLBUTTONDOWN:
break;
case WM_NCLBUTTONUP:
break;
case WM_NCLBUTTONDBLCLK:
break;
case WM_NCMBUTTONDOWN:
break;
case WM_NCMBUTTONUP:
break;
case WM_NCMBUTTONDBLCLK:
break;
case WM_NCRBUTTONDOWN:
break;
case WM_NCRBUTTONUP:
break;
case WM_NCRBUTTONDBLCLK:
break;
case WM_MOUSEMOVE:
//PrintFormat("WM_MOUSEMOVE", "鼠标移动");
break;
case WM_LBUTTONDOWN:
PrintFormat("WM_LBUTTONDOWN", "按下鼠标左键");
break;
case WM_LBUTTONUP:
PrintFormat("WM_LBUTTONUP", "释放鼠标左键");
break;
case WM_LBUTTONDBLCLK:
PrintFormat("WM_LBUTTONDBLCLK", "双击鼠标左键");
break;
case WM_RBUTTONDOWN:
PrintFormat("WM_RBUTTONDOWN", "按下鼠标右键");
break;
case WM_RBUTTONUP:
PrintFormat("WM_RBUTTONUP", "释放鼠标右键");
break;
case WM_RBUTTONDBLCLK:
PrintFormat("WM_RBUTTONDBLCLK", "双击鼠标右键");
break;
case WM_MBUTTONDOWN:
PrintFormat("WM_MBUTTONDOWN", "按下鼠标中键");
break;
case WM_MBUTTONUP:
PrintFormat("WM_MBUTTONUP", "释放鼠标中键");
break;
case WM_MBUTTONDBLCLK:
PrintFormat("WM_MBUTTONDBLCLK", "双击鼠标中键");
break;
case WM_MOUSEWHEEL:
PrintFormat("WM_MOUSEWHEEL", "鼠标滚轮滚动");
break;
default:
printf("WndProc msg=0x%04X, wParam=%I64d, lParam=%I64d\n", message, wParam, lParam);
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
结果如下,原来创建一个窗口还会额外触发这么多的事件,剩下的就靠你们了
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)