04文档与视图.docx
- 文档编号:9889137
- 上传时间:2023-05-21
- 格式:DOCX
- 页数:60
- 大小:1.30MB
04文档与视图.docx
《04文档与视图.docx》由会员分享,可在线阅读,更多相关《04文档与视图.docx(60页珍藏版)》请在冰点文库上搜索。
04文档与视图
第4章文档与视图
MFC提供了将应用程序的数据与显示分开的文档/视图结构,它为应用程序提供了统一的框架。
如
正在运行中的SDI应用程序中的对象文档视图结构中的各种对象及其创建与关系
4.1文档/视图体系
文档(document)对应于用户的数据(可以是文本、数值、图像、声音、视频等),它可以从磁盘文件中读入,也可写入磁盘文件,用户还可以定义、修改、管理这些数据。
对应的MFC类为CDocument。
视图(view)是一种窗口对象,对应于框架窗口的客户区,它负责在屏幕和打印机上显示和输出数据,为用户提供观察、选择、编辑文档数据的交互界面。
对应的MFC类为CView。
文档与视图
文档/视图结构有两种主要的方式:
SDI(SingleDocumentInterface,单文档界面)和MDI(MultipleDocumentInterface,多文档界面)。
在.NET中新添加了一种MTDI(MultipleTop-levelDocumentInterface,多顶级文档界面)。
应用程序的文档/视图结构种类,可以在创建MFC应用程序时,在“MFC应用程序向导”对话框的“应用程序类型”页中设置(缺省为MDI),在该对话框页中还可以选择是否具有“文档/视图结构支持”(缺省是选中)。
参见下图。
SDI应用程序只有一个框架窗口(类)和一个视图窗口(对应于框架窗口的客户区),且只有一个文档类,每次只能打开一个文档。
这里的文档和视图一般是一一对应的。
MDI应用程序有一个主框架窗口(类),可有任意多个子框架窗口和对应的视图客户区窗口,也可有多个文档类,可以同时打开多个文档/窗口。
这里,每个视图对应于一个文档,而每个文档则可对应于多个视图。
MTDI类似于MDI,只是MDI中的每个文档视图窗口都是主框架窗口的子窗口(只能位于主框架窗口的客户区内);而MTDI的文档视图窗口都是顶层窗口,位于主框架窗口之外。
SDIMDIMTDI
不同的文档界面MDI/MTDI的一个文档可以对应多个视图
1.文档模板类
文档、框架窗口与视图通过文档模板联系在一起,MFC的文档模板类为CDocTemplate。
对SDI与MDI,它有两个对应的派生类CSingleDocTemplate与CMultiDocTemplate:
它们的构造函数的参数都一样:
C[Single|Multi]DocTemplate(//文档模板构造函数
UINTnIDResource,//文档类型的资源ID
CRuntimeClass*pDocClass,//派生文档类对象的指针
CRuntimeClass*pFrameClass,//[派生]框架窗口类对象的指针
CRuntimeClass*pViewClass//派生视图类对象的指针
);
CWinApp类创建文档模板的操作分两步进行,首先用文档模板类的构造函数创建一个SDI或MDI文档模板的实例,然后调用CWinApp类的成员函数AddDocument将该模板添加到应用程序的模板列表中。
创建文档模板的操作一般在派生应用程序类的InitInstance成员函数中完成。
例如:
(SDI)
BOOLCDrawApp:
:
InitInstance(){
……
//注册应用程序的文档模板。
文档模板
//将用作文档、框架窗口和视图之间的连接
CSingleDocTemplate*pDocTemplate;
pDocTemplate=newCSingleDocTemplate(IDR_MAINFRAME,
RUNTIME_CLASS(CDrawDoc),
RUNTIME_CLASS(CMainFrame),//自定义MDI子框架
RUNTIME_CLASS(CDrawView));
AddDocTemplate(pDocTemplate);
……
}
其中,RUNTIME_CLASS宏返回一个指向CRunTimeClass类的指针:
CRuntimeClass*RUNTIME_CLASS(class_name)
又例如:
(MDI)
BOOLCImageApp:
:
InitInstance(){
……
//注册应用程序的文档模板。
文档模板
//将用作文档、框架窗口和视图之间的连接
CMultiDocTemplate*pDocTemplate;
pDocTemplate=newCMultiDocTemplate(
IDR_BMPTYPE,
RUNTIME_CLASS(CImageDoc),
RUNTIME_CLASS(CChildFrame),//自定义MDI子框架
RUNTIME_CLASS(CImageView));
AddDocTemplate(pDocTemplate);
pDocTemplate=newCMultiDocTemplate(
IDR_GIFTYPE,
RUNTIME_CLASS(CImageDoc),
RUNTIME_CLASS(CChildFrame),//自定义MDI子框架
RUNTIME_CLASS(CImageView));
AddDocTemplate(pDocTemplate);
……
}
可见一个MDI应用程序可有多个MDI模板,每个MDI模板在运行时又可有多个实例(对应于同一模板中同一文档类型/视图类型的多个文档对象/视图窗口)。
如下图所示:
具有两个文档类型的MDI应用程序
2.文档类
所有用户的文档类都是从文档基类CDocument派生的:
CDocument类的常用成员函数有:
virtualPOSITIONGetFirstViewPosition()const;//获得视图列表中与本文档关联的
//第一个视图的位置,该位置可用于GetNextView函数
virtualCView*GetNextView(POSITION&rPosition)const;//返回rPosition所指的
//视图的指针,获得下一个本文档关联的视图的位置到rPosition中
使用GetFirstViewPosition与GetNextView可遍历文档的所有视图。
constCString&GetTitle()const;//返回文档(窗口)的标题,一般为相关联的文件名
virtualvoidSetTitle(LPCTSTRlpszTitle);//设置文档(窗口)的标题
constCString&GetPathName()const;//返回与文档相关联的文件的路径
//无关联文件时返回NULL
virtualvoidSetPathName(LPCTSTRlpszPathName,BOOLbAddToMRU=TRUE);
//设置存取文档的默认路径(与文档(窗口)的标题),若bAddToMRU=TRUE,
//则将该路径添加到最近使用文件(MRU=mostrecentlyused)的列表中
BOOLIsModified();//判断文档在最后一次存储后是否被修改过
//若被修改过,则在用户关闭文档窗口或应用程序时,会提示保存文件
voidSetModifiedFlag(BOOLbModified=TRUE);//设置文档在最后一次存储后
//是否被修改过
voidUpdateAllViews(CView*pSender,LPARAMlHint=0L,//在用户通过视图
CObject*pHint=NULL);//pSender修改了文档数据后,
//应调用该函数通知所有与文档相关联的其他视图窗口,
//若pSender=NULL,则通知与文档相关联的所有视图窗口
//该函数会调用每个视图类的OnUpdate成员函数
//一般是在调用SetModifiedFlag后调用该函数
缺省时,派生的文档类会覆盖其基类CObject的如下序列化成员函数
virtualvoidSerialize(CArchive&ar);
以支持文档的读写。
如
voidCTestDoc:
:
Serialize(CArchive&ar){
if(ar.IsStoring()){//写入
//TODO:
addstoringcodehere
ar< } else{//读取 //TODO: addloadingcodehere ar>>m_nWidth>>m_nHeight; } } 注意: 在派生应用程序类的InitInstance成员函数中缺省会调用其成员函数 LoadStdProfileSettings();//LoadstandardINIfileoptions(includingMRU) 来支持MRU(mostrecentlyused最近使用)文件列表功能,其函数原型为 voidLoadStdProfileSettings(UINTnMaxMRU=_AFX_MRU_COUNT); 若nMaxMRU=0,则不支持MRU。 _AFX_MRU_COUNT=4。 例如: LoadStdProfileSettings (2);LoadStdProfileSettings(10); 也可调用应用程序类的成员函数 virtualvoidAddToRecentFileList(LPCTSTRlpszPathName); 来向MRU文件列表中添加指定的文件路径串。 MFC将MRU功能封装在从CObject类派生的CRecentFileList类中。 3.框架窗口类 因为视图窗口是框架窗口的子窗口,位于框架窗口的客户区。 视图窗口本身只是一个没有边框、没有标题条、更没有菜单条和控制条的矩形区域。 视图窗口不能单独存在,必须依附于一个框架窗口。 框架窗口负责管理标题条、菜单条、控制条、加速键和视图窗口或文档子窗口。 框架窗口(类)也是通过文档模板(类)与视图(类)及文档(类)联系在一起的。 框架窗口与视图 MFC中框架窗口类为从窗口类CWnd派生的类CFrameWnd: SDI应用程序的主框架窗口一般以它为基类,如 classCMainFrame: publicCFrameWnd{ protected: //createfromserializationonly CMainFrame(); DECLARE_DYNCREATE(CMainFrame) ...... } 但MDI应用程序的主框架窗口则一般以其派生类CMDIFrameWnd为基类,如 classCMainFrame: publicCMDIFrameWnd{ DECLARE_DYNAMIC(CMainFrame) public: CMainFrame(); ...... } 而用户的文档子窗口的框架窗口则从另一个框架窗口类CMDIChildWnd派生。 如: classCChildFrame: publicCMDIChildWnd{ DECLARE_DYNCREATE(CChildFrame) public: CChildFrame(); ...... } MDI框架窗口与子窗口 框架窗口的创建过程 4.视图类 视图是文档与用户的接口,为用户提供观察、选择、编辑文档数据的交互界面。 MFC中的视图类为从CWnd派生的CView类及其派生类。 MFC应用程序的视图类的基类一般为CView,其他常用的视图基类有CScrollView、C[Rich]EditView、CFormView、CHtmlView和(MFC8.0新加的)CWndFormsView。 1)CView类 CView是用户视图类的缺省基类。 也是其他各种MFC视图类的基类。 例如: classCTestView: publicCView { protected: //仅从序列化创建 CTestView(); DECLARE_DYNCREATE(CTestView) //属性 public: CTestDoc*GetDocument()const; //操作 public: //重写 public: virtualvoidOnDraw(CDC*pDC);//重写以绘制该视图 virtualBOOLPreCreateWindow(CREATESTRUCT&cs); protected: virtualBOOLOnPreparePrinting(CPrintInfo*pInfo); virtualvoidOnBeginPrinting(CDC*pDC,CPrintInfo*pInfo); virtualvoidOnEndPrinting(CDC*pDC,CPrintInfo*pInfo); //实现 public: virtual~CTestView(); #ifdef_DEBUG virtualvoidAssertValid()const; virtualvoidDump(CDumpContext&dc)const; #endif protected: CDocument*m_pDocument; //生成的消息映射函数 protected: DECLARE_MESSAGE_MAP() }; CView类的常用成员函数有: CDocument*GetDocument()const;//获得对应文档类对象的指针 virtualvoidOnInitialUpdate();//初始化虚消息响应函数,可覆盖 virtualvoidOnActivateView(BOOLbActivate,CView*pActivateView, CView*pDeactiveView);//当视图窗口被激活或非激活时被调用 virtualvoidOnDraw(CDC*pDC)=0;//纯虚函数,必须覆盖 其基类CWnd的常用成员函数有: CDC*GetDC();//获得视图窗口的DC intReleaseDC(CDC*pDC);//释放视图窗口的DC voidGetClientRect(LPRECTlpRect)const;//获得客户区矩形 voidGetWindowRect(LPRECTlpRect)const;//获得窗口矩形 BOOLGetUpdateRect(LPRECTlpRect,BOOLbErase=FALSE); //获得需重绘的最小矩形 voidMoveWindow(intx,inty,intnWidth,intnHeight,BOOLbRepaint=TRUE); //改变窗口的位置和尺寸 voidMoveWindow(LPCRECTlpRect,BOOLbRepaint=TRUE); CFrameWnd*GetParentFrame()const;//获得父框架窗口的指针 CFrameWnd*GetTopLevelFrame()const;//获得顶层框架窗口的指针 voidInvalidate(BOOLbErase=TRUE);//使整个客户区矩形无效重画 voidUpdateWindow();//通过发送WM_PAINT消息来更新客户区 CWnd*SetCapture();//设置鼠标捕获 : : BOOLReleaseCapture(VOID);//释放设置鼠标捕获 CWnd*GetDlgItem(intnID)const;//获得nID对应的控件窗口指针 UINTGetDlgItemInt(intnID,BOOL*lpTrans=NULL,BOOLbSigned=TRUE)const; //获得/设置控件中显示的整数 voidSetDlgItemInt(intnID,UINTnValue,BOOLbSigned=TRUE); intGetDlgItemText(intnID,LPTSTRlpStr,intnMaxCount)const; intGetDlgItemText(intnID,CString&rString)const; //获得/设置控件中显示的串 voidSetDlgItemText(intnID,LPCTSTRlpszString); …… 2)GetDocument 缺省情况下,MFC会自动在派生的视图类中覆盖其成员函数GetDocument,使其能够获得派生的文档类指针。 应用程序中的GetDocument函数一般有两个版本: ●在头文件中定义的正式版(内联函数): #ifndef_DEBUG//TestView.cpp中的非调试版本 inlineCTestDoc*CTestView: : GetDocument()const {returnreinterpret_cast #endif ●在代码文件定义的测试版: #ifdef_DEBUG ...... CTestDoc*CTestView: : GetDocument()const//调试版本是内联的 { ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CTestDoc))); return(CTestDoc*)m_pDocument; } #endif//_DEBUG 在视图类中可以调用GetDocument函数来获得对应的文档对象,从而可显示、输出、编辑和修改文档数据。 如在OnDraw函数中MFC自动加入的语句: voidCTestView: : OnDraw(CDC*pDC) { CTestDoc*pDoc=GetDocument(); ASSERT_VALID(pDoc); if(! pDoc) return; //TODO: 在此处为本机数据添加绘制代码 } 需要注意的是,应用程序中的文档对象虽然在视图对象创建之前,已经被创建,但是文档类中(Serialize函数)对文件的读取则是在视图类创建之后,而且是在视图类的OnCreate和OnSize函数被调用之后,但是是在视图类的OnInitialUpdate函数之前(参见下面的创建应用程序过程图)。 所以不能在视图类的构造函数中调用GetDocument,不然得到的将是一个空文档的指针,利用该指针对文档类数据的任何操作都会导致系统的致命错误(因为其变量还没有初始化)。 创建SDI/MDI应用程序的过程 (实线箭头表示实际过程,虚线箭头表示逻辑过程) 视图的初始化过程 若希望在文档数据被显示之前,根据文档中的参数做一些初始化工作(如按图像的大小改变窗口的尺寸),可以在视图类中添加(重写型)消息响应函数OnInitialUpdate(该函数是在窗口已经创建但还没有显示时被系统调用,这时文档对象已经存在,而且文档文件已经被读取),并在此函数中作一些必要的文档操作。 3)CScrollView类 如果文档较大(如大尺寸图像),不能一次在视图窗口中完整显示,则必须使用滚动窗口。 此时,用户视图类必须以CView的派生类CScrollView为基类,该类可以自动支持文档的滚动。 滚动视图类CScrollView是MFC提供的一种自动化程度非常高的滚动窗口类,可在创建项目时,在“MFC应用程序向导”最后一步的“生成的类”页,将C*View的基类从缺省的CView改成CScrollView。 对已经存在的项目,可在*View.h和*View.cpp文件中,将所有的CView替换成CScrollView。 替换方法和步骤: 可以选“编辑\查找和替换\在文件中替换”菜单项或按“Ctrl+Shift+H”组合键,打开“查找和替换”对话框,在“查找内容”栏中输入“CView”、在“替换为”栏中输入“CScrollView”,保持“查找范围”栏的“整个解决方案”选项不变,按该对话框右下角的“全部替换”按钮。 在OnInitialUpdate函数中或其他需要的地方调用CScrollView类的成员函数SetScrollSizes来设置滚动的范围和参数: voidSetScrollSizes(intnMapMode,SIZEsizeTotal,constSIZE&sizePage=sizeDefault, constSIZE&sizeLine=sizeDefault); 例如: (其中: m_iWidth、h为视图类的整型类变量,init为视图类的布尔类变量(初始化为false)),参见“03绘图-2(打印)”中的“3.8位图”的“9.CImage类”的“2)例子” voidCImageView: : OnInitialUpdate(){ CScrollView: : OnInitialUpdate(); CImageDoc*pDoc=GetDocument(); //对滚动视图类,必须设置滚动的尺寸 if(pDoc->img.IsNull())SetScrollSizes(MM_TEXT,CSize(100,100)); else{ m_iWidth=pDoc->img.GetWidth();m_iHeight=pDoc->img.GetHeight(); RECTcrect; GetClientRect(&crect); SetScrollSizes(MM_TEXT,CSize(m_iWidth,m_iHeight),CSize(crect.right,crect.bottom),CSize(10,10)); //GetParentFrame()->RecalcLayout();//对单文档界面 ResizeParentToFit(); m_bInit=true; } } 还可以在用户改变窗口大小时,调整滚动的页面和行的大小。 例如: voidCImageView: : OnSize(UINTnType,intcx,intcy){ CScrollView: : OnSize(nType,cx,cy); //TODO: 在此处添加消息处理程序代码 CImageDoc*pDoc=GetDocument(); ASSERT_VALID(pDoc); if(! pDoc->img.IsNull()){
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 04 文档 视图