阅读本文前,我们假设您已经:
1,知道如何创建一个单文档的App Wizard
2,知道C++ 类、函数重载等简单知识
3,知道如何给View类或者Doc文档添加成员变量
4,会用MFC的IDE调试工具最好,那么本文的程序您可以copy去调试
5,知道如何为某个框架类添加虚函数或消息处理函数
本课内容:
1, 首先讲解了一下什么是串行化,
2, 然后建立一个可串行化的类,并串行化之
一、 CArchive 和串行化
把对象(一个类)保存在永久性媒质上,比如磁盘。然后读取时,可以在内存中重新构建这个对象。把对象存储在磁盘的过程称为“串行化”。
一个Archive和一个文件相关,并且允许带缓冲的写和从存储器读出数据。
创建CArchive之前必须创一个一个CFile,必须保证CArchive的load/store状态和文件的打开模式相一致。一个文件只能有一个活动的CArchive。
当你创建一个CArchive对象时,和CFile或者其派生类关联来表示一个打开的文件。也可以指定CArchive是否是用来load或store。Archive不仅可以处理基本类型,也可以处理CObject派生
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<
读取:
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);
Note:读取和保存的格式、顺序要完全一致
二、 文档调用顺序
OnNewDocument()是虚函数。在程序运行之初构造文档,或是新建文档。
可以用GetDocString()函数获取IDR_MAINFRAME字符串的内容
修改Doc标题:
(1) 可以在其中设置文档标题SetTitle("XXXX"),
(2) 在String Table中修改标题字段
(3) 在新建工程的第四部advance选项中也能进行修改
点击“新建”后,先调用OnFileNew()函数,在OnFileNew中再调用OnNewDocument().
Void CwinApp::OnFIleNew(){
If(m_pDocManager != NULL)m_pDocManager->OnFileNew();
}
OnNewDocument()函数内部调用过程:
1, voidCWinApp::OnFileNew()中调用CDocManager*类型的成员变量m_pDicManager的OnFileNew函数:
m_pDicManager->OnFileNew()
2, 在CDocManager::OnFileNew()中从文档链表取出文档指针。
(在这个OnFileNew中调用OpenDocumentFile(),以下两步都是本函数内语句)
pTemplate = (CDocTemplate*)m_templateList.GetHead();
执行pTemplate->OpenDocumentFile(NULL);语句
//调用单文档的OpenDocumentFile()
3, CDocument* CSingleDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName, BOOL bMakeVisible)
(在OpenDocumentFile中创建文档、视类、和框架类对象)
pDocument = CreateNewDocument();
pFrame = CreateNewFrame(pDocument, NULL);
if (!pDocument->OnNewDocument())
BOOL CGraphicDoc::OnNewDocument()
三、 串行化Serialize(CArchive &ar)
保存和读取数据的函数。点击“打开”或者“保存”菜单,最先调用此函数
执行例子:
if(ar.IsStoring())
{ar<
else
{ ar>>m_nDrawType>>m_pOrigin>>m_pEnd;}
我们文档类中调用Serialize保存一个可串行化的类的数据时实际上是利用了这个对象本身的Serialize函数,这个对象需要什么对象,都需要在你编写可串行化的类时去确定
OnFileOpen函数调用内部过程
void CWinApp::OnFileOpen()中调用
void CDocManager::OnFileOpen()中调用DoPromptFileName
在其中获得打开文件对话框,
然后回到CDocManager::OnFileOpen()中,再调用
AfxGetAp()->OpenDocumentFile();在其中初始化pOpenDocument指针,注意其中执行match=pTemplate->MatchDocType()查看是否有打开文档。如果文档已经打开,就不会调用Serialize()函数
生成可串行化的类的五个步骤:
A serializable class usually has a Serialize member function, and it usually uses the DECLARE_SERIAL and IMPLEMENT_SERIAL macros, as described under class CObject.
分为五步:
1 . Deriving your class from CObject (or from some class derived from CObject).(即生成可串行化的类)
2 . Overriding the Serialize member function.
3 . Using the DECLARE_SERIAL macro in the class declaration.
4 . Defining a constructor that takes no arguments.
5 . Using the IMPLEMENT_SERIAL macro in the implementation file for your class.
IMPLEMENT_SERIAL(CGraph,CObject,1),1为版本号,保存和读取时版本号必须相同一个文档类对象能和多个视类对象相关,一个视类对象只和一个文档类对象相关.
CPtr类和CObArray类很相似,只是CObArray类的add增加的是CObject *指针类型。
类存入文件的例子
void CGraphicDoc::Serialize(CArchive& ar){
POSITION pos=GetFirstViewPosition();//多文档的时候,有多个view
CGraphicView *pView=(CGraphicView *)GetNextView(pos);
if (ar.IsStoring()){
int nCount=pView->m_obArray.GetSize();
ar<
for(int i=0;i<<PVIEW->m_obArray.GetAt(i);}
}
else {
int nCount;ar>>nCount;//读出数目
CGraph *pGraph;
for(int i=0;i>pGraph;pView->m_obArray.Add(pGraph);}
}
}
类对象存入数组
CGraph *pGraph=new CGraph(m_nDrawType,m_pOrigin,point);
m_obArray.Add(pGraph);
一个文档来可以有多个相关的视类对象,而一个视类对象只能有一个文档类,要获得一个视类对象指针,就需要获得第一个视类对象在链表中的指针。然后通过POSITION值,调用GetNextView()不断获取视类对象
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)
1,知道如何创建一个单文档的App Wizard
2,知道C++ 类、函数重载等简单知识
3,知道如何给View类或者Doc文档添加成员变量
4,会用MFC的IDE调试工具最好,那么本文的程序您可以copy去调试
5,知道如何为某个框架类添加虚函数或消息处理函数
本课内容:
1, 首先讲解了一下什么是串行化,
2, 然后建立一个可串行化的类,并串行化之
一、 CArchive 和串行化
把对象(一个类)保存在永久性媒质上,比如磁盘。然后读取时,可以在内存中重新构建这个对象。把对象存储在磁盘的过程称为“串行化”。
一个Archive和一个文件相关,并且允许带缓冲的写和从存储器读出数据。
创建CArchive之前必须创一个一个CFile,必须保证CArchive的load/store状态和文件的打开模式相一致。一个文件只能有一个活动的CArchive。
当你创建一个CArchive对象时,和CFile或者其派生类关联来表示一个打开的文件。也可以指定CArchive是否是用来load或store。Archive不仅可以处理基本类型,也可以处理CObject派生
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<
读取:
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);
Note:读取和保存的格式、顺序要完全一致
二、 文档调用顺序
OnNewDocument()是虚函数。在程序运行之初构造文档,或是新建文档。
可以用GetDocString()函数获取IDR_MAINFRAME字符串的内容
修改Doc标题:
(1) 可以在其中设置文档标题SetTitle("XXXX"),
(2) 在String Table中修改标题字段
(3) 在新建工程的第四部advance选项中也能进行修改
点击“新建”后,先调用OnFileNew()函数,在OnFileNew中再调用OnNewDocument().
Void CwinApp::OnFIleNew(){
If(m_pDocManager != NULL)m_pDocManager->OnFileNew();
}
OnNewDocument()函数内部调用过程:
1, voidCWinApp::OnFileNew()中调用CDocManager*类型的成员变量m_pDicManager的OnFileNew函数:
m_pDicManager->OnFileNew()
2, 在CDocManager::OnFileNew()中从文档链表取出文档指针。
(在这个OnFileNew中调用OpenDocumentFile(),以下两步都是本函数内语句)
pTemplate = (CDocTemplate*)m_templateList.GetHead();
执行pTemplate->OpenDocumentFile(NULL);语句
//调用单文档的OpenDocumentFile()
3, CDocument* CSingleDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName, BOOL bMakeVisible)
(在OpenDocumentFile中创建文档、视类、和框架类对象)
pDocument = CreateNewDocument();
pFrame = CreateNewFrame(pDocument, NULL);
if (!pDocument->OnNewDocument())
BOOL CGraphicDoc::OnNewDocument()
三、 串行化Serialize(CArchive &ar)
保存和读取数据的函数。点击“打开”或者“保存”菜单,最先调用此函数
执行例子:
if(ar.IsStoring())
{ar<
else
{ ar>>m_nDrawType>>m_pOrigin>>m_pEnd;}
我们文档类中调用Serialize保存一个可串行化的类的数据时实际上是利用了这个对象本身的Serialize函数,这个对象需要什么对象,都需要在你编写可串行化的类时去确定
OnFileOpen函数调用内部过程
void CWinApp::OnFileOpen()中调用
void CDocManager::OnFileOpen()中调用DoPromptFileName
在其中获得打开文件对话框,
然后回到CDocManager::OnFileOpen()中,再调用
AfxGetAp()->OpenDocumentFile();在其中初始化pOpenDocument指针,注意其中执行match=pTemplate->MatchDocType()查看是否有打开文档。如果文档已经打开,就不会调用Serialize()函数
生成可串行化的类的五个步骤:
A serializable class usually has a Serialize member function, and it usually uses the DECLARE_SERIAL and IMPLEMENT_SERIAL macros, as described under class CObject.
分为五步:
1 . Deriving your class from CObject (or from some class derived from CObject).(即生成可串行化的类)
2 . Overriding the Serialize member function.
3 . Using the DECLARE_SERIAL macro in the class declaration.
4 . Defining a constructor that takes no arguments.
5 . Using the IMPLEMENT_SERIAL macro in the implementation file for your class.
IMPLEMENT_SERIAL(CGraph,CObject,1),1为版本号,保存和读取时版本号必须相同一个文档类对象能和多个视类对象相关,一个视类对象只和一个文档类对象相关.
CPtr类和CObArray类很相似,只是CObArray类的add增加的是CObject *指针类型。
类存入文件的例子
void CGraphicDoc::Serialize(CArchive& ar){
POSITION pos=GetFirstViewPosition();//多文档的时候,有多个view
CGraphicView *pView=(CGraphicView *)GetNextView(pos);
if (ar.IsStoring()){
int nCount=pView->m_obArray.GetSize();
ar<
for(int i=0;i<<PVIEW->m_obArray.GetAt(i);}
}
else {
int nCount;ar>>nCount;//读出数目
CGraph *pGraph;
for(int i=0;i>pGraph;pView->m_obArray.Add(pGraph);}
}
}
类对象存入数组
CGraph *pGraph=new CGraph(m_nDrawType,m_pOrigin,point);
m_obArray.Add(pGraph);
一个文档来可以有多个相关的视类对象,而一个视类对象只能有一个文档类,要获得一个视类对象指针,就需要获得第一个视类对象在链表中的指针。然后通过POSITION值,调用GetNextView()不断获取视类对象
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)