双缓冲在之前写字符雨的时候,已经简单介绍过,今天我们来写一个简单的程序来体会双缓冲机制
我们实现一个在屏幕上画直线的功能:
在类中添加变量,保存起点坐标和终点坐标:
//定义一个容器,保存每次画的直线
using Lint = std::pair(CPoint,CPoint);
CList<>m_List;CPoint m_begin;
CPoint m_end;
在对话框上添加WM_MOUSEMOVE,WM_LBUTTONDOWM,WM_LBUTTONUP消息处理函数:
void C双缓冲View::OnDraw(UINT nFlags,CPoint point){
C双缓冲View* pDoc = GetDocument();
ASSERT_CALID(pDoc);
if(!pFoc)
return;
//画直线
pDC->MoveTo(m_begin);
pDC->LineTo(m_end);
CVIew::OnMouseMove(nFlags,point);
}
void C双缓冲::OnMouseMove(UINT nFlags,CPoint point){
if(nFlags&MK_LBUTTON){
m_end = point;
IncalidateRect(NULL,TRUE);
}
CView::OnMouseMoce(nFlags,point);
}
void C双缓冲View::OnLButtonDown(UINT nFlags,CPoint point){
//记录开始坐标
CVIew::OnLButtonDown(nFlags,point);
m_begin = point;
}
void C双缓冲View::OnLButtonUp(UINT nFlags,CPoint point){
//记录终点坐标
m_end = point;
CVIew::OnLButtonUp(nFlags,point);
ReleaseCapture();
}
这样写完之后,没有反应,这是因为没有无效区域,我们将OnLButtonUp函数中添加无效区域就可以了:
void C双缓冲View::OnLButtonUp(UINT nFlags,CPoint point){
//记录终点坐标
m_end = point;
CVIew::OnLButtonUp(nFlags,point);
InvalidateRect(NULL,TRUE);
}
只有有了无效区域,绘图消息才会产生
然后我们完善:
//定义一个容器,保存每次画的直线
using Lint = std::pair(CPoint,CPoint);
CList<>m_List;
void C双缓冲View::OnDraw(UINT nFlags,CPoint point){
C双缓冲View* pDoc = GetDocument();
ASSERT_CALID(pDoc);
if(!pFoc)
return;
pDC->MoveTo(m_begin);
pDC->LineTo(m_end);
auto pos = m_list.GetHeadPossition();
while(pos){
auto Lint = m_list.GetNext(pos);
//画直线
pDC->MoveTo(Line.first);
pDC->LineTo(line.second);
}
CVIew::OnMouseMove(nFlags,point);
}
void C双缓冲::OnMouseMove(UINT nFlags,CPoint point){
if(nFlags&MK_LBUTTON){
m_end = point;
IncalidateRect(NULL,TRUE);
}
CView::OnMouseMoce(nFlags,point);
}
void C双缓冲View::OnLButtonDown(UINT nFlags,CPoint point){
//记录开始坐标
CVIew::OnLButtonDown(nFlags,point);
m_begin = point;
//捕捉客户区外鼠标消息
SetCapture();
}
void C双缓冲View::OnLButtonUp(UINT nFlags,CPoint point){
//记录终点坐标
m_end = point;
m_list.AddTail(Line(m_begin,m_end));
CVIew::OnLButtonUp(nFlags,point);
InvalidateRect(NULL,TRUE);
ReleaseCapture();
}
这样写完了之后,确实可以画出来直线,但是这是我们直接操作外设的,所以会出现闪屏的情况
这时候就需要我们的双缓冲了
双缓冲就是我们操作内存,将直线画在内存上,然后将内存完整拷贝到外设上,这样就可以避免操作慢,闪屏的问题:
Win32中,能操作设备的,只有设备句柄hdc
而在MFC中封装了:
CDC------->对应Win32::GetDC
CMetaFileDC 矢量图,位图(了解一下就行了)
CPainDC:WM_PAINT::BEGINPAINT
CWindowDC:桌面窗口的HDC
这几种对象,能代表他们各自的东西,肯定是内部有绑定机制Attah()
双缓冲:内存DC,这里的CDC就代表了内存DC
然后我们修改代码:
void C双缓冲View::OnDraw(UINT nFlags,CPoint point){
C双缓冲View* pDoc = GetDocument();
ASSERT_CALID(pDoc);
if(!pFoc)
return;
//双缓冲绘图
//1.创建内存DC
CDC dcMem;
dcMem.CreateCompatibleDC(pDC);
CRect rect;
GetClintRect(rect);
//2.创建一张屏幕DC一样的位图
CBitmap bitmap;
bitmap.CreateCompatibleBitmap(pDC,rect.Width(),rect.Height());
//3.送到内存DC中
dcMem.SeleObject(bitmap);
dcMem.FillSolidRect(rect,RGB(255,255,255));
//然后我们使用内存DC绘图
dcMem->MoveTo(m_begin);
dcMem->LineTo(m_end);
auto pos = m_list.GetHeadPossition();
while(pos){
auto Lint = m_list.GetNext(pos);
//画直线
dcMem->MoveTo(Line.first);
dcMem->LineTo(line.second);
}
//4.拷贝到设备
pDC.BitBit(0,0,rect.Width(),rect.Height(),&dcMem,0,DRCCOPY);
CVIew::OnMouseMove(nFlags,point);
}
修改完这个函数后,将绘制无效区域的函数,不再擦除背景
画壁画刷位图
在Win32中都是GDI句柄
MFC封装了GDI对象
Win32什么流程
MFC就还是什么流程
void C双缓冲View::OnDraw(UINT nFlags,CPoint point){
C双缓冲View* pDoc = GetDocument();
ASSERT_CALID(pDoc);
if(!pFoc)
return;
//双缓冲绘图
//1.创建内存DC
CDC dcMem;
dcMem.CreateCompatibleDC(pDC);
CRect rect;
GetClintRect(rect);
//2.创建一张屏幕DC一样的位图
CBitmap bitmap;
bitmap.CreateCompatibleBitmap(pDC,rect.Width(),rect.Height());
CPen pen;
pen.CreatePen(PS_DOT,55,RGB(0,255,255));
//把画笔送到内存DC
deMem.SelectObject(pen);
//3.送到内存DC中
dcMem.SeleObject(bitmap);
dcMem.FillSolidRect(rect,RGB(255,255,255));
//然后我们使用内存DC绘图
dcMem->MoveTo(m_begin);
dcMem->LineTo(m_end);
auto pos = m_list.GetHeadPossition();
while(pos){
auto Lint = m_list.GetNext(pos);
//画直线
dcMem->MoveTo(Line.first);
dcMem->LineTo(line.second);
}
//4.拷贝到设备
pDC.BitBit(0,0,rect.Width(),rect.Height(),&dcMem,0,DRCCOPY);
CVIew::OnMouseMove(nFlags,point);
}
为什么要有序列化:
我们在绘图应用程序上绘制的图形,可以保存起来,我们之后还可以打开
而我们上面写的程序,是不能保存的,这就是序列化的基本功能
简单使用以下序列化:
//直线类
class Cline:public Cobject{
public:
CLine(){};
CLine(int x,int y,CString type):x(x),y(y),str(type){};
virtual coid Setialize(CArchice* ar){
if(ar,IsLoading()){
//加载
ar>>x>>y>>str;
}else{
//保存
ar<<x<<y<<str;
}
}
int x;
int y;
int color;
CString str;
DECLARE_SERTAL(CLine)
}
IMPLEMENT_SERIAL(CLine,Cobject,1)
int main(){
int nRetCode = 0;
HMODULE hModule = ::GEtModuleHandle(nullptr);
AfxWinInit(hModule,nullptr,::GetCommandLine(),0);
CLine line(40,40,"直线");
CFile file;
file.Open(R"(文件路径\文件名)",CFile::modeCreate|CFile::modeWrite);
CArchive ar(&file,CArchice::store,4096);
ar<<&line;
ar.Close();
file.Close();
return nRetCode;
}
我们这样实现后,发现,我们只写了三个成员,但是文件中有很多,我们来简单追踪有一下序列化是如何实现的:
序列化过程
CArchive 归档类对象
CArchive& AFXAPI operator>>(CArchive& ar, CLine* &pOb)
{
pOb = (CLine*) ar.ReadObject(RUNTIME_CLASS(CLine));
return ar;
}
CArchive ar(&file, CArchive::store,4096)
{
m_nMode = nMode;//模式
m_pFile = pFile;//文件句柄
m_nBufSize = nBufSize //缓冲区大小
this->m_lpBufStart = new BYTE[m_nBufSize]; //申请了缓冲区大小
m_lpBufMax = m_lpBufStart + nBufSize;//缓冲区的尾地址
m_lpBufCur = (IsLoading()) ? m_lpBufMax : m_lpBufStart;
}
struct
{
类版本
类大小
x
}
void CArchive::WriteObject(const CObject* line)
{
//获取类信息地址
CRuntimeClass* pClassRef = pOb->GetRuntimeClass();
//写类信息
WriteClass(pClassRef);
((CObject*)pOb)->Serialize(ar对象/*归档类对象*/);
{
ar << x
{
return CArchive::operator<<((char)x);
{
if (m_lpBufCur + sizeof(LONG) > m_lpBufMax)
Flush();
*(UNALIGNED LONG*)m_lpBufCur = x;
m_lpBufCur += sizeof(LONG);
return *this;
}
}
AfxWriteStringLength(*this, 长度, 判断字符串是否是多字节
{
ar<<(BYTE)nLength;
}
:memcpy_s(m_lpBufCur, (size_t)(m_lpBufMax - m_lpBufCur), lpBuf, nTemp)
}
}
ar,close
{
Flush();
{
m_pFile->Write(m_lpBufStart, ULONG(m_lpBufCur - m_lpBufStart)
{
//写文件
::WriteFile(m_hFile, lpBuf, nCount, &nWritten, NULL)
m_lpBufCur = m_lpBufStart;
}
}
}
反序列化:
int main(){
int nRetCode = 0;
HMODULE hModule = ::GEtModuleHandle(nullptr);
AfxWinInit(hModule,nullptr,::GetCommandLine(),0);
CLine* line;
CFile file;
file.Open(R"(文件路径\文件名)",CFile::modeCreate|CFile::modeRead);
CArchive ar(&file,CArchice::store,4096);
ar >> line;
ar.Close();
file.Close();
std::cout<<line->str;
std::coutd<<line-x;
std::cout<<line->y;
return nRetCode;
}
CArchive ar(&file, CArchive::store,4096)
{
m_nMode = nMode;//模式 读
m_pFile = pFile;//文件句柄
m_nBufSize = nBufSize //缓冲区大小
this->m_lpBufStart = new BYTE[m_nBufSize]; //申请了缓冲区大小
m_lpBufMax = m_lpBufStart + nBufSize;//缓冲区的尾地址
m_lpBufCur = (IsLoading()) ? m_lpBufMax : m_lpBufStart;
}
ar.ReadObject(直线类信息)
{
//读类信息
CRuntimeClass* pClassRef = ReadClass(pClassRefRequested, &nSchema, &obTag);
{
BYTE* lpTemp = m_lpBufStart + nPreviouslyFilled;
do
{
//读文件 全部读上来
nBytesRead = m_pFile->Read(lpTemp, nLeftToRead);
lpTemp = lpTemp + nBytesRead;
nTotalInBuffer += nBytesRead;
nLeftToRead -= nBytesRead;
}
while (nBytesRead > 0 && nLeftToRead > 0 && nTotalInBuffer < nTotalSizeWanted);
m_lpBufCur = m_lpBufStart;
m_lpBufMax = m_lpBufStart + nTotalInBuffer;
}
//动态创建对象
pOb = pClassRef->CreateObject();
//回到我们代码
pOb->Serialize(*this)
{
CArchive::operator>>((LONG&)x);
{
if (m_lpBufCur + sizeof(LONG) > m_lpBufMax)
FillBuffer(UINT(sizeof(LONG) - (m_lpBufMax - m_lpBufCur)));
i = *(UNALIGNED LONG*)m_lpBufCur;
m_lpBufCur += sizeof(LONG);
return *this;
}
}
}
了解了序列化和反序列化过程,我们就可以将我们画的图保存起来了:
#pragma once
#include
class Cline:public CObject{
public:
DECLARE_SERTAL(CLine)
virtual void Serialize(CArchive& ar);
CPoint m_begin;
CPoint m_end;
};
//在cpp中实现:
#include "pch.h"
#include "CLine.h"
IMPLEMENT_SERIAL(CLine,CObject,1)
void Serialize(CArchive& ar){
CObject::Serialize(ae);
if(ar.IsLoading()){
ar>>m_begin.x>>m_begin.y;
ar>>m_end.x>>m_end.y;
}else{
ar<<m_begin.x<<m_begin.y;
ar<<m_end.x<<m_end.y;
}
}
我们还需要将直线的链表存储到文档中:
在文档类.cpp中:
#include "CLine.h"
为文档类添加变量:
CList<CLine>m_list;
auto pos = pDoc->m_list.GetHeadPossition();
while(pos){
auto Lint = pDoc->m_list.GetNext(pos);
//画直线
dcMem->MoveTo(Line.m_begin);
dcMem->LineTo(line.m_end);
}
#pragma once
#include
class Cline:public CObject{
public:
CLine(){};
CLine& operator_(const& line){
this->m_begin = line.m_begin;
this->m_end = list.m_red;
return *this;
}
CLine(const CLine& line){
this->m_begin = line.m_begin;
this->m_end = list.m_red;
}
CLine(CPoint begin,CPoint end){
this->m_begin = begin;
this->m_end = end;
}
DECLARE_SERTAL(CLine)
virtual void Serialize(CArchive& ar);
CPoint m_begin;
CPoint m_end;
};
void C...DOC::Serialize(CArchive& ar){
if(ar.IsStoring()){
ar<<m_list.getSize();
auto pos = m_list.GetHeadPosition();
while(pos){
//ar<<&m_list.GetNext(pos);
CLine*p = m_listl.GetNext(pos);
ar<<&p;
//这里第二种方式,看似跟上面的方式没有什么区别,但是运行发现,只保存了一条直线
//这是因为每一次p都是一个地址
}else{
int nSize;
ar>>nSize;
CObject* shape;
while(nSize--){
ar>>shape;
m_list.AddTail(*(CLine*)shape);
}
}
}
}
双缓冲在之前写字符雨的时候,已经简单介绍过,今天我们来写一个简单的程序来体会双缓冲机制
我们实现一个在屏幕上画直线的功能:
在类中添加变量,保存起点坐标和终点坐标:
//定义一个容器,保存每次画的直线
using Lint = std::pair(CPoint,CPoint);
CList<>m_List;CPoint m_begin;
CPoint m_end;
在对话框上添加WM_MOUSEMOVE,WM_LBUTTONDOWM,WM_LBUTTONUP消息处理函数:
void C双缓冲View::OnDraw(UINT nFlags,CPoint point){
C双缓冲View* pDoc = GetDocument();
ASSERT_CALID(pDoc);
if(!pFoc)
return;
//画直线
pDC->MoveTo(m_begin);
pDC->LineTo(m_end);
CVIew::OnMouseMove(nFlags,point);
}
void C双缓冲::OnMouseMove(UINT nFlags,CPoint point){
if(nFlags&MK_LBUTTON){
m_end = point;
IncalidateRect(NULL,TRUE);
}
CView::OnMouseMoce(nFlags,point);
}
void C双缓冲View::OnLButtonDown(UINT nFlags,CPoint point){
//记录开始坐标
CVIew::OnLButtonDown(nFlags,point);
m_begin = point;
}
void C双缓冲View::OnLButtonUp(UINT nFlags,CPoint point){
//记录终点坐标
m_end = point;
CVIew::OnLButtonUp(nFlags,point);
ReleaseCapture();
}
这样写完之后,没有反应,这是因为没有无效区域,我们将OnLButtonUp函数中添加无效区域就可以了:
void C双缓冲View::OnLButtonUp(UINT nFlags,CPoint point){
//记录终点坐标
m_end = point;
CVIew::OnLButtonUp(nFlags,point);
InvalidateRect(NULL,TRUE);
}
只有有了无效区域,绘图消息才会产生
然后我们完善:
//定义一个容器,保存每次画的直线
using Lint = std::pair(CPoint,CPoint);
CList<>m_List;
void C双缓冲View::OnDraw(UINT nFlags,CPoint point){
C双缓冲View* pDoc = GetDocument();
ASSERT_CALID(pDoc);
if(!pFoc)
return;
pDC->MoveTo(m_begin);
pDC->LineTo(m_end);
auto pos = m_list.GetHeadPossition();
while(pos){
auto Lint = m_list.GetNext(pos);
//画直线
pDC->MoveTo(Line.first);
pDC->LineTo(line.second);
}
CVIew::OnMouseMove(nFlags,point);
}
void C双缓冲::OnMouseMove(UINT nFlags,CPoint point){
if(nFlags&MK_LBUTTON){
m_end = point;
IncalidateRect(NULL,TRUE);
}
CView::OnMouseMoce(nFlags,point);
}
void C双缓冲View::OnLButtonDown(UINT nFlags,CPoint point){
//记录开始坐标
CVIew::OnLButtonDown(nFlags,point);
m_begin = point;
//捕捉客户区外鼠标消息
SetCapture();
}
void C双缓冲View::OnLButtonUp(UINT nFlags,CPoint point){
//记录终点坐标
m_end = point;
m_list.AddTail(Line(m_begin,m_end));
CVIew::OnLButtonUp(nFlags,point);
InvalidateRect(NULL,TRUE);
ReleaseCapture();
}
这样写完了之后,确实可以画出来直线,但是这是我们直接操作外设的,所以会出现闪屏的情况
这时候就需要我们的双缓冲了
双缓冲就是我们操作内存,将直线画在内存上,然后将内存完整拷贝到外设上,这样就可以避免操作慢,闪屏的问题:
Win32中,能操作设备的,只有设备句柄hdc
而在MFC中封装了:
CDC------->对应Win32::GetDC
CMetaFileDC 矢量图,位图(了解一下就行了)
CPainDC:WM_PAINT::BEGINPAINT
CWindowDC:桌面窗口的HDC
这几种对象,能代表他们各自的东西,肯定是内部有绑定机制Attah()
双缓冲:内存DC,这里的CDC就代表了内存DC
然后我们修改代码:
void C双缓冲View::OnDraw(UINT nFlags,CPoint point){
C双缓冲View* pDoc = GetDocument();
ASSERT_CALID(pDoc);
if(!pFoc)
return;
//双缓冲绘图
//1.创建内存DC
CDC dcMem;
dcMem.CreateCompatibleDC(pDC);
CRect rect;
GetClintRect(rect);
//2.创建一张屏幕DC一样的位图
CBitmap bitmap;
bitmap.CreateCompatibleBitmap(pDC,rect.Width(),rect.Height());
//3.送到内存DC中
dcMem.SeleObject(bitmap);
dcMem.FillSolidRect(rect,RGB(255,255,255));
//然后我们使用内存DC绘图
dcMem->MoveTo(m_begin);
dcMem->LineTo(m_end);
auto pos = m_list.GetHeadPossition();
while(pos){
auto Lint = m_list.GetNext(pos);
//画直线
dcMem->MoveTo(Line.first);
dcMem->LineTo(line.second);
}
//4.拷贝到设备
pDC.BitBit(0,0,rect.Width(),rect.Height(),&dcMem,0,DRCCOPY);
CVIew::OnMouseMove(nFlags,point);
}
修改完这个函数后,将绘制无效区域的函数,不再擦除背景
画壁画刷位图
在Win32中都是GDI句柄
MFC封装了GDI对象
Win32什么流程
MFC就还是什么流程
void C双缓冲View::OnDraw(UINT nFlags,CPoint point){
C双缓冲View* pDoc = GetDocument();
ASSERT_CALID(pDoc);
if(!pFoc)
return;
//双缓冲绘图
//1.创建内存DC
CDC dcMem;
dcMem.CreateCompatibleDC(pDC);
CRect rect;
GetClintRect(rect);
//2.创建一张屏幕DC一样的位图
CBitmap bitmap;
bitmap.CreateCompatibleBitmap(pDC,rect.Width(),rect.Height());
CPen pen;
pen.CreatePen(PS_DOT,55,RGB(0,255,255));
//把画笔送到内存DC
deMem.SelectObject(pen);
//3.送到内存DC中
dcMem.SeleObject(bitmap);
dcMem.FillSolidRect(rect,RGB(255,255,255));
//然后我们使用内存DC绘图
dcMem->MoveTo(m_begin);
dcMem->LineTo(m_end);
auto pos = m_list.GetHeadPossition();
while(pos){
auto Lint = m_list.GetNext(pos);
//画直线
dcMem->MoveTo(Line.first);
dcMem->LineTo(line.second);
}
//4.拷贝到设备
pDC.BitBit(0,0,rect.Width(),rect.Height(),&dcMem,0,DRCCOPY);
CVIew::OnMouseMove(nFlags,point);
}
为什么要有序列化:
我们在绘图应用程序上绘制的图形,可以保存起来,我们之后还可以打开
而我们上面写的程序,是不能保存的,这就是序列化的基本功能
简单使用以下序列化:
我们这样实现后,发现,我们只写了三个成员,但是文件中有很多,我们来简单追踪有一下序列化是如何实现的:
序列化过程
CArchive 归档类对象
CArchive& AFXAPI operator>>(CArchive& ar, CLine* &pOb)
{
pOb = (CLine*) ar.ReadObject(RUNTIME_CLASS(CLine));
return ar;
}
CArchive ar(&file, CArchive::store,4096)
{
m_nMode = nMode;//模式
m_pFile = pFile;//文件句柄
m_nBufSize = nBufSize //缓冲区大小
this->m_lpBufStart = new BYTE[m_nBufSize]; //申请了缓冲区大小
m_lpBufMax = m_lpBufStart + nBufSize;//缓冲区的尾地址
m_lpBufCur = (IsLoading()) ? m_lpBufMax : m_lpBufStart;
}
struct
{
类版本
类大小
x
}
void CArchive::WriteObject(const CObject* line)
{
//获取类信息地址
CRuntimeClass* pClassRef = pOb->GetRuntimeClass();
//写类信息
WriteClass(pClassRef);
((CObject*)pOb)->Serialize(ar对象/*归档类对象*/);
{
ar << x
{
return CArchive::operator<<((char)x);
{
if (m_lpBufCur + sizeof(LONG) > m_lpBufMax)
Flush();
*(UNALIGNED LONG*)m_lpBufCur = x;
m_lpBufCur += sizeof(LONG);
return *this;
}
}
AfxWriteStringLength(*this, 长度, 判断字符串是否是多字节
{
ar<<(BYTE)nLength;
}
:memcpy_s(m_lpBufCur, (size_t)(m_lpBufMax - m_lpBufCur), lpBuf, nTemp)
}
}
ar,close
{
Flush();
{
m_pFile->Write(m_lpBufStart, ULONG(m_lpBufCur - m_lpBufStart)
{
//写文件
::WriteFile(m_hFile, lpBuf, nCount, &nWritten, NULL)
m_lpBufCur = m_lpBufStart;
}
}
}
反序列化:
int main(){
int nRetCode = 0;
HMODULE hModule = ::GEtModuleHandle(nullptr);
AfxWinInit(hModule,nullptr,::GetCommandLine(),0);
CLine* line;
CFile file;
file.Open(R"(文件路径\文件名)",CFile::modeCreate|CFile::modeRead);
CArchive ar(&file,CArchice::store,4096);
ar >> line;
ar.Close();
file.Close();
std::cout<<line->str;
std::coutd<<line-x;
std::cout<<line->y;
return nRetCode;
}
CArchive ar(&file, CArchive::store,4096)
{
m_nMode = nMode;//模式 读
m_pFile = pFile;//文件句柄
m_nBufSize = nBufSize //缓冲区大小
this->m_lpBufStart = new BYTE[m_nBufSize]; //申请了缓冲区大小
m_lpBufMax = m_lpBufStart + nBufSize;//缓冲区的尾地址
m_lpBufCur = (IsLoading()) ? m_lpBufMax : m_lpBufStart;
}
ar.ReadObject(直线类信息)
{
//读类信息
CRuntimeClass* pClassRef = ReadClass(pClassRefRequested, &nSchema, &obTag);
{
BYTE* lpTemp = m_lpBufStart + nPreviouslyFilled;
do
{
//读文件 全部读上来
nBytesRead = m_pFile->Read(lpTemp, nLeftToRead);
lpTemp = lpTemp + nBytesRead;
nTotalInBuffer += nBytesRead;
nLeftToRead -= nBytesRead;
}
while (nBytesRead > 0 && nLeftToRead > 0 && nTotalInBuffer < nTotalSizeWanted);
m_lpBufCur = m_lpBufStart;
m_lpBufMax = m_lpBufStart + nTotalInBuffer;
}
//动态创建对象
pOb = pClassRef->CreateObject();
//回到我们代码
pOb->Serialize(*this)
{
CArchive::operator>>((LONG&)x);
{
if (m_lpBufCur + sizeof(LONG) > m_lpBufMax)
FillBuffer(UINT(sizeof(LONG) - (m_lpBufMax - m_lpBufCur)));
i = *(UNALIGNED LONG*)m_lpBufCur;
m_lpBufCur += sizeof(LONG);
return *this;
}
}
}
了解了序列化和反序列化过程,我们就可以将我们画的图保存起来了:
#pragma once
#include
class Cline:public CObject{
public:
DECLARE_SERTAL(CLine)
virtual void Serialize(CArchive& ar);
CPoint m_begin;
CPoint m_end;
};
//在cpp中实现:
#include "pch.h"
#include "CLine.h"
IMPLEMENT_SERIAL(CLine,CObject,1)
void Serialize(CArchive& ar){
CObject::Serialize(ae);
if(ar.IsLoading()){
ar>>m_begin.x>>m_begin.y;
ar>>m_end.x>>m_end.y;
}else{
ar<<m_begin.x<<m_begin.y;
ar<<m_end.x<<m_end.y;
}
}
我们还需要将直线的链表存储到文档中:
在文档类.cpp中:
#include "CLine.h"
为文档类添加变量:
CList<CLine>m_list;
auto pos = pDoc->m_list.GetHeadPossition();
while(pos){
auto Lint = pDoc->m_list.GetNext(pos);
//画直线
dcMem->MoveTo(Line.m_begin);
dcMem->LineTo(line.m_end);
}
#pragma once
#include
class Cline:public CObject{
public:
CLine(){};
CLine& operator_(const& line){
this->m_begin = line.m_begin;
this->m_end = list.m_red;
return *this;
}
CLine(const CLine& line){
this->m_begin = line.m_begin;
this->m_end = list.m_red;
}
CLine(CPoint begin,CPoint end){
this->m_begin = begin;
this->m_end = end;
}
DECLARE_SERTAL(CLine)
virtual void Serialize(CArchive& ar);
CPoint m_begin;
CPoint m_end;
};
void C...DOC::Serialize(CArchive& ar){
if(ar.IsStoring()){
ar<<m_list.getSize();
auto pos = m_list.GetHeadPosition();
while(pos){
//ar<<&m_list.GetNext(pos);
CLine*p = m_listl.GetNext(pos);
ar<<&p;
//这里第二种方式,看似跟上面的方式没有什么区别,但是运行发现,只保存了一条直线
//这是因为每一次p都是一个地址
}else{
int nSize;
ar>>nSize;
CObject* shape;
while(nSize--){
ar>>shape;
m_list.AddTail(*(CLine*)shape);
}
}
}
}