随笔-19  评论-2  文章-0  trackbacks-0

2009-9-3

========================================================
《深入解析MFC》笔记 7.MFC的文档/视图结构
========================================================

文档/视图相互依赖关系
    · CWinApp包含一个 CDocManager 指针。
    · CDocManager 维护一个文档模板链表,须在 CWinApp::IniInstance()中 创建并加入这些模板。
    · 文档模板将这 3 个类绑定在一起: CView / CDocument / CFrameWnd。这些类都根据传递给文档模板构造函数的CRuntimeClass信息创建
    · MDI 专有的文档模板维护一个打开文档链表,而 SDI 专有的文档模板只有一个指向打开文档的指针。
    · 文档维护一个打开视图的链表。使用这个链表与视图通信、更新视图。
    · 文档有一个指针指向它们的文档模板。用这个指针设置标题,进行命令路由选择,在被删除时通知文档模板
    · 框架有一个指针指向当前的活跃视图
    · 被创建时,框架等到一个 CCreateContext 结构,包含了在文档模板中可以找到的CRuntimeClass信息和一个指向文档的指针。
    · 视图有一个指针指向它的文档。当该视图被删除时,用该指针通知文档。
    · 视图可以通过调用 CView::GetParentFrame() 获得它的框架窗口。
    · 如果文档要访问它的所有视图的框架,可以遍历它的视图链表,并调用 CView::GetParentFrame().

    · CDocTemplate —— 在 CWinApp 中创建,保存在 CWinApp::m_pDocManage中
    · CDocManager —— 在CWinApp::InitInstance() 中创建
    · CFrameWnd —— 在 CDocTemplate::CreateNewFrame() 中创建
    · CDocument —— 在 CDocTemplate::CreateNewDocument() 中创建
    · CView —— 通过 CFrameWnd::OnCreate() 创建
                                                         
     ID_FILE_OPEN   →   CWinApp::OnFileOpen()                      CWinApp::OnFileNew()     ←   ID_FILE_NEW    
          命令                                 ↓                                                         ↓                                
                                          获取文件名                                         一个文档模板?  →否→        从用户获取文档类型
                                                 ↓                                                          ↓                                               ↓
                                     使用文件拓展名,选择文档模板               是                                            ↓ 
                                                   ↓                                                         ↓                                            ↓
                                                    ------------------------------选择的模板-------------------------------
         
         
                   选择模板
                        ↓                                                               → →→打开? →→Yes→→  CMyDoc::OnOpenDocument()   →
     Construct document  object: CMyDoc                          ↑            ↓                                               ↓                                      ↓
                        ↓                                                               ↑            ↓                                               ↓                                      ↓                         
     Construct frame window object : CMainFrame             ↑              →→→→→→→CMyDoc::OnNewDocument()            ↓
                        ↓                                                               ↑                                                             ↓                                     ↓
          CframeWnd::Create()                                              ↑                                                     文档准备好   ←←←←←←                              
     CFrameWnd::OnCreateClient()                                    ↑
                        ↓                                                               ↑                                                                                                                   
             Create CMyView            →→→→→→→→→→→→                             选择模板之后的控制流程
         
         
           CWinApp::OnFileOpen()                                             CWinApp::OnFileNew()    
                         ↓                                                                                ↓
          CDocManager::OnFileOpen()                                   CDocManager::OnFileNew()
                                               ↓                                          ↓
                                           CDocTemplate::OpenDocumentFile()
                                           CDocTemplate::CreateNewDocument()
                                           CDocTemplate::CreateNewFrame()
                                                             WM_CREATE
                                                    CFrameWnd::OnCreate()
                                                CFrameWnd::OnCreateHelper()
                                                CFrameWnd::OnCreateClient()
                                                CFrameWnd::CreateView()
                                                CMyDocument::OnOpenDocument()
                                         [if file was specified to OpenDocumentFile()]
                                                CMyDocument::OnNewDocument()       
                                        创建文档/视图体系中所有对象过程中调用的函数
         
         
