MFC 消息映射(转载)

    技术2022-05-11  143

    初学MFC,还有很多内部机理并不太了解,还是自己给自己打气,将每天的心得记录下来.   消息的传递与发送是Windows应用程序的核心所在,任何事件的触发与响应均要通过消息的作用才能得以完成。在SDK编程中,对消息的获取与分发主要是通过消息循环来完成的,而在MFC编程中则是通过采取消息映射的方式对其进行处理的。相比而言,这样的处理方式要简单许多,这也是符合面向对象编程中尽可能隐含实现细节的原则。 一、消息的类别 1、窗口消息:即标准的WINDOWS消息,它与创建窗口,绘制窗口,移动窗口和销毁窗口等操作窗口的动                  作有关,这类消息是以WM_为前缀,不过WM_COMMAND例外.       例如: WM_CREATE  -- 创建窗口后立即发出的一个消息,用于指示窗口初始化            WM_CLOSE    -- 通知窗口要将它关闭            WM_PAINT    -- 通知窗口绘制自身            WM_LBUTTONDOWN -- 通知窗口在它的客户区中按下了鼠标左键                   WM_MOVE、WM_QUIT等等.. 其他的可查看微软发布的技术参考资料 -- 窗口消息的类别。          2、命令消息:以WM_COMMAND为消息名.在消息中含有命令的标志符ID(wParam的低16位;而高16位                   为0L),以区分具体的命令.由菜单,工具栏等命令接口对象产生.          注意:              凡是从基类CCmdTarget派生的类都能处理命令消息              命令消息的lParam为0L,区分于控件消息      3、控件消息:控件通知消息也是以WM_COMMAND为消息名.由编辑框,列表框,子窗口发送给父窗口的                  通知消息.       目前控件消息有3种格式:          仿窗口消息格式 -- 如:WM_HSCROLL 或者 WM_VSCROLL : 滚动控件通知父窗口沿水平或者垂直                                                                                     方向滚动窗口                             WM_PARENTNOTIFY:  通知控件窗口建立或销毁其他事件                             WM_CTLCOLOR :    通知父窗口要改变控件的颜色                             WM_DRAWITEM,WM_DELETEITEM,WM_MEASUREITEM,WM_CHARTOITEM:                              通知父窗口将绘制控件自身窗口                 仿命令消息格式 -- messge为WM_COMMAND;wParam底16位为控件ID,高16位为消息通知码;                              lParam为控件窗口句柄          单独控件消息格式 -- message为WM_NOTIFY;wParam为控件ID;lParam为指向NMHDR的指针          NMHDR 定义如下:          typedef struct tagNMHDR{            HWND hwndFrom ;  -- 发出控件消息的控件窗口的句柄      UINT idFrom ;         -- 控件的资源ID      UINT code ;            -- 控件消息的消息通知码EX_XXX     }NMHDR ;                二、命令的分解和组装:由于命令消息与控件消息的wParam的高16位和低16位分别表示不同的含义,       因此需要分解或组装工作       分解:     HIGHWORD(wParam)  -- 获得wParam 的高16位     LOWWORD(wParam)  -- 获得wParam 的低16位         组装:     命令消息组装 -- 如: (WM_COMMAND,MAKEWPARAM(ID_FILE_OPEN,0),0L)     控件消息组装 -- 如: (WM_COMMAND,MAKEWPARAM(IDOK,BN_CLICKED),hwnd)     三、SendMessage和PostMessage函数     1、SendMessage和PostMessage函数只能给窗口发消息,也就是说只能给CWnd类及其派生类对象          对应的窗口发消息。          语法:       SendMessage(HWND hwnd,UINT message,WPARAM wParam ,LPARAM lParam ) -- 发送       int res = ::SendMessage(hwnd,message,wParam,lParam)             PostMessage(HWND hwnd,UINT message ,WPARAM wParam ,LPARAM lParam ) -- 寄送       int res = ::PostMessage(hwnd,message,wParam,lParam)            通常鼠标和键盘消息采用寄送方式,而其他消息采用发送方式           2、使用MFC发送或者寄送消息            int res = pWnd->SendMessage(UINT message,WPARAM wParam,LPARAM lParam) -- pWnd 为接收消息的目标窗口对象      int res = pWnd->PostMessage(UINT message,WPARAM wParam,LPARAM lParam) -- 同上           3、检索消息队列中的消息PeekMessage 和 GetMessage          语法:       BOOL res = ::PeekMessage(LPMSG lpMsg,HWND hwnd,UINT wMsgFilterMin,UINT wMsgFilterMax,UINT wRemoveMsg)       BOOL res = ::GetMessage(LPMSG lpMsg ,HWND hwnd,UINT wMsgFilterMin,UINT wMsgFilterMax)              lpMsg -- MSG结构变量的指针       hwnd  -- 要截获消息的窗口       wMsgFilterMin,wMsgFilterMax -- 与lpMsg相对应,表示查看消息的范围,如果它们分别为0,0,则表示将查看所有的消息       wRemoveMsg -- 取值为 PM_REMOVE时,PeekMessage函数看完后,将删除消息.取值为 PM_NOREMOVE时,PeekMessage函数看完后,返回消息的一个备份,            不删除队列中的消息      功能:       PeekMessage -- 只是窥看一下消息队列,查询一下指定消息是否在在消息队列中;看完后,是否从队列中删除该消息,取决于标志wRemoveMsg       GetMessage  -- 当没有一个新消息到达队列前,该函数一直阻塞,一旦有新消息时,则从队列中删除该消息,并返回此消息.                      四、消息映射表 1、为了在类中加入静态消息映射表,MFC是通过一对宏来实现的 在类声明文件.h中的声明: DECLARE_MESSAGE_MAP() -- 此句通常在类声明的最后 在类的实现文件.cpp中: BEGIN_MESSAGE_MAP(类名,父类名)     ………    消息映射入口项.     ……… END_MESSAGE_MAP( ) 2、命令消息映射入口项是一个ON_COMMAND的宏.比如文件菜单下的"打开…"菜单(ID值为ID_FILE_OPEN)对应的消息映射入口项为:   ON_COMMAND(ID_FILE_NEW,OnFileOpen) 3、在类定义中加入消息处理函数的函数原型(函数声明.h)     afx_msg OnFileOpen();// 函数原型     作为约定.消息处理函数一般以On打头 MFC还提供了其他一些用于消息映射的宏,详情可参见下表: 宏名      说明 DECLARE_MESSAGE_MAP  -- 在头文件声明源文件中所含有的消息映射 BEGIN_MESSAGE_MAP  -- 标记源文件消息映射的开始 END_MESSAGE_MAP  -- 标记源文件消息映射的结束 ON_COMMAND  -- 将特定命令的处理委派给类的一个成员函数 ON_CONTROL   -- 映射一个函数到一个定制控制通知消息。其中,定制控制通知消息是从一个控制发送到其父窗口的消息。 ON_CONTROL_RANGE  -- 将一个控制ID的范围映射到一个消息处理函数 ON_CONTROL_REFLECT  -- 映射一个由父窗口反射回控制的通知消息 ON_MESSAGE   -- 将一个用户自定义消息映射到一消息处理函数 ON_NOTIFY    -- 映射一个控制消息到一个函数 ON_NOTIFY_RANGE  -- 映射一个控制ID范围内的控制消息到一个函数 ON_NOTIFY_EX   -- 映射一个控制消息到一个函数,该成员函数返回FALSE或TRUE来表明通知是否应被传送到下一个对象以进行其他反应。 ON_NOTIFY_EX_RANGE  -- 映射一个控制ID范围内的控制消息到一个函数,该成员函数返回FALSE或TRUE来表明通知是否应被传送到下一个对象以进行其他反应 ON_NOTIFY_REFLECT  -- 映射一个控制消息到一个函数。该消息将会被控制的父窗口反射回来。 ON_REGISTERED_MESSAGE  -- 映射一个唯一的消息到一个将要处理该注册消息的函数上。该消息是由RegisterWindowMessage()函数注册的。 ON_UPDATE_COMMAND_UI   -- 映射一个函数来处理一个用户接口更新命令消息 ON_UPDATE_COMMAND_UI_RANGE -- 映射一个命令ID的范围到一个更新消息处理函数 五、MFC程序处理消息的路径 1、处理窗口消息     MFC对窗口消息的处理是最直观的,窗口消息只有窗口类能够接收和处理,在MFC应用程序框架的基本类中,只有框架类和视图是窗口类         当消息被BOOL CWnd::OnWndMsg(UINT message,WPARAM wParam,LPARAM lParam,LRESULT *pResult)函数判别为窗口消息时,OnWndMsg(...)将直接对消息所属的窗口类的消息     映射表进行搜索,找到匹配的消息处理函数后便执行它,否则继续搜索基类。若仍未找到则把消息交给默认处理函数LRESULT DefWindowProc(...)处理.     2、处理命令消息    理论上所有从基类CCmdTarget类派生的类均可处理命令消息,但是MFC应用程序框架对命令消息的处理作出了一个特别的顺序规定,它将依次检查MFC应用程序基本类的消息映射    表,以便判别各类是否定义了命令消息处理函数       命令传递路线:    命令--->视图类--->文档类--->框架窗口类--->应用程序类    3、处理控件消息    主框架窗口类的OnWndMsg(...)判别消息类型为WM_NOTIFY后,将调用该类的虚函数BOOL OnNotify(WPARAM wParam,LPARAM lParam,LRESULT &pResult).                 OnWndMsg(...)                 |                 |                 v          OnNotify(...)                 |                 |                 v       <  控件窗口类能    YES             处理该消息   > -----> 控件窗口类处理消息                 | NO                 v      控件的父窗口类::OnWndMsg(...)                六、自定义消息处理 1、自定义静态窗口消息    系统允许用户把自定义窗口消息映射为范围在WM_USER + 1 到 WM_USER + ox7fff       需做工作:    1) 在类的实现文件中定义消息       #define WM_SAYHELLO WM_USER+100          2) 在类的声明消息处理函数(假定为CMyView类)       class CMyView:public CView       {        ...        protected:        ...        afx_msg LRESULT OnSayHello(WPARAM,LPARAM);        DECLARE_MESSAGE_MAP()       }          3) 在类的消息映射表中加入映射项      BEGIN_MESSAGE_MAP(CMyView,CView)      ...      ON_MESSAGE(WM_SAYHELLO,OnSayHello)      ...      END_MESSAGE_MAP()    4) 在类的实现文件中实现消息处理函数      LRESULT CMyView::OnSayHello(WPARAM wParam,LPARAM lParam)      {       AfxMessageBox("Hello.I am in CMyView");      }       5) 给窗口发送消息      pView->SendMessage(WM_SAYHELLO,0L,0L); 或 pView->PostMessage(WM_SAYHELLO,0L,0L);      2、自定义动态窗口消息      1) 定义并注册消息(.cpp)       #define MESSAGE_NAME "2005-07-24-THIS-IS-A-MESSAGE-TEST"       UINT WM_MYSAYHELLO = ::RegisterWndMessage(MESSAGE_NAME);          2) 在类中声明消息处理函数(假定为CMyView)       class CMyView:public CView       {        ...        protected:        ...        afx_msg LRESULT OnSayHello(WPARAM,LPARAM);        DECLARE_MESSAGE_MAP()       }         3) 在类的消息映射表中加入映射项       ON_REGISTERED_MESSAGE(WM_MYSAYHELLO,OnSayHello)          4) 在类实现文件中实现消息处理函数       LRESULT  CMyView::OnSayHello(WPARAM wParam,LPARAM lParam)       {         AfxMessageBox("Hello,I am in CMyView.");       }          5) 给窗口发送消息       pView->SendMessage(WM_SAYHELLO,0L,0L); 或 pView->PostMessage(WM_SAYHELLO,0L,0L);

    最新回复(0)