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

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

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





                 消息映射表的每一笔记录是这样的形式: 



                 struct AFX_MSGMAP_ENTRY 

                 { 

                     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) 

                 }; 



                 内中包括一个Windows 消息、其控制组件ID  以及通告码(notification code ,对消息的 



                 更多描述,例如EN_CHANGED 或CBN_DROPDIOWN 等)、一个签名记号、以及一个 



                 CCmdTarget 衍生类别的成员函数。任何一个ON_ 宏会把这六个项目初始化起来。例 



                 如: 



                 #define ON_WM_CREATE ()  

                   { WM_CREATE; 0; 0; 0; AfxSig_is;  

                     (AFX_PMSG)(AFX_PMSGW)(int (AFX_MSG_CALL CWnd::*)(LPCREATESTRUCT))OnCreate }; 



                 你看到了可怕的类型转换动作,这完全是为了保持类型安全(type…safe )。 



580 


…………………………………………………………Page 643……………………………………………………………

                                                       第9章   訊息映射與命令繞行   



有一个很莫名其妙的东西:AfxSig_ 。要了解它作什么用,你得先停下来几分钟,想想另 



一个问题:当上一节的推动引擎比对消息并发现吻合之后,就调用对应的处理例程,但 



它怎么知道要交给消息处理例程哪些参数呢?要知道,不同的消息处理例程需要不同的 



参数(包括个数和类型),而其函数指针(AFX_PMSG )却都被定义为这付德行: 



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



这么简陋的信息无法表现应该传递什么样的参数,而这正是AfxSig_ 要贡献的地方。当 



推动引擎比对完成,欲调用某个消息处理例程lpEntry…》pfn 时,动作是这样子地(出现 



在CWnd::OnWndMsg 和DispatchCmdMsg  中): 



 union MessageMapFunctions mmf; 

 mmf。pfn = lpEntry…》pfn; 



 switch (lpEntry…》nSig) 

 { 

 case AfxSig_is: 

         lResult = (this…》*mmf。pfn_is)((LPTSTR)lParam); 

         break; 



 case AfxSig_lwl: 

         lResult = (this…》*mmf。pfn_lwl)(wParam; lParam); 

         break; 



 case AfxSig_vv: 

         (this…》*mmf。pfn_vv)(); 

         break; 

 。。。 

 } 



