• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            (轉(zhuǎn))文檔/視圖結(jié)構(gòu)中的各個(gè)部分是如何聯(lián)系到一起的

            文檔/視圖結(jié)構(gòu)是MFC中最有特色而又有難度的部分,在這當(dāng)中涉及了應(yīng)用、文檔模板、文檔、視圖、MDI框架窗口、MDI子窗口等不同的對(duì)象,如果不了解 這些部分之間如何關(guān)聯(lián)的話,就可能犯錯(cuò)誤,也就很難編出有水平的文檔/視圖程序。比如我在初學(xué)VC編程的時(shí)候,為應(yīng)用程序添加了兩個(gè)文檔模板,兩個(gè)模板公 用一個(gè)文檔類,只是視圖不一樣,期望當(dāng)一個(gè)模板的文檔的視圖改變了文檔后,調(diào)用UpdateAllViews后也能更新另一個(gè)文檔模板的視圖,結(jié)果當(dāng)然是 不行的,原因就是對(duì)MFC的文檔/視圖結(jié)構(gòu)沒(méi)有深入的了解,了解的最好方法就是閱讀一下MFC的源代碼。下面就是我的筆記:

            (一)應(yīng)用程序?qū)ο笈c文檔模板之間的聯(lián)系:

                    首先,在應(yīng)用程序?qū)ο笾杏幸粋€(gè)CDocManager指針類型的共有數(shù)據(jù)成員m_pDocManager,在CDocManager中維護(hù)一個(gè) CPtrList類型的鏈表:m_tempateList,它是一個(gè)保護(hù)成員。InitInstance函數(shù)中調(diào)用CWinApp:: AddDocTemplate函數(shù),實(shí)際上是調(diào)用m_pDocManager的AddDocTemplate函數(shù)向鏈表m_templateList添加 模板指針。CWinApp提供了GetFirstDocTemplatePosition和GetNextDocTemplate函數(shù)實(shí)現(xiàn)對(duì) m_templateList鏈表的訪問(wèn)(實(shí)際上是調(diào)用了CDocManager的相關(guān)函數(shù))。

                     在文件操作方面CWinApp提供的最常用的功能是文件的新建(OnFileNew)和打開(kāi)(OnFileOpen),它也是調(diào)用CDocManager 類的同名函數(shù)。對(duì)于新建,一般的時(shí)候在只有一個(gè)文檔模板的時(shí)候,它新建一個(gè)空白的文件;如果有多個(gè)文檔模板的時(shí)候,它會(huì)出現(xiàn)一個(gè)對(duì)話框提示選擇文檔類型。 它的源代碼如下:

            void CDocManager::OnFileNew()

            {

                   if (m_templateList.IsEmpty())

                   {

                                            .......

                          return;

                   }

                            //取第一個(gè)文檔模板的指針

                   CDocTemplate* pTemplate = (CDocTemplate*)m_templateList.GetHead();

                   if (m_templateList.GetCount() > 1)

                   {

                          // 如果多于一個(gè)文檔模板,出現(xiàn)對(duì)話框提示用戶去選擇

                          CNewTypeDlg dlg(&m_templateList);

                          int nID = dlg.DoModal();

                          if (nID == IDOK)

                                 pTemplate = dlg.m_pSelectedTemplate;

                          else

                                 return;     // none - cancel operation

                   }

                            ......

                            //參數(shù)為NULL的時(shí)候OpenDocument File會(huì)新建一個(gè)文件

                   pTemplate->OpenDocumentFile(NULL);

            }

            打開(kāi)文件:

            void CDocManager::OnFileOpen()

            {

                   // 出現(xiàn)打開(kāi)文件對(duì)話框

                   CString newName;

                   if (!DoPromptFileName(newName, AFX_IDS_OPENFILE,

                     OFN_HIDEREADONLY | OFN_FILEMUSTEXIST, TRUE, NULL))

                          return; // open cancelled

                   AfxGetApp()->OpenDocumentFile(newName);          //實(shí)際也是調(diào)用文檔模板的同名函數(shù)

            }

            (二)文檔模板與文檔之間的聯(lián)系:

                    從上面看出應(yīng)用程序?qū)ο髮?duì)文件的新建和打開(kāi)是依靠文檔模板的OpenDocumentFile函數(shù)實(shí)現(xiàn)的。MFC的模板類是用來(lái)聯(lián)系文檔類、視類和框架類的,在它的構(gòu)造函數(shù)就需要這三者的信息:

            CDocTemplate ( UINT nIDResource, CRuntimeClass* pDocClass, CRuntimeClass* pFrameClass, CRuntimeClass* pViewClass );

            構(gòu)造函數(shù)利用后三個(gè)參數(shù)為它的三個(gè)CruntimeClass*類型的保護(hù)成員賦值:

                   m_pDocClass = pDocClass;

                   m_pFrameClass = pFrameClass;

                   m_pViewClass = pViewClass;

                文檔模板分為單文檔模板和多文檔模板兩種,這兩個(gè)模板的實(shí)現(xiàn)是不同的,除了上面的三個(gè)成員,內(nèi)部有彼此不相同的但是很重要的成員變量。對(duì)于多文檔模板: CPtrList m_docList;,單文檔模板:CDocument* m_pOnlyDoc;。它們都有一個(gè)成員函數(shù)AddDocument,分別各自的成員進(jìn)行賦值操作,而在它們的父類的CDocTemplate中則是為 它所添加的文檔的m_pDocTemplate變量賦值為模板自己的地址:

            void CDocTemplate::AddDocument(CDocument* pDoc)

            {

                   ASSERT_VALID(pDoc);

                   ASSERT(pDoc->m_pDocTemplate == NULL);  

                   pDoc->m_pDocTemplate = this;

            }

            由于單文檔模板只能擁有一個(gè)文檔,所以它只是維護(hù)一個(gè)指向自己所擁有的模板的指針:m_pOnlyDoc,AddDocument函數(shù)就是要為這個(gè)成員賦值:

            void CSingleDocTemplate::AddDocument(CDocument* pDoc)

            {

                            ......

                   CDocTemplate::AddDocument(pDoc);

                   m_pOnlyDoc = pDoc;

            }
            由于多文檔模板可以擁有多個(gè)文檔,所以它要維護(hù)的是包含它所打開(kāi)的所有文檔的指針的鏈表,所以它的AddDocument的實(shí)現(xiàn)為:

            void CMultiDocTemplate::AddDocument(CDocument* pDoc)

            {

                            ......

                   CDocTemplate::AddDocument(pDoc);

                   m_docList..AddTail(pDoc);

            }
                模板通過(guò)m_pOnlyDoc(單文檔)或記住了自己所擁有的所有的模板的指針,并通過(guò)GetFirstDocPosition和GetNextDoc函 數(shù)可以實(shí)現(xiàn)對(duì)它所擁有的文檔的訪問(wèn),同時(shí)使文檔記住了自己所屬文檔模板的指針,同時(shí)文檔提供了GetDocTemplate()函數(shù)可以取得它所屬的模 板。

            對(duì)AddDocument函數(shù)的調(diào)用主要是發(fā)生在另一個(gè)成員函數(shù)CreateNewDocument里,它的作用是創(chuàng)建一個(gè)新的文檔:

            CDocument* CDocTemplate::CreateNewDocument()

            {

                   if (m_pDocClass == NULL)

                   {

                     ……

                   }

                   CDocument* pDocument = (CDocument*)m_pDocClass->CreateObject();

                ……

                   AddDocument(pDocument);

                   return pDocument;

            }

            CreateNewDocument函數(shù)主要利用文檔類的運(yùn)行時(shí)指針的函數(shù)CreateObject創(chuàng)建一個(gè)新文檔對(duì)象,并利用AddDocument將其指針賦給相關(guān)的成員,留做以后使用。

                在應(yīng)用程序的OnFileNew和OnFileOpen函數(shù)都使用了模板的OpenDocumentFile函數(shù),而且在實(shí)際編程的時(shí)候也大都使用這個(gè)函 數(shù)。在MSDN的文檔說(shuō)這個(gè)函數(shù)當(dāng)參數(shù)不為NULL的時(shí)候打開(kāi)文件,否則就用上面所說(shuō)的CreateNewDocument函數(shù)創(chuàng)建一個(gè)新文檔,那么它是 如何實(shí)現(xiàn)的呢?

            CDocument* CSingleDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName,

                   BOOL bMakeVisible)

            {

                   CDocument* pDocument = NULL;

                   CFrameWnd* pFrame = NULL;

                   BOOL bCreated = FALSE;      // => doc and frame created

                   BOOL bWasModified = FALSE;

                //如果已經(jīng)有打開(kāi)的文檔,就會(huì)詢問(wèn)否保存文件

                   if (m_pOnlyDoc != NULL)

                   {

                          pDocument = m_pOnlyDoc;

                          if (!pDocument->SaveModified())

                                 return NULL;     

                          pFrame = (CFrameWnd*)AfxGetMainWnd();

                                            ......

                   }

                //創(chuàng)建新文件

                   else

                   {

                          pDocument = CreateNewDocument();

                          ASSERT(pFrame == NULL);    

                          bCreated = TRUE;

                   }

                            ......

                //如果第一次創(chuàng)建文檔則也要?jiǎng)?chuàng)建框架窗口。

                   if (pFrame == NULL)

                   {

                          ASSERT(bCreated);

                          // create frame - set as main document frame

                          BOOL bAutoDelete = pDocument->m_bAutoDelete;

                          pDocument->m_bAutoDelete = FALSE;

                          pFrame = CreateNewFrame(pDocument, NULL);

                          pDocument->m_bAutoDelete = bAutoDelete;

                                            ......

                   }

                   if (lpszPathName == NULL)

                   {

                          // 為新文檔設(shè)置默認(rèn)標(biāo)題

                          SetDefaultTitle(pDocument);

                    ……

                  //一般的時(shí)候重載OnNewDocument初始化一些數(shù)據(jù),如果返回FALSE,表示初始化失//敗,銷毀窗口。

                          if (!pDocument->OnNewDocument())

                          {

                                                            ......

                                 if (bCreated)

                                        pFrame->DestroyWindow();    // will destroy document

                                 return NULL;

                          }

                   }

                   else

                   {

                          CWaitCursor wait;

                          // open an existing document

                          bWasModified = pDocument->IsModified();

                          pDocument->SetModifiedFlag(FALSE);

                          //OnOpenDocument函數(shù)重新初始化文檔對(duì)象

                          if (!pDocument->OnOpenDocument(lpszPathName))

                          {

                                 if (bCreated)

                                 {

                            //新建文檔的情況

                                        pFrame->DestroyWindow();   

                                 }

                                 else if (!pDocument->IsModified())

                                 {

                                        // 文檔沒(méi)有被修改,恢復(fù)原來(lái)文檔的修改標(biāo)志

                                        pDocument->SetModifiedFlag(bWasModified);

                                 }

                                 else

                                 {

                                        // 修改了原始的文檔

                                        SetDefaultTitle(pDocument);

                                        if (!pDocument->OnNewDocument())

                                        {

                                               TRACE0("Error: OnNewDocument failed after trying to open a document - trying to continue.\n");

                                        }

                                 }

                                 return NULL;        // open failed

                          }

                          pDocument->SetPathName(lpszPathName);

                   }

                   CWinThread* pThread = AfxGetThread();

                   if (bCreated && pThread->m_pMainWnd == NULL)

                   {

                          pThread->m_pMainWnd = pFrame;

                   }

                   InitialUpdateFrame(pFrame, pDocument, bMakeVisible);

                   return pDocument;

            }

            以下是多文檔模板的OpenDocumentFile的實(shí)現(xiàn)

            CDocument* CMultiDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName,

                   BOOL bMakeVisible)

            {

                   //新建一個(gè)文檔對(duì)象

                   CDocument* pDocument = CreateNewDocument();

            ……

                   BOOL bAutoDelete = pDocument->m_bAutoDelete;

                   pDocument->m_bAutoDelete = FALSE;  

                   CFrameWnd* pFrame = CreateNewFrame(pDocument, NULL);

                   pDocument->m_bAutoDelete = bAutoDelete;

            ……

                   if (lpszPathName == NULL)

                //當(dāng)是新建的時(shí)候

                   {

                          SetDefaultTitle(pDocument);

                          // avoid creating temporary compound file when starting up invisible

                          if (!bMakeVisible)

                                 pDocument->m_bEmbedded = TRUE;

                          if (!pDocument->OnNewDocument())

                          {

                                 pFrame->DestroyWindow();

                                 return NULL;

                          }

                          m_nUntitledCount++;

                   }

                   else

                   {

                          // 打開(kāi)一個(gè)已經(jīng)存在的文件

                          CWaitCursor wait;

                          if (!pDocument->OnOpenDocument(lpszPathName))

                          {

                                 // user has be alerted to what failed in OnOpenDocument

                                 TRACE0("CDocument::OnOpenDocument returned FALSE.\n");

                                 pFrame->DestroyWindow();

                                 return NULL;

                          }

                          pDocument->SetPathName(lpszPathName);

                   }

                   InitialUpdateFrame(pFrame, pDocument, bMakeVisible);

                   return pDocument;

            }

                從上面看出模板類的OpenDocumentFile函數(shù)里,利用CreateNewDocument對(duì)象使文檔對(duì)象與模板對(duì)象建立了聯(lián)系,利用了CreateNewFrame函數(shù)使框架窗口與文檔、視圖、模板發(fā)生了聯(lián)系:

            posted on 2011-04-17 20:43 蝸牛也Coding 閱讀(489) 評(píng)論(0)  編輯 收藏 引用


            只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問(wèn)   Chat2DB   管理


            <2010年10月>
            262728293012
            3456789
            10111213141516
            17181920212223
            24252627282930
            31123456

            導(dǎo)航

            統(tǒng)計(jì)

            常用鏈接

            留言簿(8)

            隨筆檔案(78)

            搜索

            積分與排名

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

            少妇久久久久久久久久| 亚洲国产天堂久久综合网站| 性做久久久久久久久久久| 免费精品国产日韩热久久| 亚洲精品第一综合99久久 | a级毛片无码兔费真人久久| 国产精品免费久久久久久久久| 精品久久久无码中文字幕天天| 777午夜精品久久av蜜臀| 久久久久免费精品国产| 合区精品久久久中文字幕一区| 人妻精品久久久久中文字幕69| 久久这里只有精品久久| 久久精品国产亚洲AV影院| 99久久人妻无码精品系列 | 久久久久人妻一区精品果冻| 99久久无色码中文字幕人妻| 亚洲国产精品久久久久久| 久久久久波多野结衣高潮| 久久久久中文字幕| 无码超乳爆乳中文字幕久久| 国产一区二区精品久久凹凸| 99久久99久久久精品齐齐| 一本大道久久香蕉成人网| 久久国产精品免费一区二区三区| 亚洲av成人无码久久精品| 麻豆精品久久久久久久99蜜桃| 日本三级久久网| 丰满少妇高潮惨叫久久久| 7777精品久久久大香线蕉| 亚洲午夜精品久久久久久app| 亚洲午夜久久久精品影院| 久久精品一区二区| 国产精品一久久香蕉产线看| 亚洲国产精品高清久久久| 久久精品国产久精国产一老狼| 亚洲一级Av无码毛片久久精品| 欧美与黑人午夜性猛交久久久| 久久精品国产只有精品66| 久久免费视频一区| 中文成人久久久久影院免费观看|