您的位置:首页 > 其它

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

2008-12-13 17:41 357 查看
/////////////////////////////////////////////
/* 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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: