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

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

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



                                                                     m_pMainWnd…》UpdateWindow(); 

                         2                                         8 

                            AfxWinInit(。。。); 

                                                                     return TRUE; 

                         3                                         } 

                            pApp…》InitApplication(); 

                            pApp…》InitInstance(); 

                         4 

                                                                  CMyFrameWnd::CMyFrameWnd() 

                            nReturnCode = pApp…》Run(); 

                         9                                         { 

                                                                   6 

                                                                     Create(NULL; 〃Hello MFC〃; 。。。; 

                            AfxWinTerm(); 

                                                                            〃MainMenu〃); 

                        } 

                                   CWinApp::Run                    } 

                                    CWinApp::Run 



                            CWinThread::Run                       void CMyFrameWnd::OnPaint()  { 。。。 } 

                            do {                                  void CMyFrameWnd::OnAbout()  { 。。。 } 

                             do { 

                              ::GetMessage(&msg;。。。); 

                               ::GetMessage(&msg;。。。); 

                              PreTranslateMessage{&msg); 

                               PreTranslateMessage{&msg);         BEGIN_MESSAGE_MAP(CMyFrameWnd; CFrameWnd) 

                              ::TranslateMessage(&msg); 

                               ::TranslateMessage(&msg); 

                               ::DispatchMessage(&msg);              ON_MAND(IDM_ABOUT; OnAbout) 

                                ::DispatchMessage(&msg); 

                              。。。                                    ON_WM_PAINT() 

                               。。。 

                            } while (::PeekMessage(。。。));         END_MESSAGE_MAP() 

                             } while (::PeekMessage(。。。)); 



                                                 DefWindowProc 

                                                 DefWindowProc                              AfxWndProc 

                                                                   hooking and subclassing   AfxWndProc 



                                                                   (please see chap9; p。560; 

                                                                  “Minotauros and Theseus”) 



                     Hello 程序进行到这里,窗口类别注册好了,窗口诞生并显示出来了,UpdateWindow 被 



                     调用,使得消息队列中出现了一个WM_PAINT 消息,等待被处理。现在,执行的脚步到 



                     达pApp …》Run 。 



                     稍早我说过了,pApp  指向CMyWinApp 对象(也就是本例的theApp ),所以,当程序 



                     调用: 



                        pApp…》Run(); 



                     相当于调用: 



                        CMyWinApp::Run(); 



390 


…………………………………………………………Page 453……………………………………………………………

                                                          第6章    MFC 程式的生死因果 



要知道,CMyWinApp 继承自CWinApp,而Run 又是CWinApp 的一个虚拟函数。我们 



并没有改写它(大部份情况下不需改写它),所以上述动作相当于调用: 



   CWinApp::Run(); 



其源代码出现在APPCORE。CPP  中: 



int CWinApp::Run() 

 { 

    if (m_pMainWnd == NULL && AfxOleGetUserCtrl()) 

    { 

        // Not launched /Embedding or /Automation; but has no main window! 

        TRACE0(〃Warning: m_pMainWnd is NULL in CWinApp::Run quitting 

         application。n〃); 

        AfxPostQuitMessage(0); 

    } 

    return CWinThread::Run(); 

 } 



32 位MFC 与16 位MFC  的巨大差异在于CWinApp 与CCmdTarget 之间多出了一 



个CWinThread,事情变得稍微复杂一些。CWinThread 定义于THRDCORE。CPP : 



