天天看點

文檔類CDocument,子架構類CFrameWnd及視圖類CView的關系及怎樣互相調用

文檔類、子架構類及視圖類的關系及如何互相調用 收藏 

了解文檔和視圖的互相作用關系是編寫mfc程式的基本功。但是mfc的應用程式架構把文檔和視圖之間的關系封裝了起來,初學的朋友往往不得要領,是以寫程式往往被局限于在用向導生成的架構中。本文希望能夠盡可能說明白文檔視圖架構之間是如何進行作用,希望能給一些朋友帶來小小的幫助。   

  幾個概念:   

  (雖然大家都知道了,雷神還是要重申一次)   

  文檔對象:是用來儲存資料的。   

  視圖對象:是用來顯示和編輯資料的。   

  應用程式架構:架構是用來管理不同文檔顯示界面的。例如你有一個資料網格顯示界面,還有一個圖形顯示界面,它們的資料可能都來自你的文檔,但是視圖不同,怎麼辦用架構。為什麼不用視圖?為的是把界面管理獨立的拿出來。   

  文檔模闆:mfc把文檔/視圖/架構視為一體,隻要你建立文檔/視圖架構結構的程式,必定會為你建立這三個類。這個工作在在應用程式初始化時完成,如下:   

  bool   cmyhtmlapp::initinstance()   

  {   

  //。。。。。。   

  csingledoctemplate*   pdoctemplate;   

  pdoctemplate   =   new   csingledoctemplate(   

  idr_mainframe,   

  runtime_class(cmyhtmldoc),   

  runtime_class(cmainframe),               //   main   sdi   frame   window   

  runtime_class(cmyhtmlview));   

  adddoctemplate(pdoctemplate);   

  //。。。。。。   

  }   

  單文檔:就是一次隻能打開一個檔案,和你的文檔類型支援的多少無關。你完全可以做一個單文檔的支援所有圖象格式的程式,隻不過它一次隻能打開一個文檔罷了。   

  多文檔:就是你可以打開多個檔案,和文檔類型也無關。你也可以作一個可以同時打開多個文檔的程式,但它隻支援一種文檔類型。   

  何時需要文檔/視圖架構結構?   

  首先你可以不使用文檔視圖這種架構結構,即便是在mfc中。你可以在你需要的時候選擇使用這種方式。你可以完成一個隻有視圖沒有文檔的程式,例如一個基于對話框的應用。   

  哪什麼時候需要呢?   

  當你想将你的資料層和界面層分開的時候。   

  通常我們對資料的操作放在文檔類中,例如存取,打開,關閉。在這裡你可以盡情的對你的資料進行操作,假如你需要,在對資料進行了改變後,對視圖做一下更新,那麼程式會将你對資料所做的改變呈現給你的程式的使用者。由此可見視圖的作用就是提供一個使用者和資料之間進行資料交換的界面,它的作用就是在需要的時候顯示資料,并在需要的時候提供輸入界面。當使用者輸入後實際的資料操作工作是由文檔類來做的。那架構類有在做什麼呢?   

  架構類是為了便于管理你的文檔類和視圖類而存在的。通常我們的操作都是通過視圖視窗完成,消息由視圖進行接收并且進行處理。是以消息映射定義一般在視圖中。但假如一個應用同時擁有多個視圖而目前活動視圖沒有對消息進行處理則消息會發往架構視窗。另外架構視窗可以友善的處理非視窗消息。   

  再來說一邊典型的單文檔程式的生成過程(不完整,隻挑有用的)   

  1、   cwinapp對象被建立,這個對象是全局的且隻能有一個,名字叫theapp。這時你可以完成一些工作,例如對系統資料庫的操作,(假如你想寫一個不修改系統資料庫的軟體,需要在這裡做寫工作)   

  2、   在initinstance()函數中建立文檔模闆,文檔模闆以cruntimclass靜态成員指針做構造參數。   

  3、   執行mfc架構預設的指令行參數。指令行參數有很多其中之一是,cmd1它會建立一個新檔案。(假如沒有指令行參數則執行預設的id_file_new)   

  4、   文檔模闆的執行個體根據三個類的動态建立資訊建立出文檔、視圖、架構。   

  5、   對文檔、視圖、架構進行初始化。   

  我們對文檔,視圖,架構如何産生以及他們的用途有了一定的了解,如何有效的使用它們呢。   

  文檔,視圖,架構之間的互相作用。   

  由上面的典型的單文檔程式的生成過程可以看出一個完整的應用一般由四個類組成:cwinapp應用類,cframewnd架構類,cdocument文檔類,cview視圖類。我将四個類常用的成員函數列出,大家一看便知。不過參數,傳回值均未列出,大家可以從msdn上了解更多。幾個重要的虛函數也未做說明。大家自己看吧。   

  通過全局函數afxgetapp可以得到cwinapp應用類的全局對象theapp.   

  cwinapp   

  資料成員:   

  m_pszappname   應用程式名稱   

  m_pszexename   可執行檔案的名稱   

  m_pszprofilename   ini檔案的名   

  m_pszregistrykey   系統資料庫或ini檔案的key   

  m_hinstance   執行個體的句柄   

  m_pmainwnd   為架構視窗指針   

  成員函數:   

  initinstance()     //初始化   

  parsecommandline()   //完成指令行的解析處理   

  cframewnd   

  getactivedocument()   //得到目前活動文檔指針   

  getactiveview()   //得到目前活動視圖指針   

  setactiveview()   //設定目前視圖為活動視圖   

  cdocument   

  onnewdocument()   

  onopendocument()   

  onsavedocument()   

  onfileclose()   

  //以上是用來對文檔的操作   

  getfirstviewposition()   //文檔對象連結清單中的第一個文檔位置   

  getnextview()   //下一個   

  //以上是用來周遊所有和文檔關聯的視圖   

  getdoctemplate()得到文檔模闆指針   

  addview()   //增加一個視圖   

  removeview()   //删除一個視圖   

  updateallview()   //更新所有視圖   

  cview   

  getdocument()得到對應的文檔指針     

  其他的就不列出了,大家還是看msdn。你可以直接檢視cwinapp應用類,cframewnd架構類,cdocument文檔類,cview視圖類的類成員。   

  最後說說幾個常見到的問題。   

  1,為什麼在對話框的應用程式中沒有發現文檔模闆?   

  預設的對話框程式沒有使用文檔/視圖架構結構。   

  2 ,假如我使用資料庫作為資料源是否意味着可以不需要文檔類?   

  看你自己,但是我建議使用。因為可以文檔,視圖這一個清楚友善的架構結構,以及友善完成三者之間的互相作用。  

