关于某单文档多视与MFC地初始化过程.docx
- 文档编号:11747851
- 上传时间:2023-06-02
- 格式:DOCX
- 页数:44
- 大小:2.56MB
关于某单文档多视与MFC地初始化过程.docx
《关于某单文档多视与MFC地初始化过程.docx》由会员分享,可在线阅读,更多相关《关于某单文档多视与MFC地初始化过程.docx(44页珍藏版)》请在冰点文库上搜索。
关于某单文档多视与MFC地初始化过程
单文档多视的实现
多视图是VC开发中经常要用到的技术之一,一般地实现单文档多视图有两种方式1)通过视图分割的技术(使用CSplitterWnd实现),将窗口分割为多个部分,每个部分显示各自显示不同的视图,这种技术实现起来比较简单,并且相关的资料也很多。
2)通过一个文档关联多个视图,窗口显示整个视图。
第二种实现较第一种复杂,这里给出详细的实现方法。
Step1:
使用VC6.0新建一个Project,命名为:
MultiView。
除选择单文档属性外,一切使用“默认”方式。
于是你可以获得五个类:
CMainFrame,CMultiViewApp,CMultiViewDoc,CMultiViewView,和CAboutDlg;
Step2:
新建一个新的视图View,添加一个新的MFCClass(Insert->NewClass),基类为CView(或者CView的派生子类,如CEditView等)。
类的名字为CAnotherView,这就是新的视图;并为CAnotherView添加GetDocument的实现:
CMultiViewDoc*CAnotherView:
:
GetDocument()
{
return(CMultiViewDoc*)m_pDocument;
}
Step3:
在CMultiViewApp添加成员变量记录这两个视图:
private:
CView*m_pFirstView;
CView*m_pAnotherView;
给程序菜单IDR_MAINFRAME添加一个菜单项目“视图”,该菜单项有两个子菜单“视图一”和“视图二”,添加相应函数:
(voidCMultiViewApp:
:
OnShowFirstview()和voidCMultiViewApp:
:
OnShowSecondview());
注意这里将菜单消息的响应都放在app对象里面,而不是放到MainFrame对象中进行。
Step4:
创建新的视图:
在BOOLCMultiViewApp:
:
InitInstance()中添加代码:
…….
//创建一个新的视图
CView*m_pActiveView=((CFrameWnd*)m_pMainWnd)->GetActiveView();
m_pFirstView=m_pActiveView;
m_pAnotherView=newCAnotherView();
//文档和视图关联
CDocument*m_pDoc=((CFrameWnd*)m_pMainWnd)->GetActiveDocument();
CCreateContextcontext;
context.m_pCurrentDoc=m_pDoc;
//创建视图
UINTm_IDFORANOTHERVIEW=AFX_IDW_PANE_FIRST+1;
CRectrect;
m_pAnotherView->Create(NULL,NULL,WS_CHILD,rect,m_pMainWnd,
m_IDFORANOTHERVIEW,&context);
……
Step5:
现在已经创建了视图,并且都和文档关联起来了。
现在要作的就是视图间的转换。
在voidCMultiViewApp:
:
OnShowFirstview()中添加实现代码:
voidCMultiViewApp:
:
OnShowFirstview()
{
//TODO:
Addyourcommandhandlercodehere
UINTtemp=:
:
GetWindowLong(m_pAnotherView->m_hWnd,GWL_ID);
:
:
SetWindowLong(m_pAnotherView->m_hWnd,GWL_ID,:
:
GetWindowLong(m_pFirstView->m_hWnd,GWL_ID));
:
:
SetWindowLong(m_pFirstView->m_hWnd,GWL_ID,temp);
m_pAnotherView->ShowWindow(SW_HIDE);
m_pFirstView->ShowWindow(SW_SHOW);
((CFrameWnd*)m_pMainWnd)->SetActiveView(m_pFirstView);
((CFrameWnd*)m_pMainWnd)->RecalcLayout();
m_pFirstView->Invalidate();
}
在voidCMultiViewApp:
:
OnShowSecondview()中添加实现代码:
voidCMultiViewApp:
:
OnShowSecondview()
{
//TODO:
Addyourcommandhandlercodehere
UINTtemp=:
:
GetWindowLong(m_pAnotherView->m_hWnd,GWL_ID);
:
:
SetWindowLong(m_pAnotherView->m_hWnd,GWL_ID,:
:
GetWindowLong(m_pFirstView->m_hWnd,GWL_ID));
:
:
SetWindowLong(m_pFirstView->m_hWnd,GWL_ID,temp);
m_pFirstView->ShowWindow(SW_HIDE);
m_pAnotherView->ShowWindow(SW_SHOW);
((CFrameWnd*)m_pMainWnd)->SetActiveView(m_pAnotherView);
((CFrameWnd*)m_pMainWnd)->RecalcLayout();
m_pAnotherView->Invalidate();
}
Step6:
为了演示,这里将不同的视图给予一个标记,在CMultiViewView和CAnotherView的OnDraw方法中分别添加以下代码:
pDC->TextOut(400,300,"FirstView");
pDC->TextOut(400,320,pDoc->GetTitle());
和
pDC->TextOut(400,300,"AnotherView");
pDC->TextOut(400,320,pDoc->GetTitle());
至此就大功告成了,但是实现过程中有4点说明:
1) 实现中由于使用到相关的类,因此在必要的地方要include相关的头文件,这里省略;CAnotherView的默认构造函数是Protected的,需要将其改为Public,或者提供一个产生CAnotherView对象的方法(因要创建视图对象);
2) 这里给出的是一个示例代码,实际开发中可以通过参考实现获得自己想要实现的具体应用情况(例如视图类的不同、数量不同,更重要的还有业务逻辑的不同实现等);
3) 本文的示例代码已上传到Blog,可以通过下面的地址获得代码。
MFC程序总体的架构
CWinApp――取代WinMain的地位
。
。
。
。
。
。
。
。
。
。
。
。
CFrameWnd――取代WndProc的地位
在MFC里面,似乎应该是在CWnd类里有一个WindowProc这个类,应该就是这个函数来作为窗口回调函数,因为所有的窗口回调函数都继承自CWnd类,CFrame类也是的。
在MFC中,为了让程序更加结构化,更容易理解和维护,利用了两个宏来处理消息映射:
DECLARE_MESSAGE_MAP和BEGIN_MESSAGE_MAP,见前面第三章。
程序运行第一步:
引爆器――ApplicationObject
从这一节以下,将以此图解释MFC程序的激活,运行与结束,不同小节的图将标示出当时的程序进行状况
程序运行第二步:
隐晦不明的WinMain
主要动作:
tWinMain调用AfxWinMain,AfxWinMain调用AfxWinInit
在这个过程中,tWinMain的参数hInstance经过AfxWinMain传给AfxWinInit,然后在AfxWinInit中利用传进来的参数对theApp对象进行初始化(利用全局函数AfxGetApp)
在AfxWinInit中除了对theApp对象进行初始化之处,还调用AfxInitThread函数对线程进行初始化。
程序运行第三步:
AfxWinInit――AFX内部初始化动作
程序运行第四步:
CWinApp:
:
InitApplication
程序运行第五步:
CMyWinApp:
:
InitInstance
程序运行第六步:
CFramWnd:
:
Create产生主窗口(并先注册窗口类别)
小结:
在MFC中,应用程序窗口的产生,必须经历窗口类的注册-》创建-》显示。
这一系列的动作是通过theApp->InitInstance()函数来组织调用的。
PS:
即在InitInstance里做了好多的工作,调用了相关的函数,这些函数就有窗口类的注册,窗口的创建和窗口的显示工作。
窗口类的注册动作,MFC给我们提供的接口是各个窗口类的PreCreateWindow()函数,
BOOLCStudentInfoView:
:
PreCreateWindow(CREATESTRUCT&cs)
利用这个结构体参数,对窗口的样式进行设定,这个结构体如下:
typedefstructtagCREATESTRUCT{
LPVOID lpCreateParams;
HANDLE hInstance;
HMENU hMenu;
HWND hwndParent;
int cy;
int cx;
int y;
int x;
LONG style;
LPCSTR lpszName;
LPCSTR lpszClass;
DWORD dwExStyle;
}CREATESTRUCT;
怎么让一个窗口居中显示?
?
利用cy,cx参数?
?
程序运行第七步:
窗口显示与更新
程序运行第八步:
CWinApp:
:
Run――程序生命的活水源头
把消息与处理函数串接在一起:
MessageMap机制
消息流动是个颇为复杂的机制,它和Document/View,动态生成(DynamicCreation),文件读写(Serialization)一样,都是需要特别留心的地方。
来龙去脉总整理
MFC骨干程序—关于文档视图结构的创建
这里的所谓的MFC应用程序骨干,批的是由AppWizard产生出来的MFC程序,也就是像第四章所产生的Scribblestep0那样的程序。
不二法门:
熟记MFC类别阶层架构
MFC程序的UI新风貌
Document/View支撑你的应用程序
一个问题:
关于Document/View的配合:
为什么要用Document/View机制?
?
骨干程序使用哪些MFC类别?
?
应用程序各显身手的地方只是各个可能改写的虚拟函数。
DocumentTemplate的意义
为什么要有DocumentTemplate?
DocumentTemplate对象的构造函数:
DocumentTemplate构造函数的参数说明:
对于我们的Scrible应用程序,它的相关代码如下:
DocumentTemplate
CDocTemplate管理CDocument/CView/CFrameWnd
关于File/New与File/Open按钮动作的响应过程
总体概览:
上图的灰色部分,正是DocumentTemplate动态产生“三位一体的Document/View/Frame”的行动。
注意这里的CWinApp选择适当的DocumentTempate:
由于打开一个文件需要依赖于DocumentTempate,而DocumentTempate实例创建是在CMultiViewApp:
:
InitInstance()里:
CSingleDocTemplate*pDocTemplate;
pDocTemplate=newCSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CMultiViewDoc),
RUNTIME_CLASS(CMainFrame),//mainSDIframewindow
RUNTIME_CLASS(CMultiViewView));
AddDocTemplate(pDocTemplate);
需要提供四样东西:
其中第一样就是打开文档所需要的资源IDR_MAINFRAME,资源中包含了文档的后缀,文档类型的信息,所以当我们选择打开一个文件的时候,CSingleDocTemplate会自动根据文档的后缀类型来选择不同的CSingleDocTemplate实例进行三口组的创建
CDocTemplate类如何创建三口组:
File/New与File/Open消息的总结
关于MFC主框架的类图:
主要的类:
CWinApp,CMainFrame,DocTemplete,CDocument,CView
框架类之间的关系:
CWinApp与CMainFrame及DocTemplete之间的关系:
CWinApp有两个成员变量:
CMainFrame和DocTemplete,
在CWinApp(被CMyApp所继承)的OnInitInstance方法中:
创建一个CSingleDocTemplate,将文档,框架窗口和视图联系了在一起,所以我们点文件—打开一个文件的时候,它会显示这三口组(将Doc放在View中,然后View再嵌入到Frame中),由于程序运行的时候就应该显示一个文档,而文档需要通过三口组来显示,所以这里在CWinApp的派生对象中需要有这么一个三口组数组作为成员变量。
CSingleDocTemplate*pDocTemplate;
pDocTemplate=newCSingleDocTemplate(
IDR_MAINFRAME,//这里是
RUNTIME_CLASS(CMultiViewDoc),
RUNTIME_CLASS(CMainFrame),//mainSDIframewindow
RUNTIME_CLASS(CMultiViewView));
AddDocTemplate(pDocTemplate);//这里将这个新生成的DocTemplet放到自己的DocTemplete列表中。
。
。
。
//按照深入浅出的理论是在这个OnInitInstance中对CMainFrame成员变量进行了初始化(调用构造函数),然后就引出了CMainFrame的初始化过程。
//Theoneandonlywindowhasbeeninitialized,soshowandupdateit.
m_pMainWnd->ShowWindow(SW_SHOW);//将三口组给显示出来,而不是只是只显示一个框架
m_pMainWnd->UpdateWindow();
returnTRUE;
CDocument与CView之间的关系:
是组合关系!
而且是一对多的组合关系,一个CDocument可以有多个CView,而一个CView只能对应一个CDocument
参见前面的单文档多视的实现中的第四步:
Step4:
创建新的视图:
在BOOLCMultiViewApp:
:
InitInstance()中添加代码:
…….
//创建一个新的视图
CView*m_pActiveView=((CFrameWnd*)m_pMainWnd)->GetActiveView();
m_pFirstView=m_pActiveView;
m_pAnotherView=newCAnotherView();
//文档和视图关联
CDocument*m_pDoc=((CFrameWnd*)m_pMainWnd)->GetActiveDocument();
CCreateContextcontext;
context.m_pCurrentDoc=m_pDoc;
//创建视图
UINTm_IDFORANOTHERVIEW=AFX_IDW_PANE_FIRST+1;
CRectrect;
m_pAnotherView->Create(NULL,NULL,WS_CHILD,rect,m_pMainWnd,
m_IDFORANOTHERVIEW,&context);
……
注意这里的m_pAnotherView->Create(NULL,NULL,WS_CHILD,rect,m_pMainWnd,
m_IDFORANOTHERVIEW,&context);
//一个View的创建必须与一个CMainFrame和一个context(里面有Doc)相关联
可见一个CView与CMainFrame,CDoc都有联系!
!
CMultiViewView中的成员方法:
CMultiViewDoc*CMultiViewView:
:
GetDocument()//non-debugversionisinline
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMultiViewDoc)));
return(CMultiViewDoc*)m_pDocument;
}
由于前面CView在创建的时候将CMainFrame和CDoc作为它创建的参数,所以这里m_pDocument;代表的是前面传递进来的文档的指针。
看到了吧,只返回一个指针,所以应该是一个CView只对应一个CDoc。
CMultiViewDoc类中的成员方法:
POSITIONCMultiViewDoc:
:
GetFirstViewPosition()const
{
//TODO:
Addyourspecializedcodehereand/orcallthebaseclass
returnCDocument:
:
GetFirstViewPosition();
}
CView*CMultiViewDoc:
:
GetNextView(POSITION&rPosition)const
{
//TODO:
Addyourspecializedcodehereand/orcallthebaseclass
returnCDocument:
:
GetNextView(rPosition);
}
由此可见一个CDoc可以有多个CView
CFrameWnd与CDoc之间的关系:
对于单文档程序来说一个CFrameWnd只有一个CDoc,而多文档应用程序则可以有多个CDoc
CFrameWnd中的成员方法:
CDocument*CMainFrame:
:
GetActiveDocument()
{
//TODO:
Addyourspecializedcodehereand/orcallthebaseclass
returnCFrameWnd:
:
GetActiveDocument();
}
一个CFrameWnd可以返回一个CDoc
CFrameWnd与CView之间的关系
好像没有什么关系,不过可能通过CFrameWnd获得CDoc之后,然后再由CDoc获得CView对象。
关于源码
CWinApp:
Public:
//Attributes
CWnd*m_pMainWnd;//mainwindow(usuallysameAfxGetApp()->m_pMainWnd)
CWnd*m_pActiveWnd;//activemainwindow(maynotbem_pMainWnd)
。
。
。
CDocManager*m_pDocManager;//这个就是用来管理CDocTemplet(一个实例代表的是一个三口组实例)的了。
CWnd源码:
//forchildwindows,views,panesetc
virtualBOOLCreate(LPCTSTRlpszClassName,
LPCTSTRlpszWindowName,DWORDdwStyle,
constRECT&rect,
CWnd*pParentWnd,UINTnID,
CCreateContext*pContext=NULL);
前面的CView在创建的时候就利用了这个方法:
m_pAnotherView->Create(NULL,NULL,WS_CHILD,rect,m_pMainWnd,
m_IDFORANOTHERVIEW,&context);
CView源代码:
成员变量:
protected:
CDocument*m_pDocument;
CDocument源代码:
成员变量:
protected:
//defaultimplementation
。
。
。
CDocTemplate*m_pDocTemplate;
CPtrListm_viewList;//listofviews
BOOLm_bModified;//changedsincelastsaved
CWinFrame源码:
Protected:
CView*m_pViewActive;//currentactiveview
源代码图解
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 关于 文档 MFC 初始化 过程