int CWinThread::Run() 

 { 

    // for tracking the idle time state 

    BOOL bIdle = TRUE; 

    LONG lIdleCount = 0; 



    // acquire and dispatch messages until a WM_QUIT message is received。 

    for (;;) 

    { 

        // phase1: check to see if we can do idle work 

        while (bIdle && 

                !::PeekMessage(&m_msgCur; NULL; NULL; NULL; PM_NOREMOVE)) 

        { 

            // call OnIdle while in bIdle state 

            if (!OnIdle(lIdleCount++)) 

                bIdle = FALSE; // assume 〃no idle〃 state 

        } 



        // phase2: pump messages while available 

        do 

        { 

            // pump message; but quit on WM_QUIT 



                                                                                           391 


…………………………………………………………Page 454……………………………………………………………

                    第篇    湷觥 FC  程式設計 



                                if (!PumpMessage ()) 

                                    return ExitInstance(); 



                                // reset 〃no idle〃 state after pumping 〃normal〃 message 

                                if (IsIdleMessage(&m_msgCur)) 

                                { 

                                    bIdle = TRUE; 

                                    lIdleCount = 0; 

                                } 



                            } while (::PeekMessage(&m_msgCur; NULL; NULL; NULL; PM_NOREMOVE)); 

                        } 



                        ASSERT(FALSE);  // not reachable 

                     } 



                     BOOL CWinThread::PumpMessage() 

                     { 

                        if (!::GetMessage(&m_msgCur; NULL; NULL; NULL)) 

                        { 

                            return FALSE; 

                        } 



                        // process this message 

                        if (m_msgCur。message != WM_KICKIDLE && !PreTranslateMessage(&m_msgCur)) 

                        { 

                            ::TranslateMessage(&m_msgCur); 

                            ::DispatchMessage(&m_msgCur); 

                        } 

                        return TRUE; 

                     } 



                      获得的消息如何交给适当的例程去处理呢?SDK 程序的作法是调用DispatchMessage ,把 



                      消息丢给窗口函数;MFC 也是如此。但我们并未在Hello 程序中提供任何窗口函数,是 



                      的,窗口函数事实上由MFC 提供。回头看看前面AfxEndDeferRegisterClass 源代码,它 



                      在注册四种窗口类别之前已经指定窗口函数为: 



                        wndcls。lpfnWndProc = DefWindowProc; 



392 


…………………………………………………………Page 455……………………………………………………………

                                         第6章    MFC 程式的生死因果 



注意,虽然窗口函数被指定为DefWindowProc 成员函数,但事实上消息并不是被唧往该 



处,而是一个名为AfxWndProc  的全域函数去。这其中牵扯到MFC 暗中做了大挪移的 



手脚(利用hook 和subclassing),我将在第9章详细讨论这个「乾坤大挪移」。 



你看,WinMain 已由MFC 提供,窗口类别已由MFC 注册完成、连窗口函数也都由MFC 



提供。那么我们(程序员)如何为特定的消息设计特定的处理例程?MFC 应用程序对讯 



息的辨识与判别是采用所谓的「Message Map 机制」。 



                                                                393 


…………………………………………………………Page 456……………………………………………………………

                            第篇    湷觥 FC  程式設計 



                  把消息与处理函数串接在一起:Message Map 机制 



                                                                                     HELLO。CPP 



                                                                                1    CMyWinApp theApp;   // application object 



                                                                                     BOOL CMyWinApp::InitInstance() 

                              WINMAIN。CPP 

                                                                                     { 

                                                                                      5 

                              int AFXAPI AfxWinMain (。。。)                              m_pMainWnd = new CMyFrameWnd(); 

                              {                                                        m_pMainWnd…》ShowWindow(m_nCmdShow); 

                                                                                      7 

                                  CWinApp* pApp = AfxGetApp();                         m_pMainWnd…》UpdateWindow(); 

                                                                                      8 

                                                                                       return TRUE; 

                                2                                                    } 

                                  AfxWinInit(。。。); 



                                3                                                    CMyFrameWnd::CMyFrameWnd() 

                                  pApp…》InitApplication(); 

                                  pApp…》InitInstance();                              { 

                                4 

                                                                                      6 

                                  nReturnCode = pApp…》Run();                           Create(NULL; 〃Hello MFC〃; 。。。; 

                                9 

                                                                                              〃MainMenu〃); 

                                  AfxWinTerm();                                      } 

                              } 

                                                                                    void CMyFrameWnd::OnPaint()  { 。。。 } 11 



                                      AfxWndProc                                     void CMyFrameWnd::OnAbout()  { 。。。 } 

                                                         m                      m 

                                                         e                      e 

                                                         s                      s    BEGIN_MESSAGE_MAP(CMyFrameWnd; CFrameWnd) 

                                                         s                      s 

                                                         a                      a 

                                      WM_PAINT                      WM_PAINT 

                                                         g                      g      ON_MAND(IDM_ABOUT; OnAbout) 

                                                         e 

                                                          r                     e  

                                                         o                             ON_WM_PAINT() 

                                                         u                      m 

                                                         t                      a 

                                                         i 

                                                         n 

                                          10                                         END_MESSAGE_MAP() 

                                                         g                      p 



                                                              。 

                                                              。 

                                                              。 



                            基本上Message Map 机制是为了提供更方便的程序接口(例如宏或表格),让程序员 



                            很方便就可以建立起消息与处理例程的对应关系。这并不是什么新发明,我在第1章示 



                            范了一种风格简明的SDK 程序写法,就已经展现出这种精神。 



                            MFC 提供给应用程序使用的「很方便的接口」是两组宏。以Hello  的主窗口为例, 



                            第一个动作是在HELLO。H  的CMyFrameWnd 加上DECLARE_MESSAGE_MAP : 