------------------------------------------------------------------------------------------------------------

架構、文檔、視圖類之間的調用關系

1、主架構(cframewnd)中通路視圖(cview)

  cview* getactiveview() const;

  通常定義的視圖為cview的派生類,在調用自定義視圖對象的方法時

應該這樣寫:((cmousekeyview*)getactiveview())->myfunc();

2、主架構(cframewnd)中通路文檔(cdocument)

  getactivedocument,傳回cdocument對象;

3、在視圖(cview)中通路文檔(cdocument)

  inline cmousekeydoc* cmousekeyview::getdocument()

    {return (cmousekeydoc*)m_pdocument;}

4、在視圖(cview)中通路架構(cframewnd)

  cframewnd* getparentframe() const;

5、在文檔(cdocument)中通路架構(cframewnd)

  cwnd* afxgetmainwnd();

  cwnd* afxgetapp()->m_pmainwnd;

6、在文檔(cdocument)中通路視圖(cview)

  updateallviews

  功能:通知所有的視圖文檔已被修改的資訊

  原型:

    void updateallviews(

      cview* psender,  // 要更新的視圖指針,假如希望更新所有視

圖,将此參數設為null

      lparam lhint=0l, // 包含更改消息的通知

      cobject* phint=null // 保管更改消息的對象

    }

7、在其他類中通路文檔類(cdocument)

  cdocument* getdocument()

  {

    cframewnd* frm=(cframewnd*)::afxgetmainwnd();

    assert(frm);

    cdocument* pdoc=frm->getactivedocument();

    assert(pdoc);

    assert(pdoc->iskindof(runtime_class(cmousekeydoc)));

    return (cmousekeydoc*)pdoc;

  }

[注:資料轉載自網上]

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

  mfc中文檔和視圖的關系 收藏 

1、應用程式對象有一個文檔模闆管理器cdocmanager* m_pdocmanager(第一次調用adddoctemplate時new出來)

2、文檔模闆管理器有一個文檔模闆對象清單cptrlist m_templatelist(adddoctemplate 函數負責添加該清單)

3、文檔模闆對象擁有文檔、視圖、架構的靜态cruntimeclass成員指針用于動态建立,還有一個m_nidresource用來表示應采用的ui對象

4、每個文檔模闆對象擁有 m_ponlydoc 或 m_doclist (文檔指針或文檔指針清單),onfilenew 和 onfileopen都調用文檔模闆對象的opendocumentfile,opendocumentfile 調用文檔模闆的 createnewdocument,createnewdocument再調用文檔模闆的 adddocument 填充該文檔清單或文檔指針

5、文檔對象有一個文檔模闆指針 m_pdoctemplate (回指文檔對象所屬模闆對象).同上,也是文檔模闆的 adddocument 成員函數把 this 指針(文檔模闆自身).塞給剛剛建立的文檔對象

6、文檔對象有一個 m_viewlist(視圖清單),onfilenew 和 onfileopen 都調用文檔模闆對象的opendocumentfile,該函數調用 createnewdocument 建立文檔,然後調用 createnewframe 建立架構對象.

    createnewframe 構造ccreatecontext對象

    ccreatecontext兩個重要字段:(1)剛建立的文檔指針(2)視圖的cruntimeclass指針

    createnewframe 建立架構對象後由該對象調用 loadframe

    loadframe 的最後一個參數即為 ccreatecontext 指針

    loadframe 調用 create,create 再調用 createex 最後一個參數均為此ccreatecontext指針

    create的調用由消息映射表引發cframewnd::oncreate被調用

    oncreate的lpcreatestruct的一個字段lpcreateparams 仍然是這個ccreatecontext指針

    則在cframe::oncreate中,由這個ccreatecontext的cruntimeclass(視圖的)來調用createobject

    産生視圖對象後,由該對象調用create(最後一個參數仍然是這個ccreatecontext指針)

    視圖對象的create由消息映射表引發視圖對象的oncreate被調用

    視圖的oncreate的參數 lpcreatestruct 的 lpcreateparams 還是這個ccreatecontext指針)

    于是利用 ccreatecontext 的成員 m_pcurrentdoc (目前文檔)

    來調用 cdocument::addview 把視圖加入文檔的視圖清單

7、視圖有一個文檔指針m_pdocument (指向所屬文檔)

    同上,也是cdocument::addview函數初始化的,如下所示:

    pview->m_pdocument = this;

8、架構有一個m_pviewactive(活動視圖)

    由架構的setactiveview進行設定

繼續閱讀