注意两样东西:MessageMapFunctions 和AfxSig_ 。AfxSig_ 定义于AFXMSG_。H 档: 



 enum AfxSig 

 { 

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



         AfxSig_bD;      // BOOL (CDC*) 

         AfxSig_bb;      // BOOL (BOOL) 

         AfxSig_bWww;    // BOOL (CWnd*; UINT; UINT) 

         AfxSig_hDWw;    // HBRUSH (CDC*; CWnd*; UINT) 

         AfxSig_hDw;     // HBRUSH (CDC*; UINT) 



                                                                                      581 


…………………………………………………………Page 644……………………………………………………………

                   第篇    深入  MFC  程式設計 



                           AfxSig_iwWw;    // int (UINT; CWnd*; UINT) 

                           AfxSig_iww;     // int (UINT; UINT) 

                           AfxSig_iWww;    // int (CWnd*; UINT; UINT) 

                           AfxSig_is;      // int (LPTSTR) 

                           AfxSig_lwl;     // LRESULT (WPARAM; LPARAM) 

                           AfxSig_lwwM;    // LRESULT (UINT; UINT; CMenu*) 

                           AfxSig_vv;      // void (void) 



                           AfxSig_vw;      // void (UINT) 

                           AfxSig_vww;     // void (UINT; UINT) 

                           AfxSig_vvii;    // void (int; int) // wParam is ignored 

                           AfxSig_vwww;    // void (UINT; UINT; UINT) 

                           AfxSig_vwii;    // void (UINT; int; int) 

                           AfxSig_vwl;     // void (UINT; LPARAM) 

                           AfxSig_vbWW;    // void (BOOL; CWnd*; CWnd*) 

                           AfxSig_vD;      // void (CDC*) 

                           AfxSig_vM;      // void (CMenu*) 

                           AfxSig_vMwb;    // void (CMenu*; UINT; BOOL) 



                           AfxSig_vW;      // void (CWnd*) 

                           AfxSig_vWww;    // void (CWnd*; UINT; UINT) 

                           AfxSig_vWp;     // void (CWnd*; CPoint) 

                           AfxSig_vWh;     // void (CWnd*; HANDLE) 

                           AfxSig_vwW;     // void (UINT; CWnd*) 

                           AfxSig_vwWb;    // void (UINT; CWnd*; BOOL) 

                           AfxSig_vwwW;    // void (UINT; UINT; CWnd*) 

                           AfxSig_vwwx;    // void (UINT; UINT) 

                           AfxSig_vs;      // void (LPTSTR) 

                           AfxSig_vOWNER;  // void (int; LPTSTR); force return TRUE 

                           AfxSig_iis;     // int (int; LPTSTR) 

                           AfxSig_wp;      // UINT (CPoint) 

                           AfxSig_wv;      // UINT (void) 

                           AfxSig_vPOS;    // void (WINDOWPOS*) 

                           AfxSig_vCALC;   // void (BOOL; NCCALCSIZE_PARAMS*) 

                           AfxSig_vNMHDRpl;    // void (NMHDR*; LRESULT*) 

                           AfxSig_bNMHDRpl;    // BOOL (NMHDR*; LRESULT*) 

                           AfxSig_vwNMHDRpl;   // void (UINT; NMHDR*; LRESULT*) 

                           AfxSig_bwNMHDRpl;   // BOOL (UINT; NMHDR*; LRESULT*) 

                           AfxSig_bHELPINFO;   // BOOL (HELPINFO*) 

                           AfxSig_vwSIZING;    // void (UINT; LPRECT) …return TRUE 



                           // signatures specific to CCmdTarget 

                           AfxSig_cmdui;   // void (CCmdUI*) 

                           AfxSig_cmduiw;  // void (CCmdUI*; UINT) 

                           AfxSig_vpv;     // void (void*) 

                           AfxSig_bpv;     // BOOL (void*) 



582 


…………………………………………………………Page 645……………………………………………………………

                                                      第9章   訊息映射與命令繞行   



        // Other aliases (based on implementation) 

        AfxSig_vwwh;                // void (UINT; UINT; HANDLE) 

        AfxSig_vwp;                 // void (UINT; CPoint) 

        AfxSig_bw = AfxSig_bb;      // BOOL (UINT) 

        AfxSig_bh = AfxSig_bb;      // BOOL (HANDLE) 

        AfxSig_iw = AfxSig_bb;      // int (UINT) 

        AfxSig_ww = AfxSig_bb;      // UINT (UINT) 

        AfxSig_bv = AfxSig_wv;      // BOOL (void) 

        AfxSig_hv = AfxSig_wv;      // HANDLE (void) 

        AfxSig_vb = AfxSig_vw;      // void (BOOL) 

        AfxSig_vbh = AfxSig_vww;    // void (BOOL; HANDLE) 

        AfxSig_vbw = AfxSig_vww;    // void (BOOL; UINT) 

        AfxSig_vhh = AfxSig_vww;    // void (HANDLE; HANDLE) 

        AfxSig_vh = AfxSig_vw;      // void (HANDLE) 

        AfxSig_viSS = AfxSig_vwl;   // void (int; STYLESTRUCT*) 

        AfxSig_bwl = AfxSig_lwl; 

        AfxSig_vwMOVING = AfxSig_vwSIZING;  // void (UINT; LPRECT) …return TRUE 

}; 



MessageMapFunctions  定义于 WINCORE。CPP 档: 



union MessageMapFunctions 

{ 

        AFX_PMSG pfn;   // generic member function pointer 



        // specific type safe variants 

        BOOL    (AFX_MSG_CALL CWnd::*pfn_bD)(CDC*); 

        BOOL    (AFX_MSG_CALL CWnd::*pfn_bb)(BOOL); 

        BOOL    (AFX_MSG_CALL CWnd::*pfn_bWww)(CWnd*; UINT; UINT); 

        BOOL    (AFX_MSG_CALL CWnd::*pfn_bHELPINFO)(HELPINFO*); 

        HBRUSH  (AFX_MSG_CALL CWnd::*pfn_hDWw)(CDC*; CWnd*; UINT); 

        HBRUSH  (AFX_MSG_CALL CWnd::*pfn_hDw)(CDC*; UINT); 

        int     (AFX_MSG_CALL CWnd::*pfn_iwWw)(UINT; CWnd*; UINT); 

