必须注意以下几点:
1. 打开文件事件和写入文件事件必须在document类里里实现,如下:
void CMageDoc::OnFileSave()
{
if(m_savefilepath.IsEmpty())
{
OnFileSaveAs();
}
//else if(IsModified())
else if(true)
{
DoSave(m_savefilepath,TRUE);
}
else
{
//没有修改
}
}
void CMageDoc::OnFileSaveAs()
{
CString tmpStr;
tmpStr.Format(_T("Solution File (*%s)|*%s"),FILE_EXTENSION,FILE_EXTENSION);
CFileDialog tmpDialg(FALSE,FILE_EXTENSION,_T("TEST"),OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,tmpStr,NULL,NULL,TRUE);
if(tmpDialg.DoModal() == IDOK)
{
m_savefilepath = tmpDialg.GetFileName();
OnFileSave(); //会触发Document类的serialize方法
}
}
void CMageDoc::OnFileOpen()
{
//打开文件框
CString tmpStr;
tmpStr.Format(_T("Solution File (*%s)|*%s"),FILE_EXTENSION,FILE_EXTENSION);
CFileDialog tmpDialg(TRUE,FILE_EXTENSION,_T("TEST"),OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,tmpStr,NULL,NULL,TRUE);
if(tmpDialg.DoModal() == IDOK)
{
CString tmpFP = tmpDialg.GetPathName();
czDevs->ReleaseObj();
OnOpenDocument(tmpFP); //会触发Document类的serialize方法
}
}
2. 所需保存的数据所属的类必须继承自实现了序列化功能的父类(即实现了IMPLEMENT_DYNCREATE/ DECLARE_DYNCREATE宏的类)
DECLARE_DYNCREATE(CMageDoc)
IMPLEMENT_DYNCREATE(CMageDoc, CDocument)
3. Document类必须重写Serialize函数
void CMageDoc::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
//保存DVI CDVI类实现了序列化功能
ar << czDevs->czDVIs.size();
vector<shared_ptr<CDVI>>::iterator dvibi = czDevs->czDVIs.begin(),
dviei = czDevs->czDVIs.end();
while(dvibi != dviei)
{
ar << dvibi->get();
++dvibi;
}
//保存SECT CSECT类实现了序列化功能
ar << czDevs->czSECTs.size();
vector<shared_ptr<CSECT>>::iterator sectbi = czDevs->czSECTs.begin(),
sectei = czDevs->czSECTs.end();
while(sectbi != sectei)
{
ar << sectbi->get();
++sectbi;
}
}
else
{
//读取DVI
int nDvis;
ar >> nDvis;
while(nDvis--)
{
//CDVI* tmpDvi = new CDVI;
CDVI* tmpDvi;
ar >> tmpDvi;
czDevs->AddDVI(tmpDvi);
}
//读取SECT
int nSects;
ar >> nSects;
while(nSects--)
{
CSECT* tmpSect;
ar >> tmpSect;
czDevs->AddSECT(tmpSect);
}
}
}
4. 子类必须重写Serialize函数
void CLDU::Serialize(CArchive& ar)
{
ASSERT_VALID(this);
if (ar.IsStoring())
{
ar << strName << nType << nMaxPortX << nMaxPortY << nWidth << nHeight << nXPos
<< nYPos << strSN << commType << commIP1 << commPort1 << commIP2 << commPort2
<< commCOM << commBR;
for(int i=0;i<MAX_PORT_PER_LDU;i++)
{
//以下操作繁琐,所以在结构体中重载操作符 << 实现结构体序列化功能
//ar << Port[i].nNumber << Port[i].nType << Port[i].nWidth << Port[i].nHeight << Port[i].nX
// << Port[i].nY << Port[i].nBrightness << Port[i].nMaxBrightness << Port[i].nMinBrightness << Port[i].nGamma
// << (WORD)Port[i].nSignalInPos << (WORD)Port[i].nSignalDir << Port[i].nTempIndex;
//for(int j=0;j<MAX_TEMP_GROUP;j++)
//{
// ar << Port[i].nTempR[j] << Port[i].nTempG[j] << Port[i].nTempB[j];
//}
//ar << Port[i].nTotalTiles;
//Tile* tile = Port[i].Tiles;
//int nTiles = Port[i].nTotalTiles;
//while(tile != NULL)
//{
// ar << tile->nTileType << tile->nWidth << tile->nHeight << tile->nX << tile->nY << tile->nLineStyle
// << tile->strSN << tile->PosX << tile->PosY;
// ar << tile->TileStat.cpuVer << tile->TileStat.fpgaVer << tile->TileStat.temp << tile->TileStat.current
// << tile->TileStat.volate << tile->TileStat.brightness;
// --nTiles;
// tile = tile->next;
//}
//ASSERT(nTiles == 0);
ar << Port[i];
}
}
else
{
ar >> strName >> nType >> nMaxPortX >> nMaxPortY >> nWidth >> nHeight >> nXPos
>> nYPos >> strSN >> commType >> commIP1 >> commPort1 >> commIP2 >> commPort2
>> commCOM >> commBR;
for(int i=0;i<MAX_PORT_PER_LDU;i++)
{
//以下操作繁琐,所以在结构体中重载操作符 >> 实现结构体序列化功能
//WORD tmpNSignalInPos,tmpNSignalDir;
//ar >> Port[i].nNumber >> Port[i].nType >> Port[i].nWidth >> Port[i].nHeight >> Port[i].nX
// >> Port[i].nY >> Port[i].nBrightness >> Port[i].nMaxBrightness >> Port[i].nMinBrightness >> Port[i].nGamma
// >> tmpNSignalInPos >> tmpNSignalDir >> Port[i].nTempIndex;
//Port[i].nSignalInPos = (LDUPort::SignalPostion)tmpNSignalInPos;
//Port[i].nSignalDir = (LDUPort::SignalDirection)tmpNSignalDir;
//for(int j=0;j<MAX_TEMP_GROUP;j++)
//{
// ar >> Port[i].nTempR[j] >> Port[i].nTempG[j] >> Port[i].nTempB[j];
//}
//ar >> Port[i].nTotalTiles;
//int nTiles = Port[i].nTotalTiles;
//Tile* tilePtr = NULL;
//while(nTiles > 0)
//{
// Tile* tmpTile = new Tile;
// ar >> tmpTile->nTileType >> tmpTile->nWidth >> tmpTile->nHeight >> tmpTile->nX >> tmpTile->nY >> tmpTile->nLineStyle
// >> tmpTile->strSN >> tmpTile->PosX >> tmpTile->PosY;
// ar >> tmpTile->TileStat.cpuVer >> tmpTile->TileStat.fpgaVer >> tmpTile->TileStat.temp >> tmpTile->TileStat.current
// >> tmpTile->TileStat.volate >> tmpTile->TileStat.brightness;
// tmpTile->next = NULL;
// if(nTiles == Port[i].nTotalTiles)
// {
// Port[i].Tiles = tmpTile;
// }
// if(tilePtr != NULL)
// {
// tilePtr->next = tmpTile;
// }
// tilePtr = tmpTile;
// --nTiles;
//}
//ASSERT(nTiles == 0);
ar >> Port[i];
}
}
CDrawObj::Serialize(ar);
}
还有在编写过程中遇到两个问题:
第一个问题是结构体序列化时
首先看到我上一个代码块里注释了很长的一段,是由于刚开始结构体序列化时没有重载 操作符"<<" 和 操作符">>"(其实是我知道可以通过重载这两个符号实现结构体的序列化只是函数声明有问题,稍后会提及),这时只能悲剧地一个一个成员变量序列化。后来重写操作符正确后就比较方便了代码如下:
//================================================================================================================
//==== 端口
//================================================================================================================
struct LDUPort
{
INT32U nNumber; //Port编号
INT32U nType; //Port类型
INT32S nWidth; //输出宽
INT32S nHeight; //输出高
INT32S nX; //对应LDU原点的X,Y座标
INT32S nY;
//============================================================================================================
//==== 亮度,百分比
//============================================================================================================
INT8U nBrightness;
INT8U nMaxBrightness;
INT8U nMinBrightness;
//============================================================================================================
//==== Gamma索引
//============================================================================================================
INT8U nGamma;
enum SignalPostion
{
SP_LEFT_TOP, //面对应显示模块,左上角
SP_LEFT_BOTOOM, //面对应显示模块,左下角
SP_RIGHT_TOP, //面对应显示模块,右上角
SP_RIGHT_BOTOOM //面对应显示模块,右下角
}; //这个口总箱体个数
enum SignalDirection
{
SD_VERTICAL, //垂直方向
SD_HORIZITAL //水平方向
};
SignalPostion nSignalInPos; //信号输入位置
SignalDirection nSignalDir;
//============================================================================================================
//==== 色温,百分比
//============================================================================================================
INT8U nTempIndex; //当前色温值
INT8U nTempR[MAX_TEMP_GROUP];
INT8U nTempG[MAX_TEMP_GROUP];
INT8U nTempB[MAX_TEMP_GROUP];
INT32U nTotalTiles; //信号方向
Tile *Tiles; //端口所接的第一个箱体
LDUPort(){
nNumber = 0;
nType = 0;
nWidth =1024;
nHeight = 640;
nX = 0;
nY = 0;
nTempIndex = 0;
for(int i = 0; i < MAX_TEMP_GROUP; ++i)
{
nTempR[i] = 100;
nTempG[i] = 100;
nTempB[i] = 100;
}
nBrightness = 100;
nMaxBrightness = 100;
nMinBrightness = 10;
nGamma = 0;
nTotalTiles = 0;
nSignalInPos = SP_LEFT_BOTOOM; //信号输入位置
nSignalDir = SD_VERTICAL; //信号方向
Tiles = NULL;
}
//重载>>符号,实现结构体序列化
//AFX_API friend CArchive& AFXAPI operator>>(CArchive& ar, LDUPort* &pOb)
AFX_API friend CArchive& AFXAPI operator>>(CArchive& ar, LDUPort &pOb)
{
WORD tmpNSignalInPos,tmpNSignalDir;
ar >> pOb.nNumber >> pOb.nType >> pOb.nWidth >> pOb.nHeight >> pOb.nX
>> pOb.nY >> pOb.nBrightness >> pOb.nMaxBrightness >> pOb.nMinBrightness >> pOb.nGamma
>> tmpNSignalInPos >> tmpNSignalDir >> pOb.nTempIndex;
pOb.nSignalInPos = (SignalPostion)tmpNSignalInPos;
pOb.nSignalDir = (SignalDirection)tmpNSignalDir;
for(int j=0;j<MAX_TEMP_GROUP;j++)
{
ar >> pOb.nTempR[j] >> pOb.nTempG[j] >> pOb.nTempB[j];
}
ar >> pOb.nTotalTiles;
int nTiles = pOb.nTotalTiles;
Tile* tilePtr = NULL;
while(nTiles > 0)
{
Tile* tmpTile = new Tile;
ar >> *tmpTile;
tmpTile->next = NULL;
if(nTiles == pOb.nTotalTiles)
{
pOb.Tiles = tmpTile;
}
if(tilePtr != NULL)
{
tilePtr->next = tmpTile;
}
tilePtr = tmpTile;
--nTiles;
}
ASSERT(nTiles == 0);
return ar;
}
//重载<<符号,实现结构体序列化
//AFX_API friend CArchive& AFXAPI operator<<(CArchive& ar, LDUPort* &pOb)
AFX_API friend CArchive& AFXAPI operator<<(CArchive& ar, LDUPort &pOb)
{
ar << pOb.nNumber << pOb.nType << pOb.nWidth << pOb.nHeight << pOb.nX
<< pOb.nY << pOb.nBrightness << pOb.nMaxBrightness << pOb.nMinBrightness << pOb.nGamma
<< (WORD)pOb.nSignalInPos << (WORD)pOb.nSignalDir << pOb.nTempIndex;
for(int j=0;j<MAX_TEMP_GROUP;j++)
{
ar << pOb.nTempR[j] << pOb.nTempG[j] << pOb.nTempB[j];
}
ar << pOb.nTotalTiles;
Tile* tile = pOb.Tiles;
int nTiles = pOb.nTotalTiles;
while(tile != NULL)
{
ar << *tile;
--nTiles;
tile = tile->next;
}
ASSERT(nTiles == 0);
return ar;
}
};
(//AFX_API friend CArchive& AFXAPI operator>>(CArchive& ar, LDUPort* &pOb) 改成 AFX_API friend CArchive& AFXAPI operator>>(CArchive& ar,LDUPort &pOb))
是一开始通过查看DECLARE_SERIAL的定义直接拷贝过来的,如下
#define DECLARE_SERIAL(class_name) \
_DECLARE_DYNCREATE(class_name) \
AFX_API friend CArchive& AFXAPI operator>>(CArchive& ar, class_name* &pOb);
class_name* 看到是传递指针,所以理所当然的认为结构体也是传递指针(谁知道坑爹了,还害我调试了很久)。
第二个问题是枚举序列化时必须像如下写法:
ar << pOb.nNumber << pOb.nType << pOb.nWidth << pOb.nHeight << pOb.nX
<< pOb.nY << pOb.nBrightness << pOb.nMaxBrightness << pOb.nMinBrightness << pOb.nGamma
<< (WORD)pOb.nSignalInPos << (WORD)pOb.nSignalDir<< pOb.nTempIndex;
WORD tmpNSignalInPos,tmpNSignalDir;
ar >> pOb.nNumber >> pOb.nType >> pOb.nWidth >> pOb.nHeight >> pOb.nX
>> pOb.nY >> pOb.nBrightness >> pOb.nMaxBrightness >> pOb.nMinBrightness >> pOb.nGamma
>> tmpNSignalInPos >> tmpNSignalDir>> pOb.nTempIndex;
pOb.nSignalInPos = (SignalPostion)tmpNSignalInPos;
pOb.nSignalDir = (SignalDirection)tmpNSignalDir;