MFC复习(三)MFC文档视图结构

                       /
                       /*  1.回顾"InitInstance函数"  */
                       /
BOOL CMyApp::InitInstance()//只列出了与文档视图结构相关的源代码
{
//文档模板将用作文档、框架窗口和视图之间的连接
 CMultiDocTemplate* pDocTemplate;
 pDocTemplate = new CMultiDocTemplate(IDR_MyTYPE,  //-------------------2
  RUNTIME_CLASS(CMyDoc),
  RUNTIME_CLASS(CChildFrame), // 自定义 MDI 子框架
  RUNTIME_CLASS(CMyView));
 AddDocTemplate(pDocTemplate);  //--------------------------------------------------3
 // 创建主 MDI 框架窗口
 CMainFrame* pMainFrame = new CMainFrame;
 if (!pMainFrame->LoadFrame(IDR_MAINFRAME)) //----------------------------4
  return FALSE;
 m_pMainWnd = pMainFrame;

 // 分析标准外壳命令、DDE、打开文件操作的命令行
 CCommandLineInfo cmdInfo;
 ParseCommandLine(cmdInfo);  //--------------------------------------------------------5
 // 调度在命令行中指定的命令。如果
 // 用 /RegServer、/Register、/Unregserver 或 /Unregister 启动应用程序,则返回 FALSE。
 if (!ProcessShellCommand(cmdInfo)) //------------------------------------------------6
  return FALSE;
 // 主窗口已初始化,因此显示它并对其进行更新
 pMainFrame->ShowWindow(m_nCmdShow);
 pMainFrame->UpdateWindow();
 return TRUE;
}
                     
                       /*     2.初始化文档模板       */
                      
分析以下代码:
CMultiDocTemplate* pDocTemplate;
pDocTemplate = new CMultiDocTemplate(IDR_MyTYPE,
  RUNTIME_CLASS(CMyDoc),
  RUNTIME_CLASS(CChildFrame), // 自定义 MDI 子框架
  RUNTIME_CLASS(CMyView));
    应用程序首先实例化一个CMultiDocTemplate对象,此过程也是对CMultiDocTemplate类数据成员的初始化过程。
    看一看InitInstance函数将什么参数值传给了CMultiDocTemplate的构造函数。
原来是一些RUNTIME_CLASS宏。这个地方是个难点,这将涉及到MFC的另一个重要技术---"执行期类型识别",此处暂不说明
                       ///
                       /*       3.文档模板列队       */
                       ///
   文档模板初始化结束后,InitInstance函数调用了CWinApp::AddDocTemplate(pDocTemplate)函数,其主要目的是将以初始化后的那个文档模板加入到文档模板链表中,并由CDocManager类对象进行管理。
                          ///
                       /*    4.创建程序主框架窗口    */
                       ///
    应用程序实例化了一个CMainFrame类对象,并调用LoadFrame函数加载窗口资源创建主框架窗口。
    创建窗口的主要代码是:pMainFrame->LoadFrame(IDR_MAINFRAME);LoadFrame函数是MFC包装了窗口创建过程的函数,在后面动态创建Child窗口时,它还将披挂上阵(但稍有不同)
                       //
                       /* 4.1注册应用程序主框架窗口类 */
                       //
   在传统的Win32API编程中,创建窗口一般步骤是定义窗口类,注册窗口类,并调用::CreateWindow函数来创建。前面说过LoadFrame函数封装了MFC创建窗口的过程,那么也就是说LoadFrame函数将负责定义窗口类,注册窗口类等琐碎工作。
   这一步LoadFrame调用AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG)、CMainFrame::PreCreateWindow
                       /
                       /*    4.2主框架窗口创建开始    */
                       /

  开始进入创建框架窗口的实质阶段。看LoadFrame函数做了什么?原来它调用了CFrameWnd::Create==>CWnd::CreateEx==>Win32API::CreateWindowEx、AfxHookWindowCreate(this)(此函数与消息映射和命令传递有关)。
                       //
                       /*     5.标准外壳命令解析      */
                       ///
    MFC向导制作的标准MDI应用程序启动时,应用程序会自动启动一个子窗口框架(实际上是一套文档模板)
    CCommandLineInfo cmdInfo; //===>m_nShellCommand = FileNew;
    ParseCommandLine(cmdInfo);//===>把命令行参数传给ParseParam()
    if (!ProcessShellCommand(cmdInfo))//根据cmdInfo内容执行相应操作,由于m_nShellCommand = FileNew,所以CWinApp::OnFileNew()被调用
        return FALSE;
                       //
                       /*   6.一套文档/视图即将诞生   */
                       //
    上文说CWinApp::OnFileNew()被调用了
    CWinApp::OnFileNew()==>CDocManager::OnFileNew()==>CMultiDocTemplate::OpenDocumentFile()
    CDocument* CMultiDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName,BOOL bMakeVisible)
    {
        ...
        CDocument* pDocument = CreateNewDocument();//子文档动态生成
        CFrameWnd* pFrame = CreateNewFrame(pDocument, NULL);//子窗口框架动态生成====>同时创建了CCreateContext context,之后调用LoadFrame
        pDocument->OnNewDocument();
        ...
    }
                       //
                       /*     6.1.子视图动态生成      */
                       //
