MFC 关键技术之永久保存

必须注意以下几点:

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_DYNCREATEDECLARE_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;


  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值