MFC:以消息为基础的事件驱动系统和消息映射机制

以消息为基础的事件驱动系统和消息映射机制

(1)消息

A.What(什么是消息)

本质是一个数据结构,用于应用程序不同部分之间进行通信和交互

typedef struct tagMSG {HWND   hwnd;        // 接收该消息的窗口句柄UINT   message;     // 消息标识符(如 WM_CREATE、WM_SIZE 等)WPARAM wParam;      // 32 位消息的特定附加信息,确切含义依赖于消息值LPARAM lParam;      // 32 位消息的特定附加信息,确切含义也依赖于消息值DWORD  time;        // 消息创建时的时间POINT  pt;          // 消息创建时鼠标/光标在屏幕坐标系中的位置
} MSG;
  • hwnd:表示将要接收这个消息的窗口的句柄,也就是说谁将接收到这个消息
  • message:消息的类型标识符,指定了消息的类型,也就是说明了该消息是用来干什么的
  • wParam和lParam:这两个成员用于携带消息的附加参数,其具体含义取决于具体的消息类型
  • time:消息创建时的时间
  • pt:消息创建时鼠标/光标在屏幕坐标系中的位置

B.Which(有哪些类型的消息)

  • 窗口消息:

    与窗口内部运作有关的消息,如创建窗口(wm_create)、绘制窗口(wm_paint)、鼠标移动(wm_mousemove)、控件颜色(wm_ctlcolor)、水平滚动(wm_hscroll)等

  • 命令消息:

    当用户从菜单选中一个命令项目、按下一个快捷键或者点击工具栏上的一个按钮时,都将发送 wm_command 命令消息

    BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd) ON_COMMEND(IDD_BUTTON01, OnButton1LButtonDown) 
    END_MESSAGE_MAP() 
    

    上述代码表明:当点击控件IDD_BUTTON01时,将调用函数OnButton1LButtonDown()

  • 控件通知消息:

    当窗口内的子控件发生一些事件(通常由用户输入触发),需要通知父窗口时发送的消息。通知消息只适用于标准的窗口控件,如按钮、列表框、组合框、编辑框,以及 Windows 公共控件如树状视图、列表视图等

    BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd) ON_NOTIFY(LVN_KEYDOWN, IDC_LIST1, OnKeyDownList1)
    END_MESSAGE_MAP() 

    当列表控件 IDC_LIST1 发送 LVN_KEYDOWN 通知消息时,OnKeyDownList1 函数就会被调用,从而可以在该函数中进行相应的处理

  • 用户定义消息:

    step01:使用#define指令定义一个消息标识符 #define WM_MYMSG WM_USER + 8
    step02:在类声明中声明消息映射 DECLARE_MESSAGE_MAP()
    step03:在类中定义消息处理函数 afx_msg LRESULT MyMsgHandler(WPARAM wParam, LPARAM lParam);
    step04:实现消息映射

    BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd) ON_MESSAGE(WM_MYMSG, OnMyMsgHandler) 
    END_MESSAGE_MAP() 
    

(2)消息队列

A.What(什么是消息队列)

本质是一个存放MSG的队列数据结构,用于存放消息的队列

B.Which(MFC中有哪些消息队列)

系统消息队列:

主要接收来自硬件设备(如鼠标、键盘等)的输入消息,然后将这些消息分配到相应应用程序的线程消息队列中

线程消息队列:

存储与该线程相关的所有消息,包括系统发送的标准 Windows 消息(如 WM_CREATE、WM_SIZE 等)、用户自定义消息以及由其他线程或进程发送给本线程的消息

例如,当用户点击鼠标时,系统会产生一个鼠标点击消息,并将其放入系统消息队列。然后,Windows 会将这个消息传递到相应应用程序的线程消息队列中。应用程序的线程在消息循环中获取到这个消息后,根据消息的类型和参数进行相应的处理,比如调用相应的窗口过程函数。