关键在于CreateNewFrame中的CCreateContext context、LoadFrame,这里的LoadFrame含有参数context
LoadFrame(...,&context)-->CFrameWnd::Create(...,&context)--> CWnd::CreateEx(...,&context)-->CWnd::CreateWindowEx  //(这里将创建一个CREATESTRUCT cs 结构作为消息传递参数)

CWnd::CreateEx

{

    CREATESTRUCT cs;  //窗口创建的消息结构

    AfxHookWindowCreate(this);  //为CFrameWnd挂上消息钩子,用于消息映射和命令传递,这里的this为CreateNewFrame中创建的CFrameWnd

    HWND hWnd = ::AfxCtxCreateWindowEx(cs); //创建窗口

    ASSERT(hWnd == m_hWnd); // should have been set in send msg hook

}

void AFXAPI AfxHookWindowCreate(CWnd* pWnd)

{

    _AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();//pThreadState 是个全局对象

    pThreadState->m_pWndInit = pWnd;   //pWnd是一个CFrameWnd

}

::CreateWindowEx API函数将产生WM_CREATE消息,并将&context传递之(存在LPCREATESTRUCT中,注意LPCREATESTRUCT为CREATESTRUCT的结构指针),CMainFrame::OnCreate将响应消息,并引起一系列的函数调用
int CMainFrame::OnCreate(LPCREATESTRUCT)==>CFrameWnd::OnCreate(LPCREATESTRUCT)==>CFrameWnd::OnCreateHelper(CCreateContext)==>CFrameWnd::OnCreateClient(CCreateContext)==>CFrameWnd::CreateView(CCreateContext)

struct CCreateContext

{

    CRuntimeClass* m_pNewViewClass;// for creating new views

    CDocument* m_pCurrentDoc;// for creating MDI children (CMDIChildWnd::LoadFrame)

    CDocTemplate* m_pNewDocTemplate;// for sharing view/frame state from the original view/frame

    CView* m_pLastView;

    CFrameWnd* m_pCurrentFrame;

};
CFrameWnd::OnCreate(LPCREATESTRUCT lpcs)
{
    CCreateContext* pContext = (CCreateContext*)lpcs->lpCreateParams; // 注意CCreateContext
}
CWnd* CFrameWnd::CreateView(CCreateContext* pContext, UINT nID)
{
    CWnd* pView = (CWnd*)pContext->m_pNewViewClass->CreateObject();

    pView->Create(NULL, NULL, AFX_WS_DEFAULT_VIEW, CRect(0,0,0,0), this, nID, pContext);//==>注意这里会调用CWnd::Create->::CreateWindowEx API函数产生WM_CREATE消息,从而创建CView窗体
}

//CView接收到WM_CREATE消息,执行OnCreate

int CView::OnCreate(LPCREATESTRUCT lpcs)

{

    CCreateContext* pContext = (CCreateContext*)lpcs->lpCreateParams;

    pContext->m_pCurrentDoc->AddView(this); //把视图加入文档的视图列表

}

void CDocument::AddView(CView* pView)

{

    pView->m_pDocument = this;  //指向当前视图所属文档

}

                       /
                       /*         7.收尾工作          */
                       /
   至此,一套完整的Document/ChildFrame/View结构生成,此“三口组”共属同一套文档模板,如果你要定义另一套不同的文档模档需再定义另一组不同“三口组”(ChildFrame可以使用相同的)。并调用AddDocTemplate将该文档模板加入到应用程序的文档模板列表。比如:

  CMultiDocTemplate* pOtherDocTemplate;
 pOtherDocTemplate = new CMultiDocTemplate(IDR_MyOtherTYPE,
  RUNTIME_CLASS(CMyOtherDoc),
  RUNTIME_CLASS(CChildFrame), // 自定义 MDI 子框架
  RUNTIME_CLASS(CMyOtherView));
 AddDocTemplate(pOtherDocTemplate);

“三口组”生成后程序调用ShowWindow,UpdateWindow将应用程序的主窗口展现在你眼前。

  注释:当你在File菜单中选择new或在工具栏中单击“新建”时,应用程序将选择当前默认的文档模板并以它为基础动态生成 Document/ChildFrame/View“三口组”,其生成过程与上述讲的一般不二。

 

 

摘自
http://www.chinaitpower.com/A/2001-10-06/879.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值