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

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

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



                                        IDR_SCRIBTYPE; 

                                        RUNTIME_CLASS(CScribbleDoc); 

                                        RUNTIME_CLASS(CChildFrame); 

                                        RUNTIME_CLASS(CScribbleView)); 

                                AddDocTemplate(pDocTemplate); 

                                。。。 

                        } 



                        想一想文件是怎么开启的:使用者选按【File/New 】或【File/Open 】(前者开启一份空文 



                        件,后者读档放到文件中),然后在View 窗口内展现出来。我们很容易误以为是CWinApp 



                        直接产生Document : 



                        BEGIN_MESSAGE_MAP(CScribbleApp; CWinApp) 

                                ON_MAND(ID_APP_ABOUT; OnAppAbout) 

                                ON_MAND(ID_FILE_NEW; CWinApp::OnFileNew) 

                                ON_MAND(ID_FILE_OPEN; CWinApp::OnFileOpen) 

                                ON_MAND(ID_FILE_PRINT_SETUP; CWinApp::OnFilePrintSetup) 

                        END_MESSAGE_MAP() 



                        其实才不,是Document Template  的杰作: 



460 


…………………………………………………………Page 523……………………………………………………………

                                          第8章    Document…View  深入探討 



            【      】       【       】 

             File/New       File/Open 



          CWinApp 选择适当 的Document Template 



                        CMyDoc 



               构造Document 对象 

                                        CMyView 

                       CChildFrame   构造View 对象      Dynamic Creation 



               构造Frame  

                       窗口对象 



               产生Frame 窗口            产生View 窗口 



    如果是【File/Open】                          注意:或许你搞不清楚“构造View 对象”和 



                    读档                      “产生View 窗口”的关系。是这样的,View 



                                            窗口就是道道地地的Windows 窗口,而为了 

               将View 窗口初始化 

                                            对象管理,MFC 把View 窗口外包一个专属的 



                                            C++ 类别,那就是CView。所以当然是先构造 

               在View 中显示资料 

                                             (construct)一个View 对象,再由其构造式 



            图8…1 Document/View/Frame 的产生    产生(create)对应的View 窗口。Frame 物 



                                            件与Frame 窗口的关系亦复如此。 



图8…1 的灰色部份,正是Document Template 动态产生「三位一体之 



Document/View/Frame 」的行动。下面的流程以及MFC 源代码足以澄清一切疑虑。在 



CMultiDocTemplate::OpenDocumentFile (注)出现之前的所有流程,我只做文字叙述,不 



显示其源代码。本章稍后有一节「台面下的Serialize 读档奥秘」,则会将每一环节的原 



始码呈现在你眼前,让你无所挂虑。 



注:如果是SDI 程序,那么就是CSingleDocTemplate::OpenDocumentFile 被调用。但「多」 



比「单」有趣,而且本书范例Scribble 程序也使用CMultiDocTemplate,所以我就以此 



为说明对象。 



CSingleDocTemplate 只支持一种文件类型,所以它的成员变量是: 



                                                                      461 


…………………………………………………………Page 524……………………………………………………………

                     第篇    深入  MFC  程式設計 



                     class CSingleDocTemplate : public CDocTemplate 

                     { 

                     。。。 

                     protected:  // standard implementation 

                             CDocument* m_pOnlyDoc; 

                     }; 



                     CMultiDocTemplate 支持多种文件类型,所以它的成员变量是: 



                     class CMultiDocTemplate : public CDocTemplate 

                     { 

                     。。。 

                     protected:  // standard implementation 

                             CPtrList m_docList; 

                     }; 



                     当使用者选按【File/New 】命令项,根据AppWizard 为我们所做的Message Map ,此一 



                     命令由CWinApp::OnFileNew 接手处理。后者调用CDocManager ::OnFileNew,后者再呼 



                     叫CWinApp::OpenDocumentFile,后者再调用CDocManager ::OpenDocumentFile,后者 



                     再调用CMultiDocTemplate::OpenDocumentFile     (这是观察MFC 源代码所得结果): 



                     // in AFXWIN。H 

                     class CDocTemplate : public CCmdTarget 

                     { 

                       。。。 

                             UINT m_nIDResource;            // IDR_ for frame/menu/accel as well 

                             CRuntimeClass* m_pDocClass;    // class for creating new documents 

                             CRuntimeClass* m_pFrameClass;  // class for creating new frames 

                             CRuntimeClass* m_pViewClass;   // class for creating new views 

                             CString m_strDocStrings;       // 'n' separated names 

                       。。。 

                     } 



                     // in DOCMULTI。CPP 

                     CDocument* CMultiDocTemplate::OpenDocumentFile (LPCTSTR lpszPathName; 

                             BOOL bMakeVisible) 

                     { 

                             CDocument* pDocument = CreateNewDocument (); 

                             。。。 

                             CFrameWnd* pFrame = CreateNewFrame (pDocument; NULL); 

                             。。。 

                             if (lpszPathName == NULL) 

                             { 

                                     // create a new document with default document name 



462 


…………………………………………………………Page 525……………………………………………………………

                                                       第8章    Document…View  深入探討 



                。。。 

        } 

        else 

        { 

                // open an existing document 

                。。。 

        } 

        InitialUpdateFrame(pFrame; pDocument; bMakeVisible); 

        return pDocument; 

} 