394 


…………………………………………………………Page 457……………………………………………………………

                                                    第6章    MFC 程式的生死因果 



    class CMyFrameWnd : public CFrameWnd 

    { 

    public: 

           CMyFrameWnd(); 

           afx_msg void OnPaint(); 

           afx_msg void OnAbout(); 

           DECLARE_MESSAGE_MAP() 

    }; 



第二个动作是在HELLO。CPP  的任何位置(当然不能在函数之内)使用宏如下: 



    BEGIN_MESSAGE_MAP(CMyFrameWnd; CFrameWnd) 

        ON_WM_PAINT() 

        ON_MAND(IDM_ABOUT; OnAbout) 

    END_MESSAGE_MAP() 



这么一来就把消息WM_PAINT  导到OnPaint 函数, 把WM_MAND 



 (IDM_ABOUT )导到OnAbout 函数去了。但是,单凭一个ON_WM_PAINT 宏,没 



有任何参数,如何使WM_PAINT 流到OnPaint 函数呢? 



MFC 把消息主要分为三大类,Message Map 机制中对于消息与函数间的对映关系也明定 



以下三种: 



■ 标准Windows 消息(WM_xxx )的对映规则: 



  宏名称                  对映消息            消息处理函数(名称已由系统预设) 



ON_WM_CHAR                WM_CHAR              OnChar 



ON_WM_CLOSE               WM_CLOSE             OnClose 



ON_WM_CREATE              WM_CREATE            OnCreate 



ON_WM_DESTROY             WM_DESTROY           OnDestroy 



ON_WM_LBUTTONDOWN         WM_LBUTTONDOWN        OnLButtonDown 



ON_WM_LBUTTONUP           WM_LBUTTONUP          OnLButtonUp 



ON_WM_MOUSEMOVE           WM_MOUSEMOVE         OnMouseMove 



ON_WM_PAINT               WM_PAINT              OnPaint 



。。。 



                                                                                 395 


…………………………………………………………Page 458……………………………………………………………

                第篇    湷觥 FC  程式設計 



                ■  命令消息(WM_MAND)的一般性对映规则是: 



                    ON_MAND(;) 



                例如: 



                   ON_MAND(IDM_ABOUT; OnAbout) 



                   ON_MAND(IDM_FILENEW; OnFileNew) 



                   ON_MAND(IDM_FILEOPEN; OnFileOpen) 



                   ON_MAND(IDM_FILESAVE; OnFileSave) 



                ■   「Notification 消息」(由控制组件产生,例如BN_xxx )的对映机制的宏分 



                    为好几种(因为控制组件本就分为好几种),以下各举一例做代表: 



                 控制组件         宏名称                       消息处理函数 



                Button    ON_BN_CLICKED(;) memberFxn 



                boBox  ON_CBN_DBLCLK(;) memberFxn 



                Edit      ON_EN_SETFOCUS(;) memberFxn 



                ListBox   ON_LBN_DBLCLK(;) memberFxn 



                 各个消息处理函数均应以afx_msg void 为函数型式。 



                 为什么经过这样的宏之后,消息就会自动流往指定的函数去呢?谜底在于Message Ma
返回目录 上一页 下一页 回到顶部 9 10
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!