孙鑫VC++视频教程笔记(13)文档与串行化

把文件在磁盘上保存下来 叫做串行化
可以使用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);
在BOOL CGraphicDoc::OnNewDocument()中,我们可以设置文档,例如:
 SetTitle("SongPeng")
 
OnNewDocument()用来在程序运行之初构造文档,或是新建文档:
Called by the framework as part of the File New command. The default implementation of this function calls the DeleteContents member function to ensure that the document is empty and then marks the new document as clean. Override this function to initialize the data structure for a new document. You should call the base class version of this function from your override.

我们已可以在String Table中修改标题,其中的IDR_MAINFRAME中的字串原为:
Graphic/n/nGraphi/n/n/nGraphic.Document/nGraphi Document
各子串之间用/n分割,可以有空子串。
各子串定义如下:
CDocTemplate::windowTitle   Name that appears in the application window’s title bar (for example, “Microsoft Excel”). Present only in the document template for SDI applications.


CDocTemplate::docName   Root for the default document name (for example, “Sheet”). This root, plus a number, is used for the default name of a new document of this type whenever the user chooses the New command from the File menu (for example, “Sheet1” or “Sheet2”). If not specified, “Untitled” is used as the default.


CDocTemplate::fileNewName   Name of this document type. If the application supports more than one type of document, this string is displayed in the File New dialog box (for example, “Worksheet”). If not specified, the document type is inaccessible using the File New command.


CDocTemplate::filterName   Description of the document type and a wildcard filter matching documents of this type. This string is displayed in the List Files Of Type drop-down list in the File Open dialog box (for example, “Worksheets (*.xls)”). If not specified, the document type is inaccessible using the File Open command.


CDocTemplate::filterExt   Extension for documents of this type (for example, “.xls”). If not specified, the document type is inaccessible using the File Open command.


CDocTemplate::regFileTypeId   Identifier for the document type to be stored in the registration database maintained by Windows. This string is for internal use only (for example, “ExcelWorksheet”). If not specified, the document type cannot be registered with the Windows File Manager.


CDocTemplate::regFileTypeName   Name of the document type to be stored in the registration database. This string may be displayed in dialog boxes of applications that access the registration database (for example, “Microsoft Excel Worksheet”).

在前两个/n之间加入字符串,就达到修改标题的效果。

在新建工程的第四部advance选项中也能进行修改

凡是从CCmdTarget派生出的类,都可以间接接受命令消息

新建文档运行路径:
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()

CWinApp负责管理文档管理器

打开文档运行路径
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)

生成可串行化的类:
 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为版本号,保存和读取时版本号必须相同
一个文档类对象能和多个视类对象相关,一个视类对象只和一个文档类对象相关.

单文档类只有一个视类对象,要获取视类对象的指针
要在文档类中访问定义在视类中的对象,首先要获得视类的指针.需要用到函数
CDocument::GetFirstViewPosition 得到视类对象的位置
virtual POSITION GetFirstViewPosition( ) const;
A POSITION value that can be used for iteration with the GetNextView member function.
Call this function to get the position of the first view in the list of views associated with the document.
然后再调用GetNextView得到视类对象的指针
 POSITION pos=GetFirstViewPosition();
 CGraphicView *pView=(CGraphicView *)GetNextView(pos);

POSITION   A value used to denote the position of an element in a collection; used by MFC collection classes.

我们文档类中调用Serialize保存一个可串行化的类的数据时实际上是利用了这个对象本身的Serialize函数,这个对象需要什么对象,都需要在你编写可串行化的类时去确定

void CGraph::Serialize(CArchive &ar)
{
 if(ar.IsStoring())
 {
  ar<<m_nDrawType<<m_pOrigin<<m_pEnd;
 }
 else
 {
  ar>>m_nDrawType>>m_pOrigin>>m_pEnd;
 }
}