顾名思义,我们很容易作出这样的联想:CreateNewDocument 动态产生Document , 



 CreateNewFrame 动态产生Document Frame 。的确是这样没错,它们利用CRuntimeClass 



 的CreateObject 做「动态生成」动作: 



// in DOCTEMPL。CPP 

CDocument* CDocTemplate::CreateNewDocument () 

{ 

        。。。 

        CDocument* pDocument = (CDocument*)m_pDocClass…》CreateObject (); 

        。。。 

        AddDocument(pDocument); 

        return pDocument; 

} 



CFrameWnd* CDocTemplate::CreateNewFrame (CDocument* pDoc; CFrameWnd* pOther) 

{ 

        // create a frame wired to the specified document 

        CCreateContext context; 

        context。m_pCurrentFrame = pOther; 

        context。m_pCurrentDoc = pDoc; 

        context。m_pNewViewClass = m_pViewClass; 

        context。m_pNewDocTemplate = this; 

        。。。 

        CFrameWnd* pFrame = (CFrameWnd*)m_pFrameClass…》CreateObject (); 

        。。。 

        // create new from resource 

        pFrame…》LoadFrame (m_nIDResource; 

                WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE; // default frame styles 

                NULL; &context) 

        。。。 

        return pFrame; 

} 



在CreateNewFrame 函数中, 不仅Frame 被动态生成出来了,其对应窗口也以 



                                                                                            463 


…………………………………………………………Page 526……………………………………………………………

                   第篇    深入  MFC  程式設計 



                   LoadFrame 产生出来了。但有两件事情令人不解。第一,我们没有看到View  的动态生 



                    成动作;第二,出现一个奇怪的家伙CCreateContext,而前一个不解似乎能够着落到这 



                    个奇怪家伙的身上,因为CDocTemplate::m_pViewClass 被塞到它的一个字段中。 



                    但是线索似乎已经中断,因为我们已经看不到任何可能的调用动作了。等一等!context 被 



                    用作LoadFrame  的最后一个参数,这意味什么?还记得第六章「CFrameWnd::Create 产 



                    生主窗口(并先注册窗口类别)」那一节提过Create 的最后一个参数吗,正是这context 。 



                    那么,是不是Document Frame 窗口产生之际由于WM_CREATE 的发生而刺激了什么动 



                    作? 



                    虽然其结果是正确的,但这样的联想也未免太天马行空了些。我只能说,经验累积出判 



                    断力!是的,WM_CREATE 引发CFrameWnd::OnCreate 被唤起,下面是相关的调用次序 



                     (经观察MFC 源代码而得知): 



                                                 CFrameWnd::OnCreate 

                                                  CFrameWnd::OnCreate 



                                               CFrameWnd::OnCreateHelper 

                                               CFrameWnd::OnCreateHelper 



                                               CFrameWnd::OnCreateClient 

                                                CFrameWnd::OnCreateClient 



                                                 CFrameWnd::CreateView 

                                                 CFrameWnd::CreateView 



                    // in WINFRM。CPP 

                   CWnd* CFrameWnd::CreateView(CCreateContext* pContext; UINT nID) 

                    { 

                           。。。 

                           CWnd* pView = (CWnd*)pContext…》m_pNewViewClass…》CreateObject (); 

                           。。。 

                           // views are always created with a border! 

                           pView…》Create (NULL; NULL; AFX_WS_DEFAULT_VIEW; 

                                         CRect(0;0;0;0); this; nID; pContext)) 

                           。。。 

                           if (afxData。bWin4 && (pView…》GetExStyle() & WS_EX_CLIENTEDGE)) 

                           { 



464 


…………………………………………………………Page 527……………………………………………………………

                                                  第8章    Document…View  深入探討 



                 // remove the 3d style from the frame; since the view is 

                 //  providing it。 

                 // make sure to recalc the non…client area 

                 ModifyStyleEx(WS_EX_CLIENTEDGE; 0; SWP_FRAMECHANGED); 

         } 

         return pView; 

 } 



