MFC 消息映射(转载)

初学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);
阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页