C.Why(消息队列的作用)

支持事件驱动模型:

通过消息队列,应用程序能够根据不同的消息触发相应的处理逻辑,实现对用户操作和系统事件的响应

缓冲消息:

对于短时间内大量产生的消息,消息队列起到缓冲的作用,避免消息的丢失或处理混乱。它按照先进先出的原则存储消息,保证消息处理的顺序性

跨线程通信:

不同线程之间可以通过向特定线程的消息队列发送消息来进行通信,实现线程之间的协调和数据传递

D.Who(谁管理消息队列)

在MFC中,Window操作系统统一管理着所有的消息队列,包括系统消息队列和线程消息队列。

在一个多线程的应用程序中,不同线程的消息队列由操作系统统一管理,使得每个线程能够按照其自身的逻辑和优先级来处理接收到的消息,而不会出现混乱或冲突

E.How(如何使用消息队列)

  • 向消息队列中添加消息:PostMessage()和SendMessage()

    PostMessage(),将消息放入线程的消息队列后立即返回,不等待消息被处理;
    SendMessage(),直接调用窗口的窗口过程函数来处理消息,并等待处理完成后才返回

  • 从消息队列中取消息:GetMessage()和PeekMessage()

    GetMessage(),从线程的消息队列中取出一条消息,如果消息队列中没有消息,该函数会阻塞,直到有消息可用或者收到 WM_QUIT 消息
    PeekMessage(),与 GetMessage 不同的是,如果消息队列中没有消息,它不会阻塞,而是立即返回 FALSE

    消息分发的一般步骤:循环读取消息队列中的消息,并进行

    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {TranslateMessage(&msg); //翻译消息DispatchMessage(&msg); //分发消息
    }
    

    TranslateMessage函数会检查传入的消息,如果发现是WM_KEYDOWN和WM_KEYUP消息的组合,且对应的键可以被键盘驱动器映射为 ASCII 字符,它就会将其转换为一条WM_CHAR消息

    DispatchMessage函数将消息分发给相应的窗口过程进行处理,因为MSG中包含消息所接收的窗口句柄

(3)消息的处理过程

外部设备或窗口内部事件产生消息,产生的消息进入线程的消息队列中,而WIndow应用程序的主函数会不断调用GetMessage函数从消息列表中获取消息,并进行消息翻译和消息转发实现消息的处理。
在这里插入图片描述

(4)消息映射机制

A.What(什么是消息映射机制)

用于将 Windows 消息与类成员函数进行关联和处理的高效机制

B.Why(消息映射机制的作用)

将这些 Windows 消息与特定的类成员函数关联起来。这样,当特定的消息被发送到窗口时,MFC 框架能够根据消息映射找到对应的处理函数,并调用它来执行相应的操作

通过消息映射机制,开发者无需直接处理复杂的 Windows 消息循环和分发逻辑,而是可以专注于编写具体的消息处理代码

C.How(如何进行消息映射)

一般而言,针对不同的消息类型,使用不同的宏进行消息映射

  • 窗口消息:

    与窗口内部运作有关的消息,如创建窗口(wm_create)、绘制窗口(wm_paint)、鼠标移动(wm_mousemove)、控件颜色(wm_ctlcolor)、水平滚动(wm_hscroll)等

  • 命令消息:

    当用户从菜单选中一个命令项目、按下一个快捷键或者点击工具栏上的一个按钮时,都将发送 wm_command 命令消息

    BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd) ON_COMMEND(IDD_BUTTON01, OnButton1LButtonDown) 
    END_MESSAGE_MAP() 
    

    上述代码表明:当点击控件IDD_BUTTON01时,将调用函数OnButton1LButtonDown()

  • 控件通知消息:

    当窗口内的子控件发生一些事件(通常由用户输入触发),需要通知父窗口时发送的消息。通知消息只适用于标准的窗口控件,如按钮、列表框、组合框、编辑框,以及 Windows 公共控件如树状视图、列表视图等

    BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd) ON_NOTIFY(LVN_KEYDOWN, IDC_LIST1, OnKeyDownList1)
    END_MESSAGE_MAP() 

    当列表控件 IDC_LIST1 发送 LVN_KEYDOWN 通知消息时,OnKeyDownList1 函数就会被调用,从而可以在该函数中进行相应的处理

  • 用户定义消息:

    step01:使用#define指令定义一个消息标识符 #define WM_MYMSG WM_USER + 8
    step02:在类声明中声明消息映射 DECLARE_MESSAGE_MAP()
    step03:在类中定义消息处理函数 afx_msg LRESULT MyMsgHandler(WPARAM wParam, LPARAM lParam);
    step04:实现消息映射

    BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd) ON_MESSAGE(WM_MYMSG, OnMyMsgHandler) 
    END_MESSAGE_MAP() 
    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/381318.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

