zoukankan      html  css  js  c++  java
  • 3.MFC基础(三)消息映射

    一、消息映射机制

     1.消息映射机制的使用

      (1)类必须派生自CCmdTarget

      (2)类内必须添加声明宏:DECLARE_MESSAGE_MAP( )

      (3)类外必须添加实现宏:BEGIN_MESSAGE_MAP( theClass, baseClass )

                                  END_MESSAGE_MAP( )

     2.消息映射机制的实现

      (1)数据结构    

          struct  AFX_MSGMAP_ENTRY
          {
            UINT           nMessage;   // 消息ID
            UINT           nCode;       // 控件通知码(只有控件的WM_COMMAND消息有通知码)
            UINT           nID;           // 命令ID、控件ID
            UINT           nLastID;     // 最后一个控件ID
            UINT_PTR    nSig;         // 消息处理函数类型
            AFX_PMSG   pfn;          // 消息处理函数的指针(地址)
          };    

          struct AFX_MSGMAP
          {
            const AFX_MSGMAP* (PASCAL* pfnGetBaseMap)( );
            const AFX_MSGMAP_ENTRY* lpEntries;
          };

      (2)宏展开的代码

         见代码

      (3)宏展开各部分的作用

          _messageEntries[ ] - 静态数组

           数组中每个元素保存了消息ID和处理消息的函数地址等

         messageMap - 静态变量

           保存父类静态变量地址(负责连接链表)

           保存了本类静态数组首地址

         GetMessageMap( )

           获取本类静态变量地址(获取链表头结点)

      (4)关系

         GetMessageMap( )

            |->CMyFrameWnd::messageMap

                    |->&CMyFrameWnd::_messageEntries[ ]

                                     |->消息ID ... 处理函数

                    |->&CFrameWnd::messageMap

                          |->&CFrameWnd::_messageEntries[ ]

                                         |->消息ID ... 处理函数

                          |->&CWnd::messageMap

                                |->&CWnd::_messageEntries[ ]

                                        |->消息ID ... 处理函数

                                |->&CCmdTarget::messageMap

                                           |->&CCmdTarget::_messageEntries[ ]

                                                                          |->消息ID ... 处理函数

                                           |->NULL  

    三、执行过程

     1.获取和窗口句柄绑定的框架类对象pFrame

     2.利用pFrame调用宏展开的虚函数GetMessageMap获取本类静态变量地址(链表头结点)pMessageMap

     3.利用pMessageMap(静态变量)的第二个成员获取相应类的静态数组并到数组中匹配查找消息ID和对应的处理函数

      如果找到,执行5

     4.如果没找,用pMessageMap的第一个成员获取父类静态变量地址,如果为NULL,结束查找;如果不为NULL,执行3

     5.用找到的数组元素的第六个成员保存的函数地址并调用,完成消息处理

      伪代码:

      //以WM_CREATE消息为例(同时注意WM_COMMAND / WM_PAINT)

      AfxWndProc( HWND  hWnd, UINT  nMsg, WPARAM  wParam, LPARAM  lParam )

      {

        CWnd*  pWnd  =  CWnd::FromHandlePermanent( hWnd );  //获取和窗口句柄绑定的框架类对象pFrame

        return  AfxCallWndProc( pWnd,  hWnd,  nMsg,  wParam,  lParam )  //参数的pWnd就是pFrame

        {

          lResult  =  pWnd->WindowProc( nMsg,  wParam,  lParam )  //函数内部this为pFrame

          {

            LRESULT  lResult  =  0;

            OnWndMsg( message,  wParam, lParam,  &lResult )  //函数内部this为pFrame

            {

              union MessageMapFunctions  mmf;

              AFX_MSGMAP*  pMessageMap  =  GetMessageMap( )  //获得链表头结点

              {

                return GetThisMessageMap( );  //返回链表头结点地址

              }

              AFX_MSGMAP_ENTRY*  lpEntry;

              //遍历链表

              for (  ; pMessageMap->pfnGetBaseMap != NULL; pMessageMap = ( *pMessageMap->pfnGetBaseMap)( ) )

              {        

                lpEntry = AfxFindMessageEntry( pMessageMap->lpEntries, message, 0, 0 ) );

                if  ( lpEntry  !=  NULL )

                {

                  goto  LDispatch;  //找到跳出for循环

                }

              }

              LDispatch:

                mmf.pfn  =  lpEntry->pfn;  //将OnCreate保存到联合体的所有成员中

                switch( lpEntry->nSig )

                {

                  case  AfxSig_l_w_l:
                    lResult  =  ( this->*mmf.pfn_l_w_l )( wParam, lParam );
                    break;

                }

            }

          }

        }  

      }

     相关代码: 

    #include "stdafx.h"
    #include "T10_MFCMsg.h"
    
    class CMyFrameWnd : public CFrameWnd
    {
        DECLARE_MESSAGE_MAP()
    /*
    protected:
        static const AFX_MSGMAP* PASCAL GetThisMessageMap();
        virtual const AFX_MSGMAP* GetMessageMap() const;
    */
    public:
        LRESULT OnCreate(WPARAM wParam, LPARAM lParam);
        LRESULT OnPaint(WPARAM wParam, LPARAM lParam);
        LRESULT OnMouseMove(WPARAM wParam, LPARAM lParam);
    private:
        int m_x;
        int m_y;
    public:
        CMyFrameWnd();
    };
    
    BEGIN_MESSAGE_MAP( CMyFrameWnd, CFrameWnd )
        ON_MESSAGE(WM_CREATE, OnCreate)
        ON_MESSAGE(WM_PAINT, OnPaint)
        ON_MESSAGE(WM_MOUSEMOVE, OnMouseMove)
    END_MESSAGE_MAP()
    
    /*
    const AFX_MSGMAP* CMyFrameWnd::GetMessageMap() const
    {
        return GetThisMessageMap();
    }
    const AFX_MSGMAP* PASCAL CMyFrameWnd::GetThisMessageMap()
    {
        typedef CMyFrameWnd ThisClass;
        typedef CFrameWnd TheBaseClass;
        static const AFX_MSGMAP_ENTRY _messageEntries[] =
        {
            { WM_CREATE, 0, 0, 0, AfxSig_lwl,
            (AFX_PMSG)(AFX_PMSGW)
            (static_cast<LRESULT(AFX_MSG_CALL CWnd::*)(WPARAM, LPARAM)> (&OnCreate)) },
            { 0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 }
        };
        static const AFX_MSGMAP messageMap = { &TheBaseClass::GetThisMessageMap, &_messageEntries[0] };
        return &messageMap;
    }
    */
    
    CMyFrameWnd::CMyFrameWnd()
    {
        m_x = 100;
        m_y = 100;
    }
    LRESULT CMyFrameWnd::OnMouseMove(WPARAM wParam, LPARAM lParam)
    {
        m_x = LOWORD(lParam);
        m_y = HIWORD(lParam);
        ::InvalidateRect(m_hWnd, NULL, TRUE);
        return 0;
    }
    LRESULT CMyFrameWnd::OnPaint(WPARAM wParam, LPARAM lParam)
    {
        PAINTSTRUCT ps = { 0 };
        HDC hdc = ::BeginPaint(m_hWnd, &ps);
        ::TextOut(hdc, m_x, m_y, L"hello", 5);
        ::EndPaint(m_hWnd, &ps);
        return 0;
    }
    LRESULT CMyFrameWnd::OnCreate(WPARAM wParam, LPARAM lParam)
    {
        AfxMessageBox(L"CMyFrameWnd::OnCreate");
        return 0;
    }
    
    class CMyWinApp : public CWinApp
    {
    public:
        virtual BOOL InitInstance();
    };
    
    CMyWinApp theApp;
    
    BOOL CMyWinApp::InitInstance()
    {
        CMyFrameWnd *pFrame = new CMyFrameWnd;
        pFrame->Create(NULL, L"MFCMsg");
        m_pMainWnd = pFrame;
        pFrame->ShowWindow(SW_SHOW);
        pFrame->UpdateWindow();
        return TRUE;
    }
    View Code

     运行结果:

      

    四、MFC消息分类

     1.windows的标准消息(键盘/鼠标/定时器...)

       ON_WM_XXX

       ON_WM_CREATE

       ON_WM_PAINT

       ON_WM_MOUSEMOVE

       ......

     2.自定义消息

       #define  WM_MYMESSAGE  WM_USER + n(1 - 31743)

       消息宏:ON_MESSAGE

     3.命令消息(WM_COMMAND)   

       消息宏:ON_COMMAND

     4.通知消息(WM_COMMAND)

       消息宏:ON_通知码     例如:ON_EN_CHANGE / ON_BN_CLICKED

     相关代码:

    #include "stdafx.h"
    #include "T11_MFCCmd.h"
    
    #define WM_MYMESSAGE WM_USER+1001
    
    class CMyFrameWnd : public CFrameWnd
    {
        DECLARE_MESSAGE_MAP()
    public:
        afx_msg int OnCreate(LPCREATESTRUCT pcs);
        afx_msg void OnPaint();
        afx_msg LRESULT OnMyMsg(WPARAM wParame, LPARAM lParam);
        afx_msg void OnOk();
        afx_msg void OnEnChange();
        afx_msg void OnBnClick();
    };
    
    BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)
        ON_WM_CREATE()  //基本消息
        ON_WM_PAINT()
        ON_MESSAGE(WM_MYMESSAGE, OnMyMsg)  //自定义消息
        //ON_COMMAND(1001, OnOk)  //命令消息
        ON_EN_CHANGE(1002, OnEnChange)  //通知消息
        ON_BN_CLICKED(1001, OnBnClick)
    END_MESSAGE_MAP()
    
    void CMyFrameWnd::OnBnClick()
    {
        AfxMessageBox(L"OK按钮被点击");
    }
    
    void CMyFrameWnd::OnEnChange()
    {
        AfxMessageBox(L"内容被修改");
    }
    
    void CMyFrameWnd::OnOk()
    {
        AfxMessageBox(L"OK按钮被点击");
    }
    
    LRESULT CMyFrameWnd::OnMyMsg(WPARAM wParame, LPARAM lParam)
    {
        AfxMessageBox(L"处理自己定义的消息");
        return 0;
    }
    
    void CMyFrameWnd::OnPaint()
    {
        PAINTSTRUCT ps = { 0 };
        HDC hdc = ::BeginPaint(m_hWnd, &ps);
        ::TextOut(hdc, 100, 100, L"hello", 5);
        ::EndPaint(m_hWnd, &ps);
    }
    
    int CMyFrameWnd::OnCreate(LPCREATESTRUCT pcs)
    {
        ::CreateWindowEx(0, L"BUTTON", L"OK", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 
            100, 100, 100, 40, m_hWnd, (HMENU)1001, AfxGetInstanceHandle(), NULL);
        ::CreateWindowEx(0, L"EDIT", L"", WS_BORDER | WS_VISIBLE | WS_CHILD, 
            400, 100, 100, 100, m_hWnd, (HMENU)1002, AfxGetInstanceHandle(), NULL);
        AfxMessageBox(L"CMyFrameWnd::OnCreate");
        ::PostMessage(m_hWnd, WM_MYMESSAGE, 1, 2);
        return CFrameWnd::OnCreate(pcs);
    }
    
    class CMyWinApp : public CWinApp
    {
    public:
        virtual BOOL InitInstance();
    };
    
    CMyWinApp theApp;
    
    BOOL CMyWinApp::InitInstance()
    {
        CMyFrameWnd *pFrame = new CMyFrameWnd;
        m_pMainWnd = pFrame;
        pFrame->Create(NULL, L"MFCCmd");
        pFrame->ShowWindow(SW_SHOW);
        pFrame->UpdateWindow();
        return TRUE;
    }
    View Code

     运行结果:

     

     

       

  • 相关阅读:
    基本类型
    匿名对象和匿名方法
    定时任务@SChedule详解
    docker的配置和安装
    数据库的学习
    docker的学习
    nginx的学习
    yyyy-MM-dd HH:mm:ss.SS的大小写的含义
    单例模式的学习
    layer的学习
  • 原文地址:https://www.cnblogs.com/csqtech/p/5681313.html
Copyright © 2011-2022 走看看