文档与串行化笔记—孙鑫(转)
转自:http://blog.csdn.net/peng6662001/archive/2006/03/29/642366.aspx(稍作修改)
串行化概念
把文件在磁盘上保存下来 叫做串行化
使用CArchive:
写入:
CFile file("1.txt",CFile::modeCreate | CFile::modeWrite);
CArchive ar(&file,CArchive::store);
int i=4;
float b=1.3f; //C默认用float定义而不加f的为double型
CString str="SongPeng";
ar<<i<<b<<str;
读取:
CFile file("1.txt",CFile::modeRead);
CArchive ar(&file,CArchive::load);
int i;
float b;
CString str;
CString strRestult;
ar>>i>>b>>str;
strRestult.Format("%d %f %s",i,b,str);
MessageBox(strRestult);
设置文档标题的三种方法:
l 在BOOL CGraphicDoc::OnNewDocument()中,我们可以设置文档,例如:
SetTitle("SongPeng")
l 我们也可以在String Table中IDR_MAINFRAME第二个标题,
l 在新建工程的第四部advance选项中也能进行修改
IDR_MAINFRAME
其中的IDR_MAINFRAME中的字串各子串之间用/n分割,可以有空子串。
各子串定义如下:
CDocTemplate::windowTitle
CDocTemplate::docName
CDocTemplate::fileNewName
CDocTemplate::filterName
CDocTemplate::filterExt
CDocTemplate::regFileTypeId
CDocTemplate::regFileTypeName
小知识点:凡是从CCmdTarget派生出的类,都可以间接接受命令消息
生成可串行化的类:
分为五步:
l 是CObject的派生类
l 重写Serialize函数
l 在声明(*.h)中使用DECLARE_SERIAL(class_name)宏
l 定义无参数的构造函数
l 实现(*.cpp)中使用IMPLEMENT_SERIAL宏
参考:IMPLEMENT_SERIAL(CGraph,CObject,1),1为版本号,保存和读取时版本号必须相同
在文档类中获得视图类的指针
例子:
POSITION pos=GetFirstViewPosition();
//pos是下一个视图的指针,若无,则返回NULL
CGraphicView *pView=(CGraphicView *)GetNextView(pos);
我们文档类中调用Serialize保存一个可串行化的类的数据时实际上是利用了这个对象本身的Serialize函数,这个对象需要什么对象,都需要在你编写可串行化的类时去确定
CObArray保存CObject派生类:
特点:
l 支持串行化
l 常作为文档类的成员(视图类中调用GetDocument()函数)
示例代码:
CGraph *pGraph=new CGraph(m_nDrawType,m_pOrigin,point);
m_obArray.Add(pGraph);
注意:删除CobArray元素的时候,因为CobArray保存的指针,所以首先应该delete指针指向的对内存,然后在remove指针元素。不管是新建文档还是打开另外一份文档,都会调用DeletContents,以保证新建文档时空的,CDocument::DeleteContents()会在打开,新建,关闭文档时被调用
void CGraphicDoc::DeleteContents()
{
// TODO: Add your specialized code here and/or call the base class
int nCount;
nCount=m_obArray.GetSize();
for(int i=0;i<nCount;i++)
{
delete m_obArray.GetAt(i); //解除指针与值之间的联系,但没有清除堆内存
m_obArray.RemoveAt(i); //清除堆内存,出错!!!
}
CDocument::DeleteContents();
}
RemoveAt会导致数组中数据的重排
因此,需要把以上代码修改为
void CGraphicDoc::DeleteContents()
{
// TODO: Add your specialized code here and/or call the base class
int nCount;
nCount=m_obArray.GetSize();
for(int i=0;i<nCount;i++)
{
delete m_obArray.GetAt(i);
}
m_obArray.RemoveAll();
CDocument::DeleteContents();
}
另一种方法
while (nCount--)
{
delete m_obArray.GetAt(nCount);
m_obArray.RemoveAt(nCount);
}
Document/View结构
l 在MFC中,文档类负责管理数据,提供保存和数据加载的功能。视类负责数据的显示,以及给用户提供对数据的编辑和修改功能。
l MFC给我们提供Document/View结构,将一个应用程序所需要的数据处理与显示的函数的空壳都设计好了,这些函数都是需函数,我们可以在派生类中重写这些函数。有关文件读写的操作在CDocument的Serialize函数中进行,有关数据和图形显示的操作在CView的OnDraw函数中进行。我们在其派生类中,只需要去关注serialize和OnDraw函数就可以了,其他的细节我们不需要去理会,程序就可以良好的运行。
l 当我么按下"File/Open",Application Framework会激活文件打开对话框,让你指定文件名,然后自动调用CGraphicView::OnDraw,传递一个显示DC,让你重新绘制窗口内容。
l MFC给我们提供Document/View结构,是希望我们将精力放在数据结构的设计和数据显示的操作上,而不是把时间和精力花费在对象与对象之间,模块与模块之间的通信上。
l 一个文档对象可以和多个视类对象相关联,而一个视类对象只能和一个文档类对象相关联
视图文档类的交互:
文档类调用
UpdateAllViews(NULL);//更新所有此文档派生的视图;
视图类调用虚函数:
OnUpdate//更新数据
新建文档运行路径:
void CWinApp::OnFileNew()--->void CDocManager::OnFileNew()--->
CDocTemplate* pTemplate = (CDocTemplate*)m_templateList.GetHead();--->
pTemplate->OpenDocumentFile(NULL);--->CDocument*
CSingleDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName,
BOOL bMakeVisible)--->pDocument = CreateNewDocument();
--->pFrame = CreateNewFrame(pDocument, NULL);--->
if (!pDocument->OnNewDocument())--->BOOL CGraphicDoc::OnNewDocument()
打开文档运行路径
void CWinApp::OnFileOpen()--->void CDocManager::OnFileOpen()--->
DoPromptFileName--->BOOL CDocManager::DoPromptFileName(CString& fileName, UINT nIDSTitle, DWORD lFlags, BOOL bOpenFileDialog, CDocTemplate* pTemplate)--->打开一个文件--->AfxGetApp()->OpenDocumentFile(newName);--->
CDocument* CWinApp::OpenDocumentFile(LPCTSTR lpszFileName)--->
CDocument* CDocManager::OpenDocumentFile(LPCTSTR lpszFileName)--->
match = pTemplate->MatchDocType(szPath, pOpenDocument);--->
判断pOpenDocument是否为空,pOpenDocument用来指定是否与先前的文档关联,即获取先前相同文档的指针,如果是,不再对文档进行操作---->
CDocument* CSingleDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName,
BOOL bMakeVisible)--->if (pDocument == NULL)--->if (pFrame == NULL)--->
if (lpszPathName == NULL)--->if (!pDocument->OnOpenDocument(lpszPathName))--->
BOOL CDocument::OnOpenDocument(LPCTSTR lpszPathName)---->
Serialize(loadArchive);---->void CGraphicDoc::Serialize(CArchive& ar)