友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
第三电子书 返回本书目录 加入书签 我的书架 我的书签 TXT全本下载 『收藏到我的浏览器』

深入浅出MFC第2版(PDF格式)-第39部分

快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!




当然,毫不令人意外地,MFC 源代码中的CObList 和CDWordArray 有这样的内容: 



// in header files 

class CDWordArray : public CObject 

{ 

        DECLARE_SERIAL(CDWordArray) 

public: 

        void Serialize(CArchive&); 

。。。 

}; 

class CObList : public CObject 

{ 

        DECLARE_SERIAL(CObList) 

public: 

        void Serialize(CArchive&); 

。。。 

}; 



// in implementation files 



                                                                                 169 


…………………………………………………………Page 232……………………………………………………………

                第篇  勿在浮砂築高台 



                IMPLEMENT_SERIAL(CObList; CObject; 0) 

                IMPLEMENT_SERIAL(CDWordArray; CObject; 0) 



                而CObject 也多了一个虚拟函数Serialize: 



                class CObject 

                { 

                public: 

                        virtual void Serialize(CArchive& ar); 

                。。。 

                } 



            没有范例程序 



               抱歉,我没有准备DOS 版的Serialization 范例程序给你。你看到了,很多东西需要仿 



                真:CFile、CArchive、CObList、CDWordArray、CRect、CPoint、运算子多载、Serialize 



                函数。。。。我干脆在本书第8章直接为你解释MFC  的作法,更好。 



          Message Mapping  (消息映射) 



               Windows 程序靠消息的流动而维护生命。你已经在第一章看过了消息的一般处理方式, 



               也就是在窗口函数中借着一个大大的switch/case  比对动作,判别消息再调用对应的处理 



               例程。为了让大大的switch/case  比对动作简化,也让程序代码更模块化一些,我在第1章 



               提供了一个简易的消息映射表作法,把消息和其处理例程关联起来。 



               当我们的类别库成立,如果其中与消息有关的类别(姑且叫作「消息标的类别」好了, 



               在MFC 之中就是CCmdTarget)都是一条鞭式地继承,我们应该为每一个「消息标的类 



               别」准备一个消息映射表,并且将基础类别与衍生类别之消息映射表串接起来。然后, 



               当窗口函数做消息的比对时,我们就可以想办法导引它沿着这条路走过去: 



170 


…………………………………………………………Page 233……………………………………………………………

                                                           第3章    MFC 六大關鍵技術之模擬 



  CObject 

   CObject 



      CCmdTarget 

       CCmdTarget 



         CWinThread 

          CWinThread 



             CWinApp 

             CWinApp 



                CMyWinApp 

                 CMyWinApp 



         CWnd 

          CWnd 



             CView 



                CMyView 

                 CMyView 



             CFrameWnd 

             CFrameWnd 



                CMyFrameWnd 

                 CMyFrameWnd 



         CDocument 

          CDocument 



             CMyDoc 

             CMyDoc 



但是,MFC 之中用来处理消息的C++ 类别,并不呈单鞭发展。作为application framework 



的重要架构之一的document/view ,也具有处理消息的能力(你现在可能还不清楚什么是 



document/view ,没有关系)。因此,消息藉以攀爬的路线应该有横流的机会: 



  CObject 

   CObject 



      CCmdTarget 

       CCmdTarget 



          CWinThread 

           CWinThread 



              CWinApp 

              CWinApp 



                 CMyWinApp 

                  CMyWinApp 



          CWnd 

           CWnd 



              CView 



                 CMyView 

                  CMyView 



              CFrameWnd 

              CFrameWnd 



                 CMyFrameWnd 

                  CMyFrameWnd 



          CDocument 

           CDocument 



              CMyDoc 

              CMyDoc 



                                                                                                    171 


…………………………………………………………Page 234……………………………………………………………

                  第篇  勿在浮砂築高台 



                  消息如何流动,我们暂时先不管。是直线前进,或是中途换跑道,我们都暂时不管,本 



                  节先把这个攀爬路线网建立起来再说。这整个攀爬路线网就是所谓的消息映射表 



                   (Message Map );说它是一张地图,当然也没有错。将消息与表格中的元素比对,然后 



                  调用对应的处理例程,这种动作我们也称之为消息映射(Message Mapping)。 



                  为了尽量降低对正常(一般)类别声明和定义的影响,我们希望,最好能够像RTTI 和 



                  Dynamic Creation 一样,用一两个宏就完成这巨大蜘蛛网的构造。最好能够像 



                  DECLARE_DYNAMIC 和IMPLEMENT_DYNAMIC 宏那么方便。 



                  首先定义一个数据结构: 



                     struct AFX_MSGMAP 

                      { 

                             AFX_MSGMAP* pBaseMessageMap; 

                             AFX_MSGMAP_ENTRY* lpEntries; 

                      }; 



                   其中的 AFX_MSGMAP_ENTRY 又是另一个数据结构: 



                     struct AFX_MSGMAP_ENTRY  // MFC 4。0 format 

                      { 

                             UINT nMessage;      // windows message 

                             UINT nCode;         // control code or WM_NOTIFY code 

                             UINT nID;           // control ID (or 0 for windows messages) 

                             UINT nLastID;       // used for entries specifying a range of control id's 

                             UINT nSig;          // signature type (action) or pointer to message # 

                             AFX_PMSG pfn;       // routine to call (or special value) 

                      }; 



                    其中的AFX_PMSG 定义为函数指针: 



                     typedef void (CCmdTarget::*AFX_PMSG)(void); 



                     然后我们定义一个宏: 



                     #define DECLARE_MESSAGE_MAP()  

                             static AFX_MSGMAP_ENTRY _messageEntries'';  

                             static AFX_MSGMAP messageMap;  

                             virtual AFX_MSGMAP* GetMessageMap() const; 



172 


…………………………………………………………Page 235……………………………………………………………

                                                       第3章    MFC 六大關鍵技術之模擬 



 于是,DECLARE_MESSAGE_MAP 就相当于声明了这样一个数据结构: 



                                                        pBaseMessageMap 

                         _messageEntries'' 

                                                            lpEntries 

                nMessage; nCode; nID; nLastID; nSig; pfn 



                                                          messageMap 



这个数据结构的内容填塞工作由三个宏完成: 



#define BEGIN_MESSAGE_MAP (theClass; baseClass)  

        AFX_MSGMAP* theClass::GetMessageMap() const  

                { return &theClass::messageMap; }  

        AFX_MSGMAP theClass::messageMap =  

        { &(baseClass::messageMap);  

                (AFX_MSGMAP_ENTRY*) &(theClass::_messageEntries) };  

        AFX_MSGMAP_ENTRY theClass::_messageEntries'' =  

        { 



#define ON_MAND (id; memberFxn)  

        { WM_MAND; 0; (WORD)id; (WORD)id; AfxSig_vv; (AFX_PMSG)memberFxn }; 



#define END_MESSAGE_MAP ()  

        { 0; 0; 0; 0; AfxSig_end; (AFX_PMSG)0 }  

        }; 



其中的AfxSig_end 定义为: 



enum AfxSig 

{ 

        AfxSig_end = 0;     // 'marks end of message map' 

        AfxSig_vv;    

}; 



 AfxSig_xx 用来描述消息处理例程memberFxn  的类型(参数与回返值)。本例纯为仿真 



 与简化,所以不在这上面作文章。真正讲到MFC 时(第四篇p580 ),我会再解释它。 



                                                                                             173 


…………………………………………………………Page 236……………………………………………………………

                   第篇  勿在浮砂築高台 



                    于是,以CView 为例,下面的源代码: 



                      // in header file 

                      class CView : public CWnd 

                      { 

                      public: 

                        。。。 

                        DECLARE_MESSAGE_MAP() 

                      }; 



                      // in implementation file 

                      #define CViewid 122 

                       。。。 

                      BEGIN_MESSAGE_MAP(CView; CWnd) 

                        ON_MAND(CViewid; 0) 

                      END_MESSAGE_MAP() 



                    就被展开成为: 



                      // in header file 

                      class CView : public CWnd 

                      { 

                      public: 

                        。。。 

                        static AFX_MSGMAP_ENTRY _messageEntries''; 

                        static AFX_MSGMAP messageMap; 

                        virtual AFX_MSGMAP* GetMessageMap() const; 

                      }; 



                      // in implementation file 

                      AFX_MSGMAP* CView::GetMessageMap() const 

                              { return &CView::messageMap; } 

                      AFX_MSGMAP CView::messageMap = 

                      { &(CWnd::messageMap); 

                              (AFX_MSGMAP_ENTRY*) &(CView::_messageEntries) }; 

                      AFX_MSGMAP_ENTRY CView::_messageEntries'' = 

                      { 

                        { WM_MAND; 0; (WORD)122; (WORD)122; 1; (AFX_PMSG)0 }; 

                        { 0; 0; 0; 0; 0; (AFX_PMSG)0 } 

                      }; 



                    以图表示则为: 



174 


…………………………………………………………Page 237……………………………………………………………

                                                     第3章    MFC 六大關鍵技術之模擬 



                                                       CWnd::messageMap 



                                                         pBaseMessageMap 

                   CView::_messageEntries'' 

                                                              lpEntries 

         WM_MAND;  0;  122;  122;   1;  (AFX_PMSG)0 



                 0; 0; 0; 0; 0; (AFX_PMSG)0             CView::messageMap 



  我们还可以定义各种类似ON_MAND 这样的宏,把各式各样的消息与特定的处 



  理例程关联起来。MFC 里头就有名为ON_ WM_PAINT 、ON_ WM_CREATE、ON_ WM_SIZE。。。 



  等等的宏。 



  我在Frame7 范例程序中为CCmdTarget  的每一衍生类别都产生类似上图的消息映射表: 



// in header files 

class CObject 

{ 

     。。。 // 注意:CObject 并不属于消息流动网的一份子。 

}; 

class CCmdTarget : public CObject 

{ 

。。。 

  DECLARE_MESSAGE_MAP() 

}; 

class CWinThread : public CCmdTarget 

{ 

 。。。 // 注意:CWinThread 并不属于消息流动网的一份子。 

}; 

class CWinApp : public CWinThread 

{ 

。。。 

  DECLARE_MESSAGE_MAP() 

}; 

class CDocument : public CCmdTarget 

{ 

。。。 

  DECLARE_MESSAGE_MAP() 

}; 

class CWnd : public CCmdTarget 

{ 

。。。 

  DECLARE_MESSAGE_MAP() 



                                                                                         175 


…………………………………………………………Page 238…………………………………………………………
返回目录 上一页 下一页 回到顶部 0 0
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!