        int     (AFX_MSG_CALL CWnd::*pfn_iww)(UINT; UINT); 

        int     (AFX_MSG_CALL CWnd::*pfn_iWww)(CWnd*; UINT; UINT); 

        int     (AFX_MSG_CALL CWnd::*pfn_is)(LPTSTR); 

        LRESULT (AFX_MSG_CALL CWnd::*pfn_lwl)(WPARAM; LPARAM); 

        LRESULT (AFX_MSG_CALL CWnd::*pfn_lwwM)(UINT; UINT; CMenu*); 

        void    (AFX_MSG_CALL CWnd::*pfn_vv)(void); 



        void    (AFX_MSG_CALL CWnd::*pfn_vw)(UINT); 

        void    (AFX_MSG_CALL CWnd::*pfn_vww)(UINT; UINT); 

        void    (AFX_MSG_CALL CWnd::*pfn_vvii)(int; int); 

        void    (AFX_MSG_CALL CWnd::*pfn_vwww)(UINT; UINT; UINT); 

        void    (AFX_MSG_CALL CWnd::*pfn_vwii)(UINT; int; int); 



                                                                                    583 


…………………………………………………………Page 646……………………………………………………………

                  第篇    深入  MFC  程式設計 



                          void    (AFX_MSG_CALL CWnd::*pfn_vwl)(WPARAM; LPARAM); 

                          void    (AFX_MSG_CALL CWnd::*pfn_vbWW)(BOOL; CWnd*; CWnd*); 

                          void    (AFX_MSG_CALL CWnd::*pfn_vD)(CDC*); 

                          void    (AFX_MSG_CALL CWnd::*pfn_vM)(CMenu*); 

                          void    (AFX_MSG_CALL CWnd::*pfn_vMwb)(CMenu*; UINT; BOOL); 



                          void    (AFX_MSG_CALL CWnd::*pfn_vW)(CWnd*); 

                          void    (AFX_MSG_CALL CWnd::*pfn_vWww)(CWnd*; UINT; UINT); 

                          void    (AFX_MSG_CALL CWnd::*pfn_vWp)(CWnd*; CPoint); 

                          void    (AFX_MSG_CALL CWnd::*pfn_vWh)(CWnd*; HANDLE); 

                          void    (AFX_MSG_CALL CWnd::*pfn_vwW)(UINT; CWnd*); 

                          void    (AFX_MSG_CALL CWnd::*pfn_vwWb)(UINT; CWnd*; BOOL); 

                          void    (AFX_MSG_CALL CWnd::*pfn_vwwW)(UINT; UINT; CWnd*); 

                          void    (AFX_MSG_CALL CWnd::*pfn_vwwx)(UINT; UINT); 

                          void    (AFX_MSG_CALL CWnd::*pfn_vs)(LPTSTR); 

                          void    (AFX_MSG_CALL CWnd::*pfn_vOWNER)(int; LPTSTR);   // force return TRUE 

                          int     (AFX_MSG_CALL CWnd::*pfn_iis)(int; LPTSTR); 

                          UINT    (AFX_MSG_CALL CWnd::*pfn_wp)(CPoint); 

                          UINT    (AFX_MSG_CALL CWnd::*pfn_wv)(void); 

                          void    (AFX_MSG_CALL CWnd::*pfn_vPOS)(WINDOWPOS*); 

                          void    (AFX_MSG_CALL CWnd::*pfn_vCALC)(BOOL; NCCALCSIZE_PARAMS*); 

                          void    (AFX_MSG_CALL CWnd::*pfn_vwp)(UINT; CPoint); 

                          void    (AFX_MSG_CALL CWnd::*pfn_vwwh)(UINT; UINT; HANDLE); 

                   }; 



                  其实呢,真正的函数只有一个pfn ,但通过union,它有许多类型不同的形象。pfn _vv 代 



                  表「参数为void ,传回值为void 」;pfn _lwl 代表「参数为wParam 和lParam,传回 



                  值为LRESULT 」;pfn _is 代表「参数为LPTSTR 字符串,传回值为int」。 



                  相当精致,但是也有点儿可怖,是不是?使用MFC 或许应该像吃蜜饯一样; 蜜饯很好 



                  吃,但你最好不要看到蜜饯的生产过程!唔,我真的不知道! 



                  无论如何,我把所有的神秘都揭开在你面前了。 



                                      山高月小   水落石出 



584 


…………………………………………………………Page 647……………………………………………………………

                                            第9章   訊息映射與命令繞行   



Scribble Step2 :UI 对象的变化 



     理论基础建立完毕,该是实作的时候。Step2 将新增三个菜单命令项,一个工具栏按钮, 



     并维护这些UI 对象的使用状态。 



改变菜单 



     Step2 将增加一个【Pen 】菜单,其中有两个命令项目;并在【Edit 】菜单中增加一个【Clear 



     All 】命令项目: 



       【Pen/Thick Line 】:这是一个切换开关,允许设定使用粗笔或细笔。如果使用 



        者设定粗笔,我们将在这项目的旁边打个勾(所谓的checked );如果使用者 



        选择细笔(也就是在打勾的本项目上再按一下),我们就把勾号去除(所谓的 



        unchecked )。 



       【Pen/Pen Widths 】:这会唤起一个对话框,允许设定笔的宽度。对话框的设计 



        并不在本章范围,那是下一章的事。 



       【Edit/Clear All 】:清除目前作用之Document 资料。当然对应之View 窗口 



        内容也应该清干净。 



      Visual C++ 整合环境中的菜单编辑器拥有非常方便的鼠标拖放(drag and drop )功能,所 



      以做出上述的菜单命令项不是难事。不过这些命令项目还得经过某些动作,才能与程序 



      码关联起来发生作用,这方面ClassWizard 可以帮助我们。稍后我会说明这一切。 



      以下利用Visual C++ 整合环境中的菜单编辑器修改菜单: 



                                                                  585 


…………………………………………………………Page 648……………………………………………………………

                 第篇    深入  MFC  程式設計 



                  激活菜单编辑器(请参考第4章)。Scribble 有两份菜单,IDR_MAINFRAME 



                   适用于没有任何子窗口的情况,IDR_SCRIBTYPE 适用于有子窗口的情况。我 



                   们选择后者。 



                   IDR_SCRIBTYPE 菜单内容出现于画面右半侧。加入新增的三个命令项。每个 



                   命令项会获得一个独一无二的识别码,定义于RESOURCE。H 或任何你指定的 



                   文件中。图下方的【Menu Item Properties 】对话框在你双击某个命令项后出现, 



                   允许你更改命令项的识别码与提示字符串(将出现在状态列中)。如果你对操作 



                   过程不熟练,请参考Visual C++ User's Guide   (Visual C++ Online 上附有此书之 



                   电子版)。 

                   三个新命令项的ID 值以及提示字符串整理于下: 

        



                     【             】 

                      Pen/Thick Line 

                    ID : ID_PEN_THICK_OR_THIN 

                    prompt : 〃Toggles the line thickness between thin and thicknToggle pen〃 



586 


…………………………………………………………Page 649……………………………………………………………

                                                       第9章   訊息映射與命令繞行   



     【               】 

      Pen/Pen Widths 

    ID : ID_PEN_WIDTHS 

    prompt : 〃Sets the size of the thin and thick pennPen thickness〃 



     【               】 

      Edit/Clear All 

    ID : ID_EDIT_CLEAR_ALL (这是一个预先定义的ID,有预设的提示字符串,请更改如下) 

    prompt : 〃Clears the drawingnErase All〃 



    注意:每一个提示字符串都有一个n 子字符串,那是作为工具栏按钮的「小黄卷标」 



    的卷标内容。「小黄卷标」(学名叫作tool tips)是Windows 95 新增的功能。 



对Framework 而言,命令项的ID 是用以识别命令消息的唯一依据。你只需在【Properties 】 



对话框中键入你喜欢的ID 名称(如果你不满意菜单编辑器自动给你的那个),至于它真 



正的数值不必在意,菜单编辑器会在你的RESOURCE。H 档中加上定义值。 



经过上述动作,菜单编辑器影响我们的程序代码如下: 



// in RESOURCE。H 

#define ID_PEN_THICK_OR_THIN           32772 

#define ID_PEN_WIDTHS                   32773 



 (注:另一个ID ID_EDIT_CLEAR_ALL 已预先定义于AFXRES。H 中) 



// in SCRIBBLE。RC 

IDR_SCRIBBTYPE MENU PRELOAD DISCARDABLE 

BEGIN 

    。。。 

    POPUP 〃&Edit〃 

    BEGIN 

        。。。 

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