【交互】MFC单文档多视图实例分析

一、基本原理

        对于多文档App而言,首先是创建CMainFrame窗口和它的子窗口MDIClient。当新建一个文档,则会new CDocument,顺便创建CChildFrame和它的子窗口CView,再次新建时,会建立另一个文档,创建另外一个CChildFrame和它的子窗口CView。对于不同视图,CView的ID标识是AFX_IDW_PANE_FIRST。在本次CChildFrame新建另外的CView时,ID标识要改变,以免重复。

        向MDIClient发送WM_MDICREATE创建CChildFrame时,内部会分配子窗口的ID值,另外MDIClient在CManiFrame::OnCreate中调用到CMDIFrameWnd中的一个函数,里面创建时,Menu ID标识也是AFX_IDW_PANE_FIRST,但是MDIClient的创建 CLIENTCREATESTRUCT ccs的里面,可以指定子窗口id标识ccs.id,即子窗口CChildFrame的id标识从这个数字开始编号AFX_IDM_FIRST_MDICHILD。

        若要获取激活窗口,则向MDIClient发送WM_GETACTIVATE消息,每个激活的CChildFrame父类CFrameWnd保存一个 CView* m_pViewActive,也就是CChildFrame会有一个主视图。

二、SDI单文档多视图的实现及自由切换【1、2】
        主要是获取当前活动文档ActiveDocument,放到context.m_pCurrentDoc,然后再创建的时候,传上下文context信息。

classCMultiViewApp : publicCWinApp{ public:       CView* m_pFirstView;       CView* m_pOtherView;       int m_currentView;       CView* m_pView2;       CView* m_pView1; } CMultiViewApp::InitInstance() {   CDocument* pDoc = ((CFrameWnd*)m_pMainWnd)->GetActiveDocument();       //通过CCreateContext实现第二视图和文档的关联       CCreateContext   context;       context.m_pCurrentDoc = pDoc;//把视图放在当前文档       UINT  m_ID = AFX_IDW_PANE_FIRST + 1;//设置标识作为CMainFrame的子窗口       CRect  rect;        //为了演示第一种多视图是实现方法,把Vew的实例创建放在了这里       m_pOtherView->Create(NULL, NULL, WS_CHILD, rect, m_pMainWnd, m_ID, &context);} //切换时,设置活动视图,另外就是重新计算,这里要具体看RecalcLayout

 ……//里面会交换View窗口ID,是因为 CFrameWnd::RecalcLayout will allocate  // this "first pane" to that portion of the frame window's client area //not allocated to control bars. m_pOtherView->ShowWindow(SW_HIDE); m_pFirstView->ShowWindow(SW_SHOW);  m_pMainWnd->SetActiveView(m_pFirstView);  m_pMainWnd->RecalcLayout(); m_pFirstView->Invalidate();


三、CMainFrame中添加不同的CChildFrame【3、4】

1、这个子窗口,只是创建了一个视图,没有指定context.m_pCurrentDoc,在CView::OnCreate()里面会报错。

CMainFrame::OnFuncTwo()
{
//仿照上面的思想,new Frame,点击一个菜单时,切换到这个CChildFrame
m_pFuncOneFrame = new CDemoFrame(); 
CCreateContext context; 
context.m_pNewViewClass = RUNTIME_CLASS(CFuncOneView); //关联的视图类,又它新建一个视图对象
m_pFuncOneFrame->LoadFrame(IDR_MAINFRAME, WS_MAXIMIZEWS_OVERLAPPEDWINDOW, this, &context); 
m_pFuncOneFrame->SetWindowText(" 业务逻辑一 "); 
m_pFuncOneFrame->ShowWindow(SW_SHOWMAXIMIZED); 
m_pFuncOneFrame->InitialUpdateFrame(NULL,true); 
}

2、加入文档后

void CMainFrame::OnFuncOne() 
{ 
// TODO: Add your command handler code here 
if (m_pFuncOneFrame != NULL) //已创建,则激活它
{ 
m_pFuncOneFrame->MDIActivate(); 
return ; 
} 
m_pFuncOneFrame = new CDemoFrame(); 
CDemoDoc* m_pDoc = new CDemoDoc(); //new了一个文档
CCreateContext context; 
context.m_pNewViewClass = RUNTIME_CLASS(CFuncOneView); //传CView class
context.m_pCurrentDoc = m_pDoc; 
m_pFuncOneFrame->LoadFrame(IDR_MAINFRAME, WS_MAXIMIZEWS_OVERLAPPEDWINDOW, this, &context); 
m_pFuncOneFrame->SetWindowText(" 业务逻辑一 "); 
m_pFuncOneFrame->ShowWindow(SW_SHOWMAXIMIZED); 
m_pFuncOneFrame->InitialUpdateFrame(NULL,true); 
} 


四、总结

       CMainFrame建立了MDIClient之后,会new CDocument,然后pFrame

CCreateContext context;
 context.m_pCurrentFrame = pOther;//NULL,
 context.m_pCurrentDoc = pDoc;//当前文档
 context.m_pNewViewClass = m_pViewClass;//CDocTemplate中已经保存有它
 context.m_pNewDocTemplate = this;
pFrame->LoadFrame(m_nIDResource, WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE,NULL, &context))
//pParenWnd会在后面设置为MDIClient
//其函数原型
virtual BOOL LoadFrame(UINT nIDResource,DWORD dwDefaultStyle = WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE,
	CWnd* pParentWnd = NULL,CCreateContext* pContext = NULL);

       对于文档管理,三、2中,可将模板放在保存一个位置,或者直接获取pDocTemplate,然后将pDoc加入到文档模板当中。

           

参考:1、MFC SDI单文档多视图的实现及自由切换(2种实现方式简析)

2、为啥交换窗口ID标识

3、MFC文档视图深入详解

4、深入分析MFC文档视图结构(项目实践)

你可能感兴趣的:(SDK,/,MFC)