blender使用- 置换修改器

置换修改器 对于物体可以先做细分,然后添加置换修改器,添加贴图。再对贴图的参数进行修改,渲染想要的效果。 旋转模式下(按下s),z表示方向,0表示平整

初学51单片机之指针基础与串口通信应用

开始之前推荐一个电路学习软件,这个软件笔者也刚接触。名字是Circuit有在线版本和不在线版本,这是笔者在B站看视频翻到的。 Paul Falstadhttps://www.falstad.com/这是地址。 离线版本在网站内点这个进去 根据你的系统下载你需要的版本红线的是windows…

C++中的多路转接技术之epoll

epoll 是干什么的?举个简单的例子 epoll的相关系统调用**epoll_create**和epoll_create1区别 epoll_ctl参数解释 **epoll_wait**参数说明返回值 epoll的使用 **epoll**工作原理epoll的优点(和 **select** 的缺点对应)epoll工作方式**水平触发**Level Triggered 工作…

艺术成分很高的完全自定义的UITabBar(很简单)

引言 在iOS应用开发中,UITabBar是一个非常场景且重要的UI组件。系统为我们提供的UITabBar虽然功能强大,但是在某些情况下,它的标准样式并不能满足我们特定的设计需求,它的灵活性也有一些局限。为了打造更具个性化好的用户友好的交…

【细如狗】记录一次使用MySQL的Binlog进行数据回滚的完整流程

文章目录 1 事情起因2 解决思路3 利用binlog进行数据回滚3.1 确认是否启用Binlog日志3.2 确认是否有binlog文件3.3 找到误操作的时间范围3.4 登录MySQL服务器查找binlog文件3.4.1 查询binlog文件路径3.4.2 找到binlog文件3.4.3 确认误操作被存储在哪一份binlog文件中 3.5 查看二…

【单片机毕业设计选题24074】-基于阿里云的空气质量监控系统

系统功能: 手机开启2.4G WiFi热点后再给系统上电 系统操作说明: 上电后OLED显示 “欢迎使用空气监控系统请稍后”,两秒后显示Connecting...表示 正在连接阿里云,正常连接阿里云后显示第一页面,如长时间显示Connecting...请 检…

初识C++|模板初阶

🍬 mooridy-CSDN博客 🧁C专栏(更新中!) 目录 🍉1. 泛型编程 🍉2. 函数模板 🥝2.1 函数模板概念 🥝2.2 函数模板格式 🥝2.3 函数模板的原理 &#x1f95…

elementUI在手机端使用遇到的问题总结

之前的博客有写过用vue2elementUI封装手机端选择器picker组件,支持单选、多选、远程搜索多选,最终真机调试的时候发现有很多细节样式需要调整。此篇博客记录下我调试过程中遇到的问题和解决方法。 一、手机真机怎么连电脑本地代码调试? 1.确…

Android 11 HAL层集成FFMPEG