void CGraphicDoc::Serialize(CArchive& ar)
{
 POSITION pos=GetFirstViewPosition();
 CGraphicView *pView=(CGraphicView *)GetNextView(pos);
 if (ar.IsStoring())
{
  int nCount=pView->m_obArray.GetSize();
  ar<<nCount;
  for(int i=0;i<nCount;i++)
  {
   ar<<pView->m_obArray.GetAt(i);
  }
 }
 else
 {
  int nCount;
  ar>>nCount;
  CGraph *pGraph;
  for(int i=0;i<nCount;i++)
  {
   ar>>pGraph;
   pView->m_obArray.Add(pGraph);
  }
 }
}

数组的保存:
 CGraph *pGraph=new CGraph(m_nDrawType,m_pOrigin,point);
 m_obArray.Add(pGraph);

CObArray incorporates the IMPLEMENT_SERIAL macro to support serialization and dumping of its elements. If an array of CObject pointers is stored to an archive, either with the overloaded insertion operator or with the Serialize member function, each CObject element is, in turn, serialized along with its array index
void CGraphicDoc::Serialize(CArchive& ar)可被修改为:
void CGraphicDoc::Serialize(CArchive& ar)
{
 POSITION pos=GetFirstViewPosition();
 CGraphicView *pView=(CGraphicView *)GetNextView(pos);
 if (ar.IsStoring())
{
}
else
{
}
pView->m_obArrary.Serialize(ar);
}

以下是CObArray在MFC中的源代码:
void CObArray::Serialize(CArchive& ar)
{
 ASSERT_VALID(this);

 CObject::Serialize(ar);

 if (ar.IsStoring())
 {
  ar.WriteCount(m_nSize);
  for (int i = 0; i < m_nSize; i++)
   ar << m_pData[i];
 }
 else
 {
  DWORD nOldSize = ar.ReadCount();
  SetSize(nOldSize);
  for (int i = 0; i < m_nSize; i++)
   ar >> m_pData[i];
 }
}

文档类时用来管理数据的我们把CObArray m_obArray放入文档类中
以下为自动生成类,这是在View类中准备好的可以获得文档来指针的函数:
CGraphicDoc* CGraphicView::GetDocument() // non-debug version is inline
{
 ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CGraphicDoc)));
 return (CGraphicDoc*)m_pDocument;
}

 在View中可以这样调用m_obArray
CGraphicDoc *pDoc=GetDocument();
 pDoc->m_obArray.Add(pGraph);

Document/View结构
在MFC中,文档类负责管理数据,提供保存和数据加载的功能。视类负责数据的显示,以及给用户提供对数据的编辑和修改功能。
MFC 给我们提供Document/View结构,将一个应用程序所需要的数据处理与显示的函数的空壳都设计好了,这些函数都是需函数,我们可以在派生类中重写 这些函数。有关文件读写的操作在CDocument的Serialize函数中进行,有关数据和图形显示的操作在CView的OnDraw函数中进行。我 们在其派生类中,只需要去关注serialize和OnDraw函数就可以了,其他的细节我们不需要去理会,程序就可以良好的运行。
当我么按下"File/Open",Application Framework会激活文件打开对话框,让你指定文件名,然后自动调用CGraphicView::OnDraw,传递一个显示DC,让你重新绘制窗口内容。
MFC给我们提供Document/View结构,是希望我们将精力放在数据结构的设计和数据显示的操作上,而不是把时间和精力花费在对象与对象之间,模块与模块之间的通信上。
一个文档对象可以和多个视类对象相关联,而一个视类对象只能和一个文档类对象相关联

不管是新建文档还是打开另外一份文档,都会调用DeletContents,以保证新建文档时空的

释放对内存
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();
}
CDocument::DeleteContents()会在打开,新建,关闭文档时被调用

CObArray::RemoveAt
Removes one or more elements starting at a specified index in an array. In the process, it shifts down all the elements above the removed element(s). It decrements the upper bound of the array but does not free memory.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);
 }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值