第二章 使用MFC消息机制
- 格式:ppt
- 大小:143.00 KB
- 文档页数:21
MFC(Microsoft Foundation Classes)是一种用于开发Windows应用程序的C++类库,它建立在Win32 API之上,并提供了更高层次的抽象和封装。
在MFC中,消息机制是实现应用程序与用户交互和事件处理的基础。
MFC消息机制的原理如下:1.消息映射表:在MFC应用程序中,每个窗口类(如对话框类、视图类等)通常都有一个消息映射表(message map),用于将消息与相应的处理函数关联起来。
消息映射表是一个静态数据结构,通过DECLARE_MESSAGE_MAP宏进行声明,并在类的实现文件中使用BEGIN_MESSAGE_MAP和END_MESSAGE_MAP宏定义映射表的内容。
2.消息处理函数:每个消息映射表项将消息的ID(或者命令ID)与相应的消息处理函数绑定在一起。
消息处理函数是成员函数,由开发人员根据需要自行定义。
当相应的消息被触发时,系统会自动调用与该消息对应的处理函数。
3.消息循环:MFC应用程序在运行时通过消息循环(message loop)不断接收和分发消息。
消息循环负责从操作系统获取消息,并将消息派发给目标窗口的消息处理函数进行处理。
消息循环可以使用Run函数或AfxGetApp()->Run函数启动。
4.分发消息:当系统从消息队列中获取到一个消息后,会根据消息的目标窗口通过HWND来查找对应的CWnd对象,并调用该窗口的响应函数(如PreTranslateMessage、OnCmdMsg等)进行消息处理。
如果消息在目标窗口的消息映射表中找到了对应的处理函数,则将该消息转发给对应的处理函数进行处理。
5.消息处理:消息处理函数执行相应的逻辑,可以进行界面更新、控件操作、数据处理等操作。
处理函数的返回值通常是布尔型,表示是否终止消息的传递。
通过这种消息机制,MFC应用程序可以实现用户交互和事件处理的功能,使开发人员可以方便地处理窗口消息,响应用户操作,以及完成界面和数据之间的交互。
mfc消息机制
MFC(Microsoft Foundation Class)是微软开发的一种面向对象的C++框架,用于Windows操作系统的应用程序开发。
MFC消息机制是MFC框架的核心之一,其基本原理是在窗口、控件等对象之间传递消息,以便处理事件和交互。
具体而言,MFC消息机制包括以下几个方面:1.消息循环:MFC使用一个消息循环来接受和处理Windows操作系统发送的Windows消息,处理完消息后将处理结果反馈给Windows操作系统。
2.消息映射:MFC中的控件和窗口都有一个关联的消息映射表,用于将Windows消息映射到应用程序代码中的相应处理函数上。
当某个控件或窗口收到消息后,根据消息类型在相应的消息映射表中查找对应的消息处理函数,并调用相应的处理函数处理消息。
3.消息类型:MFC处理的Windows消息类型包括键盘和鼠标消息、定时器消息、系统负载消息、窗口大小变化消息等等,具体的消息类型可以在MFC框架的文档中查找。
4.消息处理函数:MFC中的消息处理函数是C++成员函数,定义为afx_msg 修饰的函数,Windows消息处理函数命名时需要遵循一定的命名规则,例如OnPaint()函数用于处理绘图事件。
需要注意的是,MFC消息机制是针对Windows操作系统设计的,其他操作系统可能具有不同的消息机制。
此外,MFC框架已经不是微软推荐的最先进的应用程序开发框架,已经逐渐被其他框架和技术所取代,例如.NET Framework,WPF,UWP等。
MFC使用教程范文MFC(Microsoft Foundation Classes)是微软的一套C++类库,用于开发Windows桌面应用程序。
本教程将向您介绍MFC的基本概念和使用方法。
一、MFC简介MFC是基于面向对象的设计思想,为开发Windows应用程序提供了一套强大的工具和框架。
它提供了诸如窗口、对话框、菜单等常见界面元素的类,并且封装了底层的Windows API,简化了程序的编写过程。
二、MFC应用程序的创建要创建一个MFC应用程序,您可以使用Visual Studio进行操作。
首先,打开Visual Studio,并选择“新建项目”,然后选择“MFC应用程序”模板。
在创建项目的向导中,您可以指定应用程序的名称、位置和其他选项。
接下来,您可以选择所需的特性和模板。
例如,如果需要创建一个对话框应用程序,则可以选择“对话框”模板。
创建完成后,Visual Studio将自动为您生成一个基本的MFC应用程序框架,包括一个主窗口、一个菜单栏、一个工具栏和一个状态栏。
三、MFC界面元素的创建和使用1. 窗口(CWnd类):MFC提供了多种窗口类,如CFrameWnd、CView 等,您可以根据需要选择合适的窗口类来创建窗口。
4. 菜单(CMenu类):MFC通过CMenu类来管理菜单。
您可以创建菜单项并将其添加到菜单中,然后将菜单与窗口相关联。
5. 工具栏(CToolBar类):工具栏是一种常见的界面元素,用于提供快速访问常用命令的按钮。
您可以通过CToolBar类创建和管理工具栏,并将其与窗口相关联。
四、MFC消息机制在MFC中,程序通过消息来进行事件处理。
消息是由操作系统发送给应用程序的,应用程序通过重载消息响应函数来处理不同类型的消息。
在MFC中,您可以通过添加消息映射宏(BEGIN_MESSAGE_MAP和END_MESSAGE_MAP)和消息处理函数(OnXxx系列函数)来处理消息。
MFC消息映射机制过程1:windows OS事件驱动策略基于3种消息。
标准消息、通告消息、命令消息。
2:“事件”就是“消息”,事件是有形形象的,是站在⼈类能理解的⾓度来定义的。
消息是⽆形抽象的,是站在OS能理解的⾓度来定义的。
3:我把按下⿏标左键这⼀事件转换成WM_LBUTOONDOWN消息来告诉OS我做了按下⿏标左键这了件事情。
现在OS知道了我做了按下⿏标左键这了件事情了,那么OS怎么处理呢?3.1:消息响应函数原型//{{AFX_MSG(CMyView)afx_msg void OnLButtonDown(UINT nFlags,CPoint point);//}}AFX_MSGDECLARE_MESSAGE_MAP()3.2:ON_WM_LBUTTONDOWN消息映射宏BEGIN_MESSAGE_MAP(CMyView, CView)//{{AFX_MSG_MAP(CMyView)ON_WM_LBUTTONDOWN()//}}AFX_MSG_MAP// Standard printing commandsON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)END_MESSAGE_MAP()3.3:消息响应函数的定义void CMyView::OnLButtonDown(UINT nFlags, CPoint point){// TODO: Add your message handler code here and/or call defaultMessageBox("WM_LBUTTONDOWN");CView::OnLButtonDown(nFlags, point);}4:⾄此,我们从按下⿏标左键到看到如下图的效果,OS完成了对事件做出的反应。
mfc 信息机制MFC信息机制MFC(Microsoft Foundation Class)是微软公司推出的一套用于Windows操作系统的C++类库,它为开发者提供了丰富的工具和组件,用于快速构建Windows应用程序。
在MFC中,信息机制是其重要特性之一,它提供了一种方便的方式来管理和传递应用程序中的消息。
一、消息机制的基本概念在MFC中,消息是指应用程序中发生的各种事件,比如鼠标点击、键盘输入、窗口关闭等。
消息机制是指MFC框架中的一套机制,用于处理和分发这些消息。
消息的处理过程包括两个关键组件:消息映射和消息处理函数。
1. 消息映射消息映射是指将消息和消息处理函数进行关联的过程。
通过在类的消息映射表中添加相应的消息和处理函数的映射关系,可以告诉MFC框架在收到某个消息时应该调用哪个函数进行处理。
消息映射表一般定义在类的声明中,使用宏来声明消息映射表的内容。
2. 消息处理函数消息处理函数是指用于处理特定消息的函数。
当MFC框架收到某个消息时,会根据消息映射表中的映射关系调用相应的消息处理函数。
消息处理函数可以是类的成员函数,也可以是全局函数,具体取决于消息映射表中的声明方式。
二、消息机制的应用场景消息机制在MFC中广泛应用于用户界面的交互和事件响应。
通过消息机制,开发者可以方便地处理用户的操作和系统的事件,实现各种功能和交互效果。
1. UI事件响应在MFC应用程序中,用户通过与界面上的控件进行交互来触发各种事件,比如按钮点击、菜单选择等。
通过消息机制,我们可以将这些事件与相应的处理函数进行关联,当用户触发某个事件时,可以执行相应的处理逻辑。
2. 窗口消息处理MFC中的窗口是指用户界面上的各种窗口元素,比如对话框、窗口、视图等。
窗口消息是指与窗口相关的各种事件,比如窗口创建、大小改变、关闭等。
通过消息机制,我们可以对窗口消息进行处理,实现窗口的初始化、布局、关闭等功能。
3. 自定义消息除了系统定义的消息类型,MFC还支持自定义消息。
MFC消息机制⼀、消息的分类1、队列消息、⾮队列消息l队列消息:windows为每个应⽤程序都建⽴⼀个消息队列,那么通过消息队列,进⾏传送的消息都属于队列消息;⼀般来说,由⿏标、键盘产⽣的消息都属于队列消息。
(为什么呢?想想,⿏标、键盘事件都是由系统捕获的,系统捕获后要传递给应⽤程序,就⼀定的通过消息队列);l⾮队列消息:除了队列消息,剩下的⾃然⽽然就是⾮队列消息了;u队列消息是通过PostMessage()的⽅式投递消息的,这样的消息发送也叫“寄送”,该函数寄送消息即可返回,不需要等待程序处理结果;u⾮队列消息是通过SendMessage()的⽅式进⾏的,这样的消息发送叫“发送”;消息不需要进⼊窗⼝的消息队列,然⽽不管是队列消息,还是⾮队列消息,消息处理的起点都是AfxWndProc。
不同的是队列消息,是操作系统把消息投放到消息队列,应⽤程序空闲是,通过⼀个消息循环,搜索消息队列,不停的从消息队列抓取消息,并处理。
⼤致流程是:CwinThread->PumpMessage->CWnd->PreTranslateMessage->…………..->USER32内核->AfxWndProcBase->AfxWndProc->…….(继续处理)⽽⾮队列消息呢(即通过SendMessage⽅式发送的消息)?它是直接进⼊了USER32内核,然后处理的流程和队列消息⼀样了。
注意,不管是队列消息,还是⾮队列消息,都是从USER32内核开始,转到了AfxWndProcBase(有时候不经过这⾥),再到AfxWndProc,所以可以认为AfxWndProc是消息传递与处理的起点!出来后,不管是队列消息,还是⾮队列消息,应该由Windosw系统发往各个窗⼝的消息处理函数(这个处理函数是DefWindowProc,这是很直觉的想法,⽽且传统的SDK程序确实是这样的,但是MFC程序⽐传统的SDK多了document/view,如果如果某个消息是做⽂档处理,那么就让这个消息直接流到document中去不是更好吗?所以才有了MFC命令传递机制、MFC消息映射的出现),但是为什么都统⼀到了AfxWndProc这⾥呢?这⾥⽤到了钩⼦技术。
对话框向主窗体传递消息,在视图中显示现举例说明对话框向主窗体传递消息,以及主窗体响应消息的过程。
我们拿单文档来说明,我们要实现下列功能:通过对话框,在文本框中输入字符串,在视图中显示刚才输入的字符串。
1、在应用程序向导中选择单个文档,然后完成。
我这里的项目名称为mybook2、在资源视图中,插入一对话框,对话框名称为dlg_wzm。
3、在刚才生成的对话框中插入一文本框,设置好相应的类和变量。
为确认按钮生成响应函数。
同时在mybook.cpp的BOOL CMyBookApp::InitInstance()函数中让该对话框启动,也就是加入CDlg_wzm dlg; dlg.DoModal();两行程序,当然在前面的要加入#include "dlg_wzm.h"。
(详细过程略)4、下面重点在于点击该对话框的确认按钮向主窗体发送消息。
要现定义一个消息名称。
在stdafx.h文件中加入一行:#define WM_MYMESSAGE WM_USER+1005、在CMainFrame的pulic申明中加入一变量CString wzmstr。
目的是为了保存对话框中的字符串的值。
在对话框的Onok()函数中:void CDlg_wzm::OnOK(){// TODO: Add extra validation herethis->UpdateData(true);CMainFrame* pWnd=(CMainFrame*)AfxGetMainWnd(); //得到父窗体的指针pWnd->wzmstr=this->m_input_edit;ASSERT(pWnd!=NULL);::SendMessage(pWnd->GetSafeHwnd(), WM_MYMESSAGE,0,0); //发送消息//注意WM_MYMESSAGE就是我们前面定义的消息。
//CDialog::OnOK();}6、下面我们看看主窗体怎么接受消息。
[工程科技]MFC的消息机制的实现原理和消息处理的过程下面几节将分析MFC的消息机制的实现原理和消息处理的过程。
为此,首先要分析ClassWizard实现消息映射的内幕,然后讨论MFC的窗口过程,分析MFC窗口过程是如何实现消息处理的。
1. 消息映射的定义和实现1. MFC处理的三类消息根据处理函数和处理过程的不同,MFC主要处理三类消息:, Windows消息,前缀以“WM_”打头,WM_COMMAND例外。
Windows消息直接送给MFC窗口过程处理,窗口过程调用对应的消息处理函数。
一般,由窗口对象来处理这类消息,也就是说,这类消息处理函数一般是MFC窗口类的成员函数。
, 控制通知消息,是控制子窗口送给父窗口的WM_COMMAND通知消息。
窗口过程调用对应的消息处理函数。
一般,由窗口对象来处理这类消息,也就是说,这类消息处理函数一般是MFC窗口类的成员函数。
需要指出的是,Win32使用新的WM_NOFITY来处理复杂的通知消息。
WM_COMMAND类型的通知消息仅仅能传递一个控制窗口句柄(lparam)、控制窗ID和通知代码(wparam)。
WM_NOTIFY能传递任意复杂的信息。
, 命令消息,这是来自菜单、工具条按钮、加速键等用户接口对象的WM_COMMAND通知消息,属于应用程序自己定义的消息。
通过消息映射机制,MFC框架把命令按一定的路径分发给多种类型的对象(具备消息处理能力)处理,如文档、窗口、应用程序、文档模板等对象。
能处理消息映射的类必须从CCmdTarget类派生。
在讨论了消息的分类之后,应该是讨论各类消息如何处理的时候了。
但是,要知道怎么处理消息,首先要知道如何映射消息。
1. MFC消息映射的实现方法MFC使用ClassWizard帮助实现消息映射,它在源码中添加一些消息映射的内容,并声明和实现消息处理函数。
现在来分析这些被添加的内容。
在类的定义(头文件)里,它增加了消息处理函数声明,并添加一行声明消息映射的宏DECLARE_MESSAGE_MAP。
MFC的消息反射机制1、消息反射解释: ⽗窗⼝将⼦窗⼝发给它的通知消息,⾸先反射回⼦窗⼝进⾏处理(即给⼦窗⼝⼀个机会,让⼦窗⼝处理此消息),这样通知消息就有机会能被⼦窗⼝⾃⾝进⾏处理。
2、MFC中引⼊消息反射的原因: 在Windows的消息处理中,⼦窗⼝的发给其⽗窗⼝的通知消息只能由其⽗窗⼝进⾏处理,这使得⼦窗⼝的⾃⾝能动性⼤⼤降低(你想,它连改变⾃⼰的背景⾊,处理⼀个⾃⾝滚动问题都要其⽗窗⼝来完成),为了解决这个问题,在MFC中引⼊了反射消息 “Reflect Message”的概念,进⾏消息反射,可以使得控制⼦窗⼝能够⾃⾏处理与⾃⾝相关的⼀些消息,增强了封装性,从⽽提⾼了控制⼦窗⼝的可重⽤性。
消息反射的处理流程(不考虑OLE控制)⼀、消息反射处理流程图: 1、⽗窗⼝收到控制⼦窗⼝发来的通知消息后,调⽤它的虚函数CWnd::OnNotify.CWnd::OnNotify()主体部分:{//此时,hWndCtrl,为发送窗⼝,即⼦窗⼝的窗⼝句柄if (ReflectLastMsg(hWndCtrl, pResult))return TRUE; // ⼦窗⼝已处理了此消息AFX_NOTIFY notify;notify.pResult = pResult;notify.pNMHDR = pNMHDR;return OnCmdMsg(nID, MAKELONG(nCode, WM_NOTIFY), ¬ify, NULL);} 分析:⾸先,调⽤ReflectLastMsg(hCtrlChildWnd,...)给⼦窗⼝⼀个⾃⾝处理的机会,将消息反射给⼦窗⼝处理,函数返回 TRUE,表明⼦窗⼝处理了此消息。
反之,表⽰⼦窗⼝未处理此消息,此时,调⽤OnCmdMsg(...)由⽗窗⼝进⾏通常的处理。
2、ReflectLastMsg中: 主要是调⽤发送窗⼝的SendChildNotifyLastMsg(...)。
消息映射的实现Windows消息概述Windows应用程序的输入由Windows系统以消息的形式发送给应用程序的窗口。
这些窗口通过窗口过程来接收和处理消息,然后把控制返还给Windows。
消息的分类队列消息和非队列消息从消息的发送途径上看,消息分两种:队列消息和非队列消息。
队列消息送到系统消息队列,然后到线程消息队列;非队列消息直接送给目的窗口过程。
这里,对消息队列阐述如下:Windows维护一个系统消息队列(System message queue),每个GUI线程有一个线程消息队列(Thread message queue)。
鼠标、键盘事件由鼠标或键盘驱动程序转换成输入消息并把消息放进系统消息队列,例如WM_MOUSEMOVE、WM_LBUTTONUP、WM_KEYDOWN、WM_CHAR等等。
Windows 每次从系统消息队列移走一个消息,确定它是送给哪个窗口的和这个窗口是由哪个线程创建的,然后,把它放进窗口创建线程的线程消息队列。
线程消息队列接收送给该线程所创建窗口的消息。
线程从消息队列取出消息,通过Windows把它送给适当的窗口过程来处理。
除了键盘、鼠标消息以外,队列消息还有WM_PAINT、WM_TIMER和WM_QUIT。
这些队列消息以外的绝大多数消息是非队列消息。
系统消息和应用程序消息从消息的来源来看,可以分为:系统定义的消息和应用程序定义的消息。
系统消息ID的范围是从0到WM_USER-1,或0X80000到0XBFFFF;应用程序消息从WM_USER(0X0400)到0X7FFF,或0XC000到0XFFFF;WM_USER到0X7FFF范围的消息由应用程序自己使用;0XC000到0XFFFF范围的消息用来和其他应用程序通信,为了ID的唯一性,使用::RegisterWindowMessage来得到该范围的消息ID。
消息结构和消息处理消息的结构为了从消息队列获取消息信息,需要使用MSG结构。
MFC框架原理以及消息运行机制MFC(Microsoft Foundation Classes)是微软公司开发的一种基于面向对象的软件框架,用于开发Windows平台的应用程序。
MFC框架的主要原理是消息驱动机制。
消息驱动机制是一种事件驱动的编程模型,即程序中的操作通过消息的方式进行通知和处理。
MFC框架使用消息循环来处理应用程序的消息。
消息循环是一个无限循环,在每一次循环中,应用程序会不断地查询并处理消息队列中的消息。
消息的产生和处理是由Windows操作系统来完成的。
当发生一些特定的事件(例如鼠标点击、键盘输入等)时,Windows操作系统会将相应的消息放入消息队列中。
MFC框架通过调用Windows API函数来获取并处理消息队列中的消息。
1. 消息的类型(message type):表示消息的分类,例如鼠标消息、键盘消息等。
2. 消息的处理函数(message handler):用于处理特定类型的消息,根据消息类型的不同,消息处理函数也会有所不同。
3. 消息的参数(message parameters):包含了消息的具体信息,例如鼠标点击的坐标、键盘输入的字符等。
在MFC框架中,每个窗口控件都有一个与之相关联的消息处理函数。
当窗口控件接收到相应的消息时,该消息处理函数会被自动调用,从而完成消息的处理逻辑。
MFC框架中的消息机制是通过C++语言中的虚函数机制来实现的。
在MFC框架中,每个窗口对象都继承自CWnd类,并重载了CWnd类中的虚函数。
在消息循环中,通过调用窗口对象的成员函数来处理特定类型的消息。
MFC框架还提供了一些宏和宏函数来简化消息处理的代码。
例如,通过DECLARE_MESSAGE_MAP宏可以声明一个消息映射表,其中定义了窗口控件与消息处理函数之间的映射关系。
通过ON_MESSAGE宏可以将消息与消息处理函数进行绑定。
总结起来,MFC框架的消息机制是一种事件驱动的编程模型。
MFC框架原理以及消息运行机制(1)Windows程序内部运行机制1,windows程序设计是种事件驱动方式的程序设计,主要基于消息的。
当用户需要完成某种功能时,需要调用OS某种支持,然后OS将用户的需要包装成消息,并投入到消息队列中,最后应用程序从消息队列中取走消息并进行响应。
2,消息结构:typedef struct tagMSG { // msgHWND hwnd; //接收消息的窗口句柄。
和哪个窗口相关联。
UINT message; //消息标识。
消息本身是什么。
WPARAM wParam; //消息的附加信息。
具体取决于消息本身。
LPARAM lParam;DWORD time; //消息投递时间。
POINT pt; //消息投递时,光标在屏幕上的位置。
} MSG;3,消息队列:每个应用程序OS都为它建立一个消息队列,消息队列是个先进先出的缓冲区,其中每个元素都是一个消息,OS将生成的每个消息按先后顺序放进消息队列中,应用程序总是取走当前消息队列中的第一条消息,应用程序取走消息后便知道用户的操作和程序的状态,然后对其处理即消息响应,消息响应通过编码实现。
4,使用VC编程除了良好的C基础外还需要掌握两方面:一,消息本身。
不同消息所代表的用户操作和应用程序的状态。
二,对于某个特定的消息来说,要让OS执行某个特定的功能去响应消息。
5,Window程序入口:int WINAPI WinMain(HINSTANCE hInstance, // 当前事例句柄。
HINSTANCE hPrevInstance, // 先前事例句柄。
LPSTR lpCmdLine, // 命令行指针int nCmdShow // (窗口)显示的状态);说明:WinMain函数是Windows程序入口点函数,由OS调用,当OS启动应用程序的时候,winmain函数的参数由OS传递的。
6,创建一个完整的窗口需要经过下面四个操作步骤:一,设计一个窗口类;如:WNDCLASS wndcls;二,注册窗口类;如:RegisterClass(&wndcls);三,创建窗口;如:CreateWindow(),CreateWindowEX();四,显示及更新窗口。
mfc消息响应机制MFC消息响应机制MFC(Microsoft Foundation Class)是微软公司为开发Windows应用程序而提供的一组C++类库。
在MFC中,消息响应机制是一种重要的编程方式,用于处理用户与应用程序之间的交互。
本文将详细介绍MFC消息响应机制的原理和使用方法。
一、消息处理函数在MFC中,消息处理函数是用于响应消息的函数。
当用户与应用程序进行交互时,系统会产生相应的消息,然后通过消息映射表找到对应的消息处理函数进行处理。
消息处理函数是类成员函数,其原型通常为:afx_msg LRESULT OnMessage(WPARAM wParam, LPARAM lParam);其中,afx_msg是MFC宏定义,LRESULT是消息处理函数的返回值类型,OnMessage是函数名,WPARAM和LPARAM是消息参数,用于传递消息的附加信息。
二、消息映射表消息映射表是一个包含消息处理函数与消息ID之间对应关系的表格。
在MFC应用程序的消息映射表中,每个消息ID都与一个消息处理函数相对应。
当收到某个消息时,系统会根据消息ID查找对应的消息处理函数,并调用该函数进行处理。
消息映射表通常定义在类的声明中,格式如下:BEGIN_MESSAGE_MAP(CMyClass, CBaseClass)ON_MESSAGE(messageID, memberFxn)// more message mappings...END_MESSAGE_MAP()其中,CMyClass是消息处理类的名称,CBaseClass是消息处理类的基类,messageID是消息ID,memberFxn是与该消息ID对应的消息处理函数。
三、消息处理函数的实现消息处理函数的实现步骤如下:1. 在类的声明中定义消息处理函数的原型。
2. 在类的实现文件中,使用宏定义IMPLEMENT_DYNAMIC或IMPLEMENT_DYNCREATE来实现运行时类型信息。
mfc消息映射机制MFC消息映射机制是MFC框架中的一个重要机制,它是实现消息响应的关键。
在MFC中,消息是指Windows操作系统中的消息,例如鼠标点击、键盘输入、窗口大小改变等。
MFC消息映射机制是将消息与相应的处理函数关联起来的过程,使得程序能够响应用户的操作。
MFC消息映射机制的实现依赖于消息映射表。
消息映射表是一个数组,其中每个元素都是一个消息映射结构体。
消息映射结构体包含了消息的类型、消息的ID、消息的处理函数等信息。
当程序接收到一个消息时,MFC会根据消息的类型和ID在消息映射表中查找相应的处理函数,并将消息传递给该函数进行处理。
MFC消息映射机制的优点在于它能够将消息处理函数与消息的类型和ID进行关联,使得程序的代码更加清晰、易于维护。
此外,MFC 还提供了一些宏定义,例如DECLARE_MESSAGE_MAP和BEGIN_MESSAGE_MAP,使得消息映射表的定义更加简洁、易于理解。
MFC消息映射机制的使用方法如下:1. 在类的头文件中声明消息映射表,使用DECLARE_MESSAGE_MAP宏定义。
2. 在类的实现文件中定义消息映射表,使用BEGIN_MESSAGE_MAP和END_MESSAGE_MAP宏定义。
3. 在消息映射表中添加消息映射结构体,使用ON_MESSAGE、ON_COMMAND等宏定义。
4. 在消息处理函数中编写相应的代码,处理消息。
例如,以下代码实现了一个响应鼠标点击消息的处理函数:afx_msg LRESULT CMyWnd::OnLButtonDown(WPARAM wParam, LPARAM lParam){// 处理鼠标点击消息return 0;}BEGIN_MESSAGE_MAP(CMyWnd, CWnd)ON_WM_LBUTTONDOWN()END_MESSAGE_MAP()在上述代码中,CMyWnd是一个继承自CWnd的窗口类,OnLButtonDown是处理鼠标点击消息的函数。
MFC消息机制理解消息循环理解消息循环经及Windows程序整个的消息发送机制对于任何Windows程序都是非常重要也是最根本的.现在我们已经尝试了如何处理消息循环,我们有必要对这整个过程再深入一些.因为假如你不能理解消息循环具体是怎么一回事的话,那么以后你就会越来越糊涂.什么是消息?消息就是一个整型值.如果你查看一下你的头文件的话(当你去调查API的工作机制的话,这是一个非常好的也是大多数人都有的习惯)你就发现下面这些东西:#define WM_INITDIALOG 0x0110#define WM_COMMAND 0x0111#define WM_LBUTTONDOWN 0x0201...等等. 消息是用于底层这个层次上,窗口之间的通信.假如你希望窗口或是控件(其实也是一个特殊的窗口)做某个事情的话,你就发送给它一个消息. 假如有另一个窗口希望你做某个事情的话,它也送一个消息给你.假如有比如像用户敲击键盘,移动鼠标,点击按钮之类的事件发生的话,那么这些消息就由系统发送给那些受到影响的窗口.假如你的窗口是其中的一个的话,你就要处理这个消息,对这个消息做出相应的反应.每个窗口消息都有两个参数,wParam和lParam.最初wParam是16位的,lParam是32位,但是在WIN32中,它们都是32位的.不是每条消息都用到了这些参数,而且不同的消息对它们的使用是不同的.举个例子,WM_CLOSE消息就两个参数都没有用到,你可以把两个都忽略.WM_COMMAND消息就两个参数都用上了,wParam参数包含了两个值,一个是HIWORD(wParam),它是消息的通知码(如果可用的话),另一个是LOWORD(wParam),它是发送消息的控件或是菜单的标识符.lParam是发送消息的控件的HWND(HWND是一种数据类型,也就是窗口的句柄.控件的实质也是一个窗口,因此它也有句柄),当这个消息不是来自于一个控件或是窗口,lParam 的值就是NULL,.(比如当消息是由菜单产生时,lParam就是NULL)HIWORD()和LOWORD()是由windows定义的宏,它们的作用分别是取得一个32位的值的高两个字节(高字)和低两个字节(低字) ,(相当于是将一个双字分别去和0XFFFF0000以及0X0000FFFF作与运算,再分别向右和向左作相应16位位移后得到的结果) 在WIN32中,一个字是16位,一个双字也就是32位了.发送一个消息,你可以用函数PostMessage()或函数SendMessage(). 函数PostMessage()的作用是将消息送到消息队列中,然后立即返回.这意味着,一旦你调用了函数PostMessage()后,那么这个消息有没有得到处理就不一定了.函数 SendMessage()是将消息直接发送给窗口,然后要一直等窗口对这个消息的处理完成了,这个函数才会返回了.假如我们想关闭一个窗口的话,我们可以发送给这个窗口一个WM_CLOSE的消息,比如像这样做: PostMessage(hwnd, WM_CLOSE, 0, 0),那么这个你去点击窗口上方的关闭按钮的效果是一样的.请注意wParam 和 lParam 都是0.原因就正如我们已经谈到的那样,WM_CLOSE消息没有用到这两个参数对话框一旦你开始使用对话框,为了和对话框进行通信,你就会需要发送消息给对话框上的控件.为了做到这一点,你要么用函数GetDlgItem()加上控件的标识符来获得控件的句柄,然后呢,再用函数SendMessage();要么你就用函数SendDlgItemMessage(),这个函数把以上两步结合起来了. 你给这个函数一个窗口的句柄以及子窗口(也就是这个窗口上的控件)的标识符,你就可以获取标识符所对应的子窗口的句柄,接下来就是给子窗口发送消息了.函数SendDlgItemMessage()以及类似的API比如GetDlgItemMessage()可以工作在所有的窗口上,不仅仅是对话框.什么是消息队列让我们假设当你在忙于处理WM_PAINT消息时,突然用户在键盘上敲了一串键.这会发生什么事情呢?你到底是应该停下你的画画,对键盘作出响应,还是对敲下的这些键置之不理呢?显然两种方式都是不合理的.因此我们有了消息队列.当消息被送入消息队列后,你一个个的对它们进行处理,处理一个消息,就移除一个消息.(当然先来的消息先得到处理)这样可以确保存你不会错过哪条消息.当你对某条消息进行处理时,其它消息就等待在队列中,直到你来处理它们.什么是消息循环while(GetMessage(&Msg, NULL, 0, 0) > 0){TranslateMessage(&Msg);DispatchMessage(&Msg);}消息循环调用函数GetMessage(),这个函数它会去察看你的消息队列.假如消息队列是空的(也就是没有任何消息),那么我们的程序就停在那里,等待消息的到来.当某一个导致消息被送到消息队列的事件发生时(举个例子,系统注册的鼠标点击,比如点击关闭按钮),函数GetMessage()就会返回一个正值,表明这里有一个需要得到处理的消息,而且这个消息的值被赋给了我们传递给函数GetMessage()的参数Msg,这个结构体中.如果这个消息是WM_QUIT,那么函数GetMessage()的返回值就是0.如果有错误产生的话,那么返回值就是负值.我们得到消息后(消息在结构体变量Msg中),接下来就可以把消息传递给函数TranslateMessage().这个函数对消息又多做了一步处理,它将虚拟键的消息翻译成字符消息.这一步事实上是可选的,但是如果没有这一步的话,某些事情就不会发生了.一旦这些做完以后,我们把消息传递给函数DispatchMessage(). 函数DispatchMessage()所做的事情就是检查消息是发送哪个窗口的,然后再去查看这个窗口的窗口过程.然后呢,它就会调用这个过程,将参数: 窗口的句柄,消息以及wParam和lParam,送给窗口过程.在你的窗口过程中,你就会检查消息和它的参数,然后根据消息和它的参数,你就可以做你想做的事情了!你不用对所有的消息都进行处理,对于你不想亲自去处理的消息,你就调用函数DefWindowProc()就是了.它会为你对那些没有处理的消息做一些默认的处理.(一般情况下,这个函数其实什么也没有做,也就是相当于将你没有处理的消息忽略掉了,等于那些消息从没有产生过,只是从消息队列中过了一遍.)一旦你做完对消息的处理之后,你的窗口过程就返回了,函数DispatchMessage()也返回了.我们又回到了整个循环的的开始.对于WINDOWS程序,这里有一个非常重要的概念.那就是你的窗口过程不是由系统调用的,事实上是你自己通过调用函数DispatchMessage()间接地调用的. 假如你想自己来调用窗口过程的话(不通过函数DispatchMessage()),你可以把接受消息的窗口,它的窗口句柄作为参数传递给函数GetWindowLong()(函数GetWindowLong()通过设置最后一个参数为GWL_WNDPROC,可以获得窗口过程的地址),这样直接得到窗口的窗口过程,然后再直接执行这个窗口过程!while(GetMessage(&Msg, NULL, 0, 0) > 0){WNDPROC fWndProc = (WNDPROC)GetWindowLong(Msg.hwnd, GWL_WNDPROC);fWndProc(Msg.hwnd, Msg.message, Msg.wParam, Msg.lParam);}我在前面的例程序中尝试了这种作法,而且它确实是可行的.但是这里有许多事情,比如Unicode/ANSI的转换,调用定时器返回等等就不行了,所以呢,你可以试一试,但是不要用在实际的应用中.请注意,我们用函数GetWindowLong()获得和这个窗口相关的窗口过程.为什么不直接调用我们的WndProc()呢?是这样的,我们的消息循环负责我们程序中的所有的窗口,这些窗口包括了比如按钮,列表框之类,它们都有各自的窗口过程.因此我们要确定对不同的窗口我们调用的是相应的窗口过程.因为多个窗口都可以使用相同的窗口过程,第一个参数(窗口的句柄)就用于告诉窗口过程,消息是送给哪个窗口的.正如你所看到的那样,你的应用程序花费了绝大多数的时间在消息循环中往往返返.你非常惬意地发送一条消息给运行得正开心的窗口处理.但是当你想你的窗口退出时,你该怎么做呢?因为我们用的是一个while()循环,假如函数GetMessage()的返回值是0(OK,0),这个循环就结束了.我们也就到达我们的WinMain()的终点了,从而退出程序.这些正是函数PostQuitMessage()完成的事情.它将WM_QUIT消息送到了队列中,和返回一个正值不同,函数GetMessage()填充了Msg结构体,然后返回一个0.在这里Msg结构体的成员wParam包含了你传递给函数PostQuitMessage()的值.你要么将这个值忽略掉,要么把它作为W inMain()的返回值.也就是这个过程终止时的退出码.重要之处: 函数GetMessage()将会返回-1假如它遇到了错误的话.你要记住这一点,不然的话,在某些时候你就会被它拖住的....即使这个函数是定义成返回一个布尔值,它也可以返回除了真或假以外的其它值,因为BOOL布尔型被定义成UINT(无符号整型).下面是例程序代码,它看起来可以运行,但是在某些情况下不能正确处理.while(GetMessage(&Msg, NULL, 0, 0))while(GetMessage(&Msg, NULL, 0, 0) != 0)while(GetMessage(&Msg, NULL, 0, 0) == TRUE)上面的全是错的!你也许注意到了在整个教程中我用的都是第一个,正如我所提到的那样,只要函数GetMessage()的调用不失败的话(前提是你的所有代码都是正确的),它还是可以工作得很好.然而我有一点没有考虑到,那就是当你看到我写的这些文字的时候,你的代码可能在绝大多数的情况下都有错误.还有一点就是函数GetMessage()本身也可能在某些情况下调用失败:) 我会全部检查一遍并且纠正这个错误,但是如果我漏掉了一些的话,就原谅我.while(GetMessage(&Msg, NULL, 0, 0) > 0)上面这个就是对的.要取得相同效果的代码也应该总是这个样子的.我希望你现在对窗口的消息循环有了一个更好的理解,假如不是这样的话,不要灰心,不要害怕,一旦你使用它们一段时间后,所有的事情都会明白的.。
MFC的类层次结构与运行机制MFC的类层次结构如图所示(子类指向父类):其中:CObject:是MFC提供的绝大多数类的基类。
该类完成动态空间的分配与回收,支持一般的诊断、出错信息处理和文档序列化等。
CCmdTarget:主要负责将系统事件(消息)和窗口事件(消息)发送给响应这些事件的对象,完成消息发送、等待和派遣调度等工作,实现应用程序的对象之间的协调运行。
CWinApp:是应用程序的主线程类,它是从CWinThread类派生而来的。
CWinThread类用来完成对线程的控制,包括线程的创建、运行、终止和挂起等。
CDocument:是文档类,包含了应用程序在运行期间所用到的数据。
CWnd:是一个通用的窗口类,用来提供Windows中的所有通用特性、对话框和控件。
CFrameWnd是从CWnd类继承来的,并实现了标准的框架应用程序。
CDialog类用来控制对话框窗口。
CView:用于让用户通过窗口来访问文档。
CMDIFrameWnd和CMDIChildWnd:分别用于多文档应用程序的主框架窗口和文档子窗口的显示和管理。
CMiniFrameWnd类是一种简化的框架窗口,它没有最大化和最小化窗口按钮,也没有窗口系统菜单,一般很少用到它。
MFC运行机制在程序中,当定义一个类对象时,它会自动调用相应的构造函数。
所谓"类对象",就是用该类定义的"变量",这个"变量"又称为类的一个实例。
例如,theApp就是类CSimpApp的一个对象。
MFC正是利用类的这种"自动调用相应的构造函数"特性,使得WinMain()函数的调用变成了应用程序框架内部的调用,所以我们在代码中看不到每个Windows程序所必须有的WinMain()函数。
当应用程序运行到"CSimpApp theApp;"时,系统就会先调用基类CWinApp构造函数,进行一系列的内部初始化操作,然后自动调用CSimpApp的虚函数InitInstance(),该函数会进一步调用相应的函数来完成主窗口的构造和显示工作。