1.集成目录: android/vendor/noch/common/external/NoboMediaCodec 2.文件夹目录 3. Android.mk实现 # Copyright #LOCAL_PATH : $(call my-dir)SF_COMMON_MK : $(LOCAL_PATH)/common.mkinclude $(call first-makefiles-under,$(LOCAL_PATH))4.common.mk实现 # #…

视觉巡线小车——STM32+OpenMV(三)

目录 前言 一、OpenMV代码 二、STM32端接收数据 1.配置串口 2.接收数据并解析 总结 前言 通过视觉巡线小车——STM32OpenMV(二),已基本实现了减速电机的速度闭环控制。要使小车能够自主巡线,除了能够精准的控制速度之外&#xff0…

微信被好友屏蔽朋友圈/拉黑/删除?教你几招悄悄验证

微信这一国民级的社交软件,基本上渗入了大家日常生活的方方面面,沟通、支付、购物、娱乐都可以在上面一站式解决。微信功能虽然很全面,但某些功能细节设计也会让人感到困惑,比如我们被朋友拉黑或者删除,微信是不会通知…

数学建模--优劣解距离法TOPSIS

目录 简介 TOPSIS法的基本步骤 延伸 优劣解距离法(TOPSIS)的历史发展和应用领域有哪些? 历史发展 应用领域 如何准确计算TOPSIS中的理想解(PIS)和负理想解(NIS)? TOPSIS方法在…

【NLP自然语言处理】基于BERT实现文本情感分类

Bert概述 BERT(Bidirectional Encoder Representations from Transformers)是一种深度学习模型,用于自然语言处理(NLP)任务。BERT的核心是由一种强大的神经网络架构——Transformer驱动的。这种架构包含了一种称为自注…

宝塔SSL续签失败

我有2个网站a和b(文字中用baidu.com替换我的域名) b是要续签那个,但续签报错: nginx version: nginx/1.22.1 nginx: [emerg] host not found in upstream "github.com" in /www/server/panel/vhost/nginx/proxy/a.bai…

分享 2 个 .NET EF 6 只更新某些字段的方法

前言 EF 更新数据时,通常情况下,是更新全部字段的,但实际业务中,更新全部字段的情况其实很少,一般都是修改其中某些字段,所以为了实现这个目标,很多程序员通常会这样作: 先从数据库…

Nginx 怎样处理请求的熔断机制?

🍅关注博主🎗️ 带你畅游技术世界,不错过每一次成长机会! 文章目录 Nginx 怎样处理请求的熔断机制?一、什么是熔断机制二、Nginx 中的熔断机制原理(一)基于错误率(二)基于…

超级写手:AI笔耕者的未来图谱

在数字化时代,人工智能(AI)正悄然改变着各行各业的传统作业方式。其中,“超级写手”——AI scribes,作为一种新兴的垂直应用场景,正以其独特的魅力吸引着投资者的目光。本文将深入探讨AI写手的市场背景、技术栈、投资策略及其潜在应用领域,带您一窥这个未来写作助手的广…

动手学深度学习——5.卷积神经网络

1.卷积神经网络特征 现在,我们将上述想法总结一下,从而帮助我们设计适合于计算机视觉的神经网络架构。 平移不变性(translation invariance):不管检测对象出现在图像中的哪个位置,神经网络的前面几层应该对…

Docker构建LNMP环境并运行Wordpress平台

1.准备Nginx 上传文件 Dockerfile FROM centos:7 as firstADD nginx-1.24.0.tar.gz /opt/ COPY CentOS-Base.repo /etc/yum.repos.d/RUN yum -y install pcre-devel zlib-devel openssl-devel gcc gcc-c make && \useradd -M -s /sbin/nologin nginx && \cd /o…

解决 go 引用私有包,安装失败

问题描述 go mod tidy 或者 go run main.go 时,提示失败,例如 no such host(设置GOPRIVATE)或者 x509: certificate signed by unknown authority 之类的报错(设置GOINSECURE) 解决 在各种 insteadof 方…