Win32 一个最简单的窗口,到底涉及了多少事件

举报
福州司马懿 发表于 2022/11/19 22:11:03 2022/11/19
【摘要】 绑定消息处理器首先,在注册窗体类时,会将自定义消息处理函数绑定到 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;
}

结果如下,原来创建一个窗口还会额外触发这么多的事件,剩下的就靠你们了

图片.png

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。