午夜视频在线网站,日韩视频精品在线,中文字幕精品一区二区三区在线,在线播放精品,1024你懂我懂的旧版人,欧美日韩一级黄色片,一区二区三区在线观看视频

分享

MFC多文檔和單文檔視結(jié)構(gòu)

 haodafeng_org 2011-01-19

★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★

//這一頁的代碼最重要了,呵呵……什么都在這里面呢;


單文檔新建:CWinApp_________docManager->docSingleTemplate的 OpenDocumentFile函數(shù)參數(shù)為空,此函數(shù)完成了大部分東西,包括新建文檔類框架類等______________然后是調(diào)用CDocument就沒什么意思了,當(dāng)然我們要是重載了CDocument的新建函數(shù)就是調(diào)用子類虛函數(shù)。

多文檔新建:CWinApp_________docManager->docMultTemplate的 OpenDocumentFile函數(shù)參數(shù)為空,此函數(shù)完成了大部分東西,包括新建文檔類框架類等______________然后是調(diào)用CDocument就沒什么意思了,當(dāng)然我們要是重載了CDocument的新建函數(shù)就是調(diào)用子類虛函數(shù)。

單文檔打開:CWinApp_________docManager中經(jīng)過一個打開對話框傳遞參數(shù),中途還調(diào)用了APP的OpenDocumentFile,當(dāng)然如果我們的APP重載了這個函數(shù)也要調(diào)用我們的但是我們的函數(shù)一定別忘記最后返回是調(diào)用父類的此函數(shù)___________docSingleTemplate的 OpenDocumentFile函數(shù)參數(shù)不為空,此函數(shù)完成了大部分東西,包括新建文檔類框架類等______________然后是調(diào)用CDocument就沒什么意思了,當(dāng)然我們要是重載了CDocument的新建函數(shù)就是調(diào)用子類虛函數(shù)。

多文檔打開:CWinApp_________docManager中經(jīng)過一個打開對話框傳遞參數(shù),中途還調(diào)用了APP的OpenDocumentFile,當(dāng)然如果我們的APP重載了這個函數(shù)也要調(diào)用我們的但是我們的函數(shù)一定別忘記最后返回是調(diào)用父類的此函數(shù)___________docMultTemplate的 OpenDocumentFile函數(shù)參數(shù)不為空,此函數(shù)完成了大部分東西,包括新建文檔類框架類等______________然后是調(diào)用CDocument就沒什么意思了,當(dāng)然我們要是重載了CDocument的新建函數(shù)就是調(diào)用子類虛函數(shù)。

他們兩個只有在docMultTemplate和docSingleTemplate的 OpenDocumentFile函數(shù)中的動作不同,單文檔負責(zé)新建框架類和視類但是如果存在了我們就不重建了,只是給其賦值。而多文檔無論如何都會新建一個視類和框架類文檔類,這也就是為什么他是多文檔結(jié)構(gòu)的原因。

★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
接下來介紹這個最重要的函數(shù),它基本什么都干了,不管是新建還是打開都得調(diào)用它,呵呵……