不仅View 对象被动态生成出来了,其对应的实际Windows 窗口也以Create 函数产生出 



来。 



正因为MFC 把View 对象的动态生成动作包装得如此诡谲奇险,所以我才在图8…1 中 



把「构造View 对象」和「产生View 窗口」这两个动作特别另立一旁: 



     构造Document 对象 



                              构造View 对象 

     构造Frame 窗口对象 



     产生Frame 窗口               产生View 窗口 



                                                                                  465 


…………………………………………………………Page 528……………………………………………………………

                 第篇    深入  MFC  程式設計 



                     图8…2 解释CDocTemplate、CDocument、CView、CFrameWnd 之间的关系。下面则是 



                     一份文字整理: 



                     ■  CWinApp 拥有一个对象指针:CDocManager* m_pDocManager 。 



                     ■  CDocManager 拥有一个指针串行CPtrList m_templateList, 用来维护一系列的 



                       Document Template。一个程序若支持两「种」文件类型,就应该有两份Document 



                       Templates ,应用程序应该在CMyWinApp ::InitInstance  中以AddDocTemplate 将 



                       这些Document Templates 加入由CDocManager 所维护的串行之中。 



                     ■  CDocTemplate 拥有三个成员变量, 分别持有Document  、View 、Frame  的 



                       CRumtimeClass 指针,另有一个成员变量m_nIDResource ,用来表示此Document 



                       显现时应该采用的UI 对象。这四份资料应该在CMyWinApp::InitInstance  函数 



                       构造CDocTemplate  (注1)时指定之,成为构造式的参数。当使用者欲打开一 



                       份文件(通常是借着【File/Open 】或【File/New 】命令项),CDocTemplate 即 



                       可藉由Document/View/Frame 之CRuntimeClass 指针(注2 )进行动态生成。 



                     注1:在此我们必须有所选择,要不就使用CSingleDocTemplate,要不就使用 



                     CMultiDocTemplate , 两者都是CDocTemplate 的衍生类别。如果你选用 



                     CSingleDocTemplate,它有一个成员变量CDocument* m_pOnlyDoc,亦即它一次只能 



                     打开一份Document 。如果你选用CMultiDocTemplate,它有一个成员变量CPtrList 



                     m_docList,表示它能同时打开多个Documents 。 



                     注2 :关于CRuntimeClass 与动态生成,我在第3章已经以DOS 程序仿真之,本章 



                     稍后亦另有说明。 



                     ■  CDocument 有一个成员变量CDocTemplate* m_pDocTemplate,回指其Document 



                       Template;另有一个成员变量CPtrList m_viewList,表示它可以同时维护一系列 



                       的Views 。 



                     ■  CFrameWnd 有一个成员变量CView* m_pViewActive  ,指向目前正作用中的 



                       Vie。w 



                     ■  CView 有一个成员变量CDocument* m_pDocument,指向相关的Document 。 



466 


…………………………………………………………Page 529……………………………………………………………

                                                                                               第8章    Document…View  深入探討 



                           CWinApp                                                CDocManager 



               CDocManager* m_pDocManager;                                   CPtrList m_templateList; 



                  My。RC 



      IDR_SCRIBBTYPE ICON 〃。。。〃 

      IDR_SCRIBBTYPE MENU                                        Document Template 

      { 。。。 }                                                UINT m_nIDResource;                                           Document Template 

      STRINGTABLE 

      BEGIN                                                  CRuntimeClass* m_pDocClass; 

                                                             CRuntimeClass* m_pFrameClass; 

        IDR_SCRIBBTYPE 

          “。。。n。。。n 。。。n 。。。n 。。。n 。。。n 。。。”           CRuntimeClass* m_pViewClass; 



      END 



                                                              CDocument* m_pOnlyDoc; 



   CObject::classCObject CCmdTarget::classCCmdTargetCThreadApp::classCThreadApp 

     “CObject”      “CCmdTarget”     “CWinThread”             // in CSingleDocTemplate 

       4                4               4 



                                                              or 

   m_pfnConstruct   m_pfnConstruct  m_pfnConstruct 



    m_pNextClass    m_pNextClass     m_pNextClass             CPtrList m_docList; 

 NULL 



   CFrameWnd::classCFrameWndCWnd::classCWnd CWinApp::classCWinApp // in CMultiDocTemplate 

    “CFrameWnd”       “CWnd”          “CWinApp” 

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