-----------
体系结构

    文档与视图
                    1)文档;   2)视图;   3)文档/视图框架;   4)文档模版
    文档
        由CDocument类体现,派生自CCmdTarget,具有CObject提供的所有支持,且可以接受命令消息,支持组件对象模型(COM)接口和 OLE 自动化。
    视图
       
    文档/视图框架
    文档模板                             《深入解析MFC》 P 198
        将整个机制绑定在一起。这3个组件由 CDocTemplate 的类管理。
        CDocTemplate是一个抽象基类,定义了处理文档、框架和视图的基本操作。
        CSingleDocTemplate:  4个参数①一个资源ID,②运行时的CDocument派生类;③ 运行时的试图框架; ④ 运行时的文档视图。
                    资源ID:①窗口标题;②文档名称;③当创建一个新文档时使用的文档类型描述符;④对标准的打开文件对话框中文件类型的描述符
                                 ⑤文档扩展名过滤器; ⑥ 文件管理器使用的文件类型描述符; ⑦ 在Windows注册表中注册的 ProgID。
        SMultiDocTemplage
                    可以支持一组文档的链表,而CSingleDocTemplate只能支持一种文档
                   
    CWinApp的角色
        文档模板由 CWinApp 对象管理。
       
---------------
文档/视图结构内幕                    《深入解析MFC》P 199
    ------------------------------------
    CWinApp 管理文档模板,文档模板管理 框架/视图/文档。
   
    CWinApp / CDocTemplate 接口: CDocManager
        · CPtrList  m_templateList —— 维护一个文档模板列表的指针。 通过GetFirstDocTemplatePosition()和GetNextDocTemplate()来遍历模板列表。
       
        CDocManager::OnFileNew() 
            负责创建一个新的文档模板
            · ①OnFileNew() 检查 m_templateList 中是是否有多于一个文档模板,若是,则创建一个 CNewTypeDlg 对话框,列出一个文档链表以供用户选择。
            · ② 调用CDocTemplate::OpenDocumentFile(),
                tag:CNewTypeDlg的构造函数读入一个指向文档模板指针链表的指针,即 m_templateList。在DoModal() 之后,OnFileNew()从
                        CNewTypeDlg::m_pSelectdeTemplate 中得到选中的对话框模板。
           
            CNewTypeDlg   (DOCMGR.CPP)
                CNewTypeDlg::OnInitDialog()
                    · ①, 调用GetDlgItem() 得到一个指向 CListBox 指针,并将之类型转换成 CListBox 指针。
                    · ②,得到指针后,遍历它的文档模板链表,遍历时,通过调用CDocTemplate::GetDocString()得到文档类型的字符串版本,
                            OnInitDialog获取每个文档的这个字符串并加入链表,再调用 CListBox::SetItemDataPtr() 将这个文档模板指针附加到这项上。
                    · ③,返回到CDialog::OnInitDialog()。
                        tag:在CNewType::OnOK()中,当用户选择从链表中选择了一项并按下OK按钮时, CNewType::OnOK() 从量表中得到被选中的项,并调用
                              CListBox::SetItemDataPtr() 获得指向该文档模板的一个指针。 OnOK() 将这个被选中的模板指针放在 pSelectedTemplate 中,这样,
                              DoModal() 返回后就可以获取这个指针
    ----------------------------------------                         
    CDocTemplate:  CDocument、CView 和 CFrameWnd 管理器
   
        · m_nIDResource —— 存储传给 CDocTemplate 构造函数的第一个参数,是一个资源ID,
        · m_pDocClass —— 指向该文档模板的CDocument(或派生类)的CRuntimeClass结构,在构造函数中设定
        · m_pFrameClass —— 指向该文档模板的 CFrameWnd(或派生类)的CRuntimeClass 结构。在构造函数中设定
        · m_pViewClass —— 指向该文档模板的CView (或派生类)的CRuntimeClass结构,在构造函数中设定。
        · m_strDocStrings —— 一个CString,包含用来定义与每个文档模板联系的7个字符串的字符串表资源。在LoadTemplate()中初始化。
       
        创建新的 文档/视图/框架
            CDocTemplate::CreateNewDocument()           (DOCTEMPL.CPP)   《深入解析MFC》P205
                · 首先,通过CRuntimeClass 指针的数据成员 m_pDocClass 调用 CRuntimeClass::CreateObject() 创建一个新的文档
                · 在pDocument 中保存了 新的 CDocument(或派生类 ) 指针之后,验证 CreateObject 是否已经工作,若失败,返回NULL。
                    若成功,调用 AddDocument() 将该文档加到打开文档链表中。 CreateNewDocument() 返回指向新文档的指针。
           
            CDocTemplate::CreateNewFrame()
                · 首先,填充一个CCreateContext(存放创建各种文档/视图结构元素所需的关键信息)。
                        1>. m_pNewViewClass —— 一个 CRuntimeClass 指针,用来创建视图
                        2>. m_pCurrentDoc —— 指向当前文档对象的指针
                        3>. m_pCurrentFrame  —— 指向当前框架对象的指针
                        4>. m_pNewDocTemplate —— 如果有多个文档,指向最后一个;
                        5>. m_pLastView —— 如果有多个视图,指向最后一个视图。
                · 通过m_pFrameClass 中的 CRuntimeClass 结构调用 CRuntimeClass::CreateObject() 创建一个框架,再调用 LoadFrame()装入
                  这个框架的资源,根据这些值创建该框架。 最后,CreateNewFrame()返回一个指向新框架的指针。 
   
            CSingleDocTemplate         《深入解析MFC》P 207
                    : CDocument* m_pOnlyDoc;
                        AddDocument() 将 m_pOnlyDoc 设置成参数;
               
            CMultiDocTemplate
                     :  AddDocument() 通过调用 m_docList.AddTail( pDocument ) 将新文档加入自己的链表中。
                        CPtrList  m_docList;        
                        int m_nUntitledCount;  //记录没有标题的窗口数
           
            CMultiDocTemplate::OpenDocumentFile()
                    · 调用CreateNewDocument() 创建一个新的空文档(一个CDocument派生对象),然后通过 CreateNewFrame() 创建一个新的框架,
                    · 若参数 lpszPathName 为NULL, 则OpenDocumentFile() 知道要创建的事一个空的新文档,调用SetDefaultTitle()完成这个功能。
                        这个函数为新文档确认名称[使用Untitled与m_nUntitledCount中未命名计数的组合],然后通过新文档指针调用CDocument::SetTitle()
                        设置新文档名字,组后,OpenDocumentFile()调用 OnOpenDocumentFile(),并将未命名计数的数据成员加1.
                    · 若lpszPathName 不等于NULL,则 OpenDocumentFile() 尝试打开指定的文档,首先,OpenDocumentFile() 显示一个等待光标,然后
                        调用CDocument::OnOpenDocumentFile(),将文档名传入作为参数。若调用失败,则销毁新创建的对话框,返回一个NULL。若调用成功,
                        则OpenDocumentFile() 调用 CDocument::SetPathName() 更新CDocument 的路径。
                    ·不管lpszPathName的状态时说明,OpenDocumentFile() 最后调用 CDocTemplate::InitializeUpdateFrame(),再调用            
                        CFrameWnd::InitialUpdateFrame(),  并传递一个指向新文档的指针。
                       
    ****///---------------------------------------------
    CFrameWnd           (WINFRM.CPP)
       
        CFrameWnd 和 CView 的创建                       《深入解析MFC》P208
            视图的创建:CFrameWnd::CreateView     
                在文档模板在CreateNewFrame() 中创建框架时,Windows发出一个 WM_CREATE,进行如下调用
                            OnCreate ->  OnCreateHelper()  -> OnCreateClient()  ->  CreateView() 
            CreateView() 使用 CCreateContext::m_pNewViewClass 中存储的 CRuntimeClass 创建一个视图,创建完成后,调用 CWnd::Create()完成创建工作。
           
        CFrameWnd::InitialUpdateFrame()
            使框架中的所有视图都被更新。
            · 首先,InitialUpdateFrame() 获得一个活跃视图的指针,并存放在 pView中,
            · 若 bMakeVisible 参数为TRUE, 则InitialUpdateFrame() 发出 WM_INITIALUPDATE 给他所有后代,这个消息被映射到 CView::OnInitialUpadte()。
                发送消息后,通过CView::OnActiveView() 激活视图。
               
               
    ****///---------------------------------------------
    CDocument              (AFXWIN.H)
       
        · m_strTitle —— 文档名,通过 SetTitle()设置,保存时用它来设定框架窗口的标题和文件的名字
        · m_strPathName —— 当前文档的路径(包括文件名)。用 SetPathname() 设置,是对MRU菜单的补充,保存文件时用到。
        · m_pDocTemplate —— 指向文档的文档模板的指针。 CDocTemplate::AddDocument()中设置,通过CDocTemplate::GetDocTemplate()访问
        · m_viewList —— 记录所有在该文档下打开的所有视图的指针。  文档改变时,通过这个指针通知视图。
                                   视图通过AddView()加入到m_viewList中,RemoveView()删除。
                                   GetFirstViewPosition() 和 GetNextView() 来遍历
        · m_bModified —— “修改”标志位,被修改就设为 1。为1是框架在用户关闭文档时提示。  IsModified()   SetModifiedFlag()
        · m_bAutoDelete —— 被框架设置为 TRUE时,所有视图关闭时该文档对象要被删除。可设为 FALSE,文档在没有任何打开视图时仍会保留
        · DisconnectViews() —— 该成员函数遍历 m_viewlist 中保存的视图链表,并将 CView::m_pDocument 指针设置为 NULL,从而将所有视图从文档上断开。
        · DoSave() —— CDocument成员 OnFileSaveAs() 和 OnFileSave() 在提示输入文件名或验证文件名后,最终都调用 DoSave(),DoSave调用了 OnSaveDocument()
        · DoFileSave() —— 先检查文档要被存储到的文件的一些性质,在调用 DoSave()。
        · UpdateFrameCounts() —— 计数为该文档的所有视图打开的框架,并根据新的技术通知更新它们的窗口标题。
        · SendInitialUpdate() —— 遍历视图链表并调用 CView::OnInitialUpdate()。
       
    创建文档:             《深入解析MFC》P213
        ->  创建一个空的文档,会调用 CDocument::OnNewDocument()。
                首先调用DeleteContents() 清空文档(默认什么都不做),然后设置修改标志位为 FALSE,并确保 m_strPathName为空
               
        ->  CDocument::OnOpenDocument() 从一个文件创建文档
                ①. 首先调用 CDocument::GetFile() 打开一个文件,该函数用给出的文件名调用 CFile::Open()。若打开成功,OnOpenDocument()调用DeleteContents()
            为文件的发序列化(de-serialization)作准备(从永久存储设备读入一个新的文档)。调用SetModified()。 若序列化失败,文档被标记为“已修改”。
                ②. 根据pFile 创建一个 CArchive,并将这个 CArchive 传递给 CDocument::Serialize()。 若发序列化成功,关闭档案并释放文件
                ③. 最后,关闭修改标志位并返回TRUE
               
    保存文档:
        CDocument::OnSaveDocument()
            通过GetFile()打开一个文件,使用标志指定文件是打开用来保存的(CFile:: mode ReadWrite|CFile::modeCreate)。
            创建CArchive,并将之床底给 Serialize() 成员函数。
            若成功序列化,关闭CArchive,标志位设置成 FALSE,返回TRUE。
           
    与视图通信:
        m_viewlist 是 CDocument 与正在“视”这个文档的视图进行交互的中介。
            (需要交互的状况)
            1. 通知视图文档被销毁。  CDocument析构函数调用 DisconnectView()
            2. 从视图出发,通过调用CView::GetParentFrame() 访问框架,
            3. 通知视图文档被修改、需要更新, UpdateAllViews()完成这个功能
           
        CDocument::UpdateAllViews()
            首先调用 GetFirstViewPosition() 获得 m_viewlist的第一个视图;
            然后,遍历整个视图链表,除发送者的视图外调用 CView::OnUpdate()。
           
                       
    ****///---------------------------------------------
    CView                           (AFXWIN.H)
   
        CView 绘图
            CView::OnPaint()
                · 首先创建一个CPaintDC,包含要重画的区域,
                · 将这个 paint DC 传递给 OnPrepareDC(),最后将 paint DC 传给 OnDraw()。
                    tag:默认的 OnPrepareDC() 和 OnDraw() 实现不做任何事,
                       

posted on 2010-03-15 23:24 Euan 阅读(2315) 评论(0)  编辑 收藏 引用 所属分类: windows

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理