//
CDocument* CMultiDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName,
 BOOL bMakeVisible)
{
 //下面調(diào)用的是CDocTemplate::CreateNewDocument()
 CDocument* pDocument = CreateNewDocument();//這里面調(diào)用了AddDocument(pDocument);
                                            //添加了一個CMyMultiTestDoc : public CDocument
                                                   //CMultiDocTemplate::m_docList保存的所有該種文檔的  
                                                   //文檔實例的指針列表。
 if (pDocument == NULL)
 {
  TRACE0("CDocTemplate::CreateNewDocument returned NULL.\n");
  AfxMessageBox(AFX_IDP_FAILED_TO_CREATE_DOC);
  return NULL;
 }
 ASSERT_VALID(pDocument);

 BOOL bAutoDelete = pDocument->m_bAutoDelete;
 pDocument->m_bAutoDelete = FALSE;   // don't destroy if something goes wrong
 CFrameWnd* pFrame = CreateNewFrame(pDocument, NULL);//創(chuàng)建了一個新的CChildFrame框架
 pDocument->m_bAutoDelete = bAutoDelete;
 if (pFrame == NULL)
 {
  AfxMessageBox(AFX_IDP_FAILED_TO_CREATE_DOC);
  delete pDocument;       // explicit delete on error
  return NULL;
 }
 ASSERT_VALID(pFrame);

 if (lpszPathName == NULL)
 {
  // create a new document - with default document name
  SetDefaultTitle(pDocument);

  // avoid creating temporary compound file when starting up invisible
  if (!bMakeVisible)
   pDocument->m_bEmbedded = TRUE;

  if (!pDocument->OnNewDocument())//剛打開時新建的文檔。add  by ralf
  {
   // user has be alerted to what failed in OnNewDocument
   TRACE0("CDocument::OnNewDocument returned FALSE.\n");
   pFrame->DestroyWindow();
   return NULL;
  }

  // it worked, now bump untitled count
  m_nUntitledCount++;
 }
 else
 {
  // open an existing document
  CWaitCursor wait;
  if (!pDocument->OnOpenDocument(lpszPathName))//這里是打開一個文檔。add  by ralf
  {
   // 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;
}
要了解   文檔、視圖、框架窗口、文檔模板之間的相互關(guān)系,關(guān)鍵要理解他們的結(jié)構(gòu)  
   
  1、首先應(yīng)該對   CWinApp類有充分的了解  
          它包含并管理著應(yīng)用程序的文檔/視窗的所有信息。它有一個成員變量    
          CDocManager   *   m_pDocManager,此變量是文檔/視窗的管理器,m_templateList  
          是CDocManager里的一個列表,此列表里保存了所有文檔模板的指針,當(dāng)用戶調(diào)用  
          CWinApp::AddDocTemplate(   pDocTemplate   )   后該pDocTemplate存入了  
          CWinApp::m_pDocManager::m_templateList里。  
          CWinApp::GetFirstDocTemplatePosition()  
          CWinApp::GetNextDocTemplate(POSITION&   pos)  
          是遍例所有的文檔模板指針。  
   
  2、上面我們提到了文檔模板(CMultiDocTemplate(我們主要針對對文檔)),  
          這是一個極重要的類。CMultiDocTemplate::m_docList保存的所有該種文檔的  
          文檔實例的指針列表。下面兩個函數(shù)用于維護CMultiDocTemplate::m_docList數(shù)據(jù)  
          CMultiDocTemplate::AddDocument(CDocument*   pDoc);  
          CMultiDocTemplate::RemoveDocument(CDocument*   pDoc);  
          而CMultiDocTemplate::GetFirstDocPosition()   const;  
          CMultiDocTemplate::CDocument*   GetNextDoc(POSITION&   rPos)   const;  
          用于遍例該文檔類型所有文檔實例。  
   
  3、上面提到文檔(CDocument)  
        CDocument   我們最熟悉不過了。每一個文檔實例可有多個視與之相對應(yīng)。  
        CDocument::m_viewList用來保存所有與此文檔實例相關(guān)的View 
★★★★這里我拉魯夫說一下:CDocument::AddView函數(shù)用來維護m_viewList數(shù)據(jù)但我們一般不用★★★★
        void CDocument::AddView(CView* pView)//★★★MFC源碼
       {
     ASSERT_VALID(pView);
     ASSERT(pView->m_pDocument == NULL); // must not be already attached
     ASSERT(m_viewList.Find(pView, NULL) == NULL);   // must not be in list

            m_viewList.AddTail(pView);
     ASSERT(pView->m_pDocument == NULL); // must be un-attached
     pView->m_pDocument = this;

     OnChangedViewList();    // must be the last thing done to the document
       }
        CDocument::GetDocTemplate   可獲得CMultiDocTemplate;  
  4、CView   他是放在CMDIChildWnd里的,每一個CMDIChildWnd有一個View  
        CView::GetDocument可獲得與此視相關(guān)的CDocument  
        CView::GetParentFrame()   可獲得CMDIChildWnd;  
   
  通過以上分析可見CWinApp,CMDIChildWnd,CView,CDocument,CMultiDocTemplate之間知道其中一個實例  
  必可知道其他所有幾個實例,CWinApp統(tǒng)領(lǐng)全局,任何時候,只要獲得CWinApp實例,則所有的文檔模板,  
  文檔實例,視,F(xiàn)rame窗口均可被枚舉出來。AfxGetApp()   獲得CWinApp實例指針。
★★★★★最后我介紹一個最重要的:其實我們一個文檔一般就對應(yīng)一個視圖!!!!!!!★★★★

——————————————————————————————————————————


 



獲得CWinApp

獲得CMainFrame

獲得CChildFrame

獲得CDocument

獲得CView

在CWinApp中

AfxGetMainWnd()

m_pMainWnd

AfxGetMainWnd()->MDIGetActive()

AfxGetMainWnd()->GetActiveFrame()

SDI:AfxGetMainWnd()->GetActiveView()->GetDocument()

MDI:AfxGetMainWnd()->MDIGetActive()->GetActiveView()->GetDocument()

SDI:AfxGetMainWnd()->GetActiveView()  
MDI:AfxGetMainWnd()->MDIGetActive()->GetActiveView()
在CMainFrame中

AfxGetApp()

theApp


MDIGetActive()

GetActiveFrame()

SDI:GetActiveView()->GetDocument()  
MDI:MDIGetActive()->GetActiveView()->GetDocument()  
SDI:GetActiveView()  
MDI:MDIGetActive()->GetActiveView()
在CChildFrame中

AfxGetApp()

theApp

GetParentFrame()
GetActiveView()->GetDocument()   GetActiveView()
在CDocument中

AfxGetApp()

theApp

AfxGetMainWnd()  

AfxGetMainWnd()->MDIGetActive()

AfxGetMainWnd()->GetActiveFrame()


POSITION   pos   =   GetFirstViewPosition();GetNextView(pos)  
在CView中

AfxGetApp()

theApp

AfxGetMainWnd()   GetParentFrame()   GetDocument()
在其他類中

AfxGetApp()

AfxGetMainWnd()  

AfxGetMainWnd()->MDIGetActive()

AfxGetMainWnd()->GetActiveFrame()

SDI:AfxGetMainWnd()->GetActiveView()->GetDocument()

MDI:AfxGetMainWnd()->MDIGetActive()->GetActiveView()->GetDocument()

SDI:AfxGetMainWnd()->GetActiveView()  
MDI:AfxGetMainWnd()->MDIGetActive()->GetActiveView()

理一理MFC的這幾個類的關(guān)系,可以很容易明白上面的這些亂七八糟的邏輯。
App是應(yīng)用域,所有的域中的東西都可以通過全局函數(shù)訪問到它。
MainFrame是主框架,也基本可以用全局函數(shù)訪問到。
MainFrame下是若干個ChildFrame,ChildFrame中若干個View和Document(可能不成對),ChildFrame管理著View,View和Document進行互操作。
因此整體框架就出來了,一般除了直接應(yīng)用的關(guān)系都可以通過MainFrame-->Active ChildFrame-->Active View-->Document這條線進行訪問
_______________________________

關(guān)于MFC下的文檔和視圖以及框架之間的訪問, 這些問題已經(jīng)是老生常談了,但我覺得還是都沒有詳細的說明,特

別是對于英語較差的人,我查看了一些blog,總結(jié)了一下!希望對和我一樣的人有點幫助!
一:
      1:   因為對于SDI程序,主框架窗口就是文檔框窗(如果這個也不知道,就要查看一下MFC下的單文檔的構(gòu)成原理了).
          下面所說的是關(guān)于單文檔的.          
         
        例子: 在CMainFrame框架中如何得到視圖類的指針.
                    可以 先得到框架指針,然后調(diào)用 GetActiveView 函數(shù)指向當(dāng)前活動視.
C **View * pView;
                 pView=(C**View*)((CFrameWnd*)AfxGetApp()->m_pMainWnd)->GetActiveView();

          當(dāng)然這些也許都知道是這么用的,但真正的m_pMainWnd和AfxGetApp()是什么意思也許有的人不明白.
         大家也許都知道如何在App中獲得MainFrame指針(框架類): CWinApp 中的 m_pMainWnd變量就是CMainFrame的指針.

   所以在別的類下也可以先得到m_pMainWnd,就得到了MainFrame的指針. 所以得到視圖類的指針,必先 得到CFrameWnd的指針m_pMainWnd,然后在調(diào)用FrameWnd下的GetActiveView 就指向當(dāng)前活動視.
m_pMainWnd的由來:
      每一個MFC應(yīng)用程序都有一個CWinApp派生類的對象。這個對象對應(yīng)著程序的主線程。而 CWinApp 類中有一個 CWnd * m_pMainWnd 成員變量。這個成員變量記錄了應(yīng)用程序的主窗口。
當(dāng)你新建一個MFC應(yīng)用程序的時候,在 InitInstance虛函數(shù)里都會出現(xiàn)對 m_pMainWnd 賦值的語句.唯一的例外是單文檔界面的MFC應(yīng)用程序,你無法在 InitInstance 函數(shù)里看到這段代碼,因為它已經(jīng)被隱藏在 ProcessShellCommand 這個函數(shù)里了。由此你就可以下結(jié)論了:只要創(chuàng)建自己的窗口類,就要把這個類的對象賦值給 m_pMainWnd .而這個成員只能在C**APP類中才可以使用,所以怎樣使用這個CWinApp類里的CWnd 類型的變量來得到主框架窗口的指針呢??
AfxGetApp函數(shù)才可以 , 因為AfxGetApp()得到的是CWinApp類的對象,且AfxGetApp返回值為CWinApp對象指針,就是MFC生成的C**App.cpp中定義的那個對象(對象theApp的指針)。
因為你是在自己創(chuàng)建的項目中得到CWndApp成員函數(shù)或者成員變量,所以你必須強制轉(zhuǎn)換為你自己的項目中的類,才能找到成員函數(shù)或者變量.
注: 在單文檔中,獲得視指針的最簡單的方法還是
((C**View *)CFrameWnd::GetActiveView())
             
          2:     當(dāng)然在FrameWnd中也可以得到文檔類的指針:
                       CMyDocument* pDoc;
                       pDoc=(CMyDocument*)((CFrameWnd*)AfxGetApp()->m_pMainWnd)->GetActiveDocument();
        
          3:     由上面可以知道:在View中怎樣獲得MainFrame指針
CMainFrame *pMain=(CMainFrame *)AfxGetApp()->m_pMainWnd;

注: 從視圖類中獲得主幀窗口類指針:用函數(shù):CWnd::GetParentFrame()或AfxGetMainWnd()也
可達到目的。GetParentFrame()的工作原理是在父窗口鏈中搜索,直到找到CFrameWnd或其派生類為止,并返回其指針。

((CMainFrame *)CWnd::GetParentFrame())
或者
((CMainFrame *)AfxGetMainWnd())
        
二:
當(dāng)然對于MDI程序,由于子窗口才是文檔框窗,因此首先要用GetActiveFrame()取得活動子框架窗口,然后通過該子窗口獲取活動視圖和文檔:

                 CMDIChildWnd* pChild=(CMDIChildWnd*)((CFrameWnd*)AfxGetApp()->m_pMainWnd)-            

        >GetActiveFrame();
取得活動視圖:
CMyView* pView=(CMyView*)pChild->GetActiveView();

取得活動文檔:
CMyDocument* pDoc=pChild->GetActiveDocument();


注: 也可以用這種方法來得到多文檔中的視指針
//獲得活動子框架窗口
CMDIChildWnd* pChild=(CMDIChildWnd*)GetActiveFrame();
//或:
CMDIChildWnd* pChild=MDIGetActive();
//獲得活動子幀窗口的活動視圖
CMyView* pView=(CMyView*)pChild->GetActiveView();


三:
1.   從視圖類獲得文檔類的指針
            在視圖類中需要引用文檔類的地方之前,使用以下語句:
C*Doc *pDoc=(C*Doc*)GetDocument();
以后便可使用pDoc指針訪問文檔類。
2.    從文檔類取得視圖類的指針 CDocument類提供了兩個函數(shù)用于視圖類的定位:

   GetFirstViewPosition()和GetNextView()

注意:GetNextView()括號中的參數(shù)用的是引用方式,因此執(zhí)行后值可能改變.GetFirstViewPosition()用于

返 回第一個視圖位置(返回的并非視圖類指針,而是一個POSITION類型值),GetNextView()有兩個功能:返回下一個視圖類的指針以及用引用 調(diào)動的方式來改變傳入的POSITION類型參數(shù)的值。很明顯,在Test程序中,只有一個視圖類,因此只需將這兩個函數(shù)調(diào)用一次即可得到 CTestView的指針如下(需定義一個POSITION結(jié)構(gòu)變量來輔助操作):

    C*View* pView;
POSITION pos=GetFirstViewPosition();
pView=GetNextView(pos);

這 樣,便可到了C*View類的指針pView.執(zhí)行完成幾句后,變量pos=NULL,因為沒有下一個視圖類,自然也沒有下一個視圖類的 POSITION.但是之幾條語句太簡單,不具有太強的通用性和安全特征;當(dāng)象前面說的那樣,當(dāng)要在多個視圖為中返回某個指定類的指針時,我們需要遍歷所 有視圖類,直到找到指定類為止。判斷一個類指針指向的是否某個類的實例時,可用IsKindOf()成員函數(shù)時行檢查.

如:
pView->IsKindOf(RUNTIME_CLASS(C*View));
即可檢查pView所指是否是C*View類。
有了以上基礎(chǔ),我們已經(jīng)可以從文檔類取得任何類的指針。為了方便,我們將其作為一個文檔類的成員函數(shù),它有一個參數(shù),表示要獲得哪個類的指針。實現(xiàn)如下:
          CView* C*Doc::GetVieww(CRuntimeClass* pClass)
{ CView* pView;
POSITION pos=GetFirstViewPosition();
while(pos!=NULL){
pView=GetNextView(pos);
if(!pView->IsKindOf(pClass))
break;}
if(!pView->IsKindOf(pClass)){
AfxMessageBox("Connt Locate the View.");
return NULL;}
return pView;}
其中用了兩次視圖類的成員函數(shù)IsKindOf()來判斷,是因為退出while循環(huán)有三種可能:
1.pos為NULL,即已經(jīng)不存在下一個視圖類供操作;
2.pView已符合要求。
3.1 和2同是滿足。這是因為GetNextView()的功能是將當(dāng)前視圖指針改變成一個視圖的位置同時返回當(dāng)前視圖指針,因此pos是pView的下一個視圖類的POSITION,完全有可能既是pos==NULL又是pView符合需要。當(dāng)所需的視圖是最后一個視圖是最后一個視圖類時就如引。因此需采用兩次判斷。
使用該函數(shù)應(yīng)遵循如下格式(以取得CTestView指針為例):
CTestView* pTestView=(CTestView*)GetView(RUNTIME_CLASS(CTestView));
RUNTIME_CLASS是一個宏,可以簡單地理解它的作用:將類的名字轉(zhuǎn)化為CRuntimeClass為指針。
至于強制類型轉(zhuǎn)換也是為了安全特性考慮的,因為從同一個基類之間的指針類型是互相兼容的。這種強制類型轉(zhuǎn)換也許并不必

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多