1. 文档的基本功能:
1) 文档就是程序数据的一种抽象表示,可以表示数据库连接资源、文本文字等任何形式的数据;
2) 文档对象主要为视图提供公用成员函数,使其可以访问文档的数据,但所有的数据处理都由文档对象自己完成;
2. 文档类的主要操作:
1) 操作和可覆盖函数:在MFC文献中,操作被描述为非虚拟类的成员函数,而可覆盖函数即虚函数;
2) const String& CDocument::GetPathName() const; // 获取当前文档的绝对路径,如果文档还未命名则返回空
3) const String& CDocument::GetTitle() const; // 获取当前文档的标题,就是去掉路径和后缀,同样,如果文档还未命名则返回空
4) virtual BOOL CDocument::IsModified(); // 判断文档再最近一次保存之后是否被修改过
5) virtual void CDocument::SetModifiedFlag(BOOL bModified = TRUE); // 直接设置文档是否被修改的标志
!!IsModified和SetModifiedFlag可以实现自动化的保存更改提示,你只要通过这两个函数设置了修改标志就可以让MFC在程序关闭时提示用户该文档是否修改过,是否要保存更改,无须自己去实现弹出提示框提示保存更改;
6) void CDocument::UpdateAllViews(CView* pSender, LPARAM lHint = 0L, CObject* pHint = NULL);
!!该函数将会更新重画相应视图(内部调用了具体视图的OnUpdate函数);
i. pSender表示具体要更新的视图,如果为NULL表示与之相关的所有视图都要更新;
ii. lHint和pHint表示和更新有关的信息,这里暂时用不到,因此就直接使用默认值即可;
iii. 即使是单视图的应用程序也可以调用该函数来更新当前视图;
7) 通过GetFirstViewPosition和GetNextView来迭代程序的所有视图:
i. virtual POSITION CDocument::GetFirstViewPosition() const; // 将返回与当前文档相关联的第一个视图的位置指针
ii. virtual CView* CDocument::GetNextView(POSITION& rPosition) const; // 根据位置信息获取下一个视图的指针
iii. UpdateAllViews就是使用这两个函数来迭代更新所有视图的:
!!OnUpdate是CView的保护性成员,但是在CDocument中却可以自由访问该程序,原因是CDocument在底层被声明为CView的友元!!
1) OnNewDocument和OnOpenDocument:
i. 前者是响应File菜单的New菜单项用来创建新的文档,后者响应File菜单的Open菜单项来从磁盘中打开一个已存在的文档;
ii. 两者的主要目的都是为了执行一些专门的初始化(对文档对象中的数据成员执行一些特殊的初始化),那么问题就来了!文档对象不是有自己的构造函数吗?为啥不直接用构造函数来初始化呢?
!!这里先要理解一下永久数据和非永久数据的概念:
a. 永久数据:就是那些要保存在磁盘还要读出的那些数据(一般要通过串行化来实现此类数据的交换);
b. 非永久数据:无须保存在磁盘里的一些辅助行数据,比如一些标志等(判断文档是否被修改,某个逻辑判断的标志)以及其它数据(数据库连接资源等);
!!构造函数一般用来初始化一些非永久数据,而通常是在创建文档和打开文档时对对象中的一些永久数据进行特定的初始化,因此OnNewDocument和OnOpenDocument覆盖得比较多;
iii. 通常New比Open覆盖的频率更高,以为Open会在基类Open中间接调用Serialize串行化来初始永久数据,而New是创建一个空的新文档,需要手动初始化数据的需求更加大;
iv. 函数原型:
a. virtual BOOL CDocument::OnNewDocument();
b. virtual BOOL CDocument::OnOpenDocument(LPCTSRT lpszPathName);
!!!使用Wizard创建文档/视图结构程序时,MFC会提供这两个函数的默认实现,以方便用户覆盖(因为这两个函数覆盖得实在太频繁了),覆盖时一定要注意调用基类的响应函数!!
2) DeleteContents函数:
i. 该函数在文档被打开和关闭时调用,用来删除当前文档对象中已有的数据;
ii. 不能理解的是为何要在打开之前也要删除文档对象中的内容呢?因为通常一个程序在打开一个文档并处理完后可能会再打开另一个文档,那么此时程序应该显示新文档中的内容,那么前一个文档中的内容就理所当然的应该被删除了!
iii. 原型:virtual void CDocument::DeleteContents();
iv. 通常需要覆盖该函数来删除一些特殊的资源,比如数据库连接资源等;
3) Serialize函数:
i. 用来串行化文档的永久数据;
ii. 对于可串行化数据直接使用<<和>>串行化;
iii. 对于不能串行化的数据可以使用CArchive的Read和Write或者ReadString、WriteString读写磁盘;
iv. 如果还不行就直接使用CArchive的GetFile获取文件的CFile指针直接与文件进行底层的交互;
!!一般所有对象都可以进行串行化,那行没有默认串行化的类可以自己实现串行化协议使之串行化;
!!其它不常覆盖的函数:
a. OnCloseDocument:文档关闭时调用;
b. OnSaveDocument:文档保存时调用;
c. SaveModified:在文档未保存被关闭时调用,用以询问用户是否要做保存修改;
d. ReportSaveLoadException:串行化发生错误时调用;