图形的保存和重绘

新建一个单文档程序
添加四个画图菜单项:点、线、矩形、椭圆

View中添加三个成员变量:
CPoint m_ptOrigin;    //保存鼠标按下时的点(画图起点)
UINT m_nDrawType;    //保存点击菜单项的画图类型
CPtrArray m_ptrArray;     //保存每次绘图的集合
构造函数中初始化,赋0

添加四个菜单项的响应函数,保存画图类型:
void CGraphicView::OnDot() 
{
// TODO: Add your command handler code here
m_nDrawType=1;
}

void CGraphicView::OnLine() 
{
// TODO: Add your command handler code here
m_nDrawType=2;
}

void CGraphicView::OnRectangle() 
{
// TODO: Add your command handler code here
m_nDrawType=3;
}

void CGraphicView::OnEllipse() 
{
// TODO: Add your command handler code here
m_nDrawType=4;
}

添加一个类,用来保存画图三要素:画图类型,起点,终点
class CGraph  
{
public:
CPoint m_ptOrigin;
CPoint m_ptEnd;
UINT m_nDrawType;
CGraph();
//重载构造函数,以方便构造对象
CGraph(UINT m_nDrawType,CPoint m_ptOrigin,CPoint m_ptEnd);
virtual ~CGraph();

};


添加鼠标左键按下和抬起消息函数:
void CGraphicView::OnLButtonDown(UINT nFlags, CPoint point) 
{
// TODO: Add your message handler code here and/or call default
m_ptOrigin=point;     //保存画图起点
CScrollView::OnLButtonDown(nFlags, point);
}

void CGraphicView::OnLButtonUp(UINT nFlags, CPoint point) 
{
// TODO: Add your message handler code here and/or call default

CClientDC dc(this);
CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
dc.SelectObject(pBrush);

switch(m_nDrawType)
{
case 1:
dc.SetPixel(point,RGB(0,0,0));
break;
case 2:
dc.MoveTo(m_ptOrigin);
break;
case 3:
dc.Rectangle(CRect(m_ptOrigin,point));
break;
case 4:
dc.Ellipse(CRect(m_ptOrigin,point));
break;
}
//在堆上创建一个图形对象
CGraph *pGraph=new CGraph(m_nDrawType,m_ptOrigin,point);
//把每个图形对象添加到集合中
m_ptrArray.Add(pGraph);

CScrollView::OnLButtonUp(nFlags, point);
}
现在已经实现画图功能了,
但是,窗口尺寸改变时图形就不见了
因为窗口尺寸改变引起OnDraw()擦除了背景
重写OnDraw()函数:

void CGraphicView::OnDraw(CDC* pDC)
{
CGraphicDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here

CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
pDC->SelectObject(pBrush);

for(int i=0;i<m_ptrArray.GetSize();i++)
{
switch(((CGraph*)m_ptrArray.GetAt(i))->m_nDrawType)
{
case 1:
pDC->SetPixel(((CGraph*)m_ptrArray.GetAt(i))->m_ptEnd,RGB(0,0,0));
break;
case 2:
pDC->MoveTo(((CGraph*)m_ptrArray.GetAt(i))->m_ptOrigin);
pDC->LineTo(((CGraph*)m_ptrArray.GetAt(i))->m_ptEnd);
break;
case 3:
pDC->Rectangle(CRect(((CGraph*)m_ptrArray.GetAt(i))->m_ptOrigin,
((CGraph*)m_ptrArray.GetAt(i))->m_ptEnd));
break;
case 4:
pDC->Ellipse(CRect(((CGraph*)m_ptrArray.GetAt(i))->m_ptOrigin,
((CGraph*)m_ptrArray.GetAt(i))->m_ptEnd));
break;
}
}

接下来添加窗口滚动条
首先将本工程的View类基类改为CScrollView
如:
class CGraphicView : public CScrollView
{
.....
};
并把所有的"View"退换成"CScrollView"

SetScrollSizes()设置窗口滚动条
图形的保存和重绘 - andylanzhiyong - C++学习
 
重载View的虚函数OnInitialUpdate
void CGraphicView::OnInitialUpdate() 
{
CScrollView::OnInitialUpdate();
// TODO: Add your specialized code here and/or call the base class
SetScrollSizes(MM_TEXT,CSize(800,600));
}
这样滚动条加上去了
当画图后,拖动滚动条,图像位置发生了改变
这是因为拖动滚动条时产生了重绘,视口原点发生了改变
图形的保存和重绘 - andylanzhiyong - C++学习
 
图形的保存和重绘 - andylanzhiyong - C++学习

重写
void CGraphicView::OnLButtonUp(UINT nFlags, CPoint point) 
{
// TODO: Add your message handler code here and/or call default

CClientDC dc(this);
CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
dc.SelectObject(pBrush);

switch(m_nDrawType)
{
case 1:
dc.SetPixel(point,RGB(0,0,0));
break;
case 2:
dc.MoveTo(m_ptOrigin);
break;
case 3:
dc.Rectangle(CRect(m_ptOrigin,point));
break;
case 4:
dc.Ellipse(CRect(m_ptOrigin,point));
break;
}
OnPrepareDC(&dc);     //调整显示上下文的属性
  dc.DPtoLP(&m_ptOrigin);    //设备坐标转逻辑坐标
  dc.DPtoLP(&point);     //逻辑坐标转设备坐标

//在堆上创建一个图形对象
CGraph *pGraph=new CGraph(m_nDrawType,m_ptOrigin,point);
//把每个图形对象添加到集合中
m_ptrArray.Add(pGraph);

CScrollView::OnLButtonUp(nFlags, point);
}
 

下面来实现保存上面所画图形的功能
有两种方式:元文件和兼容设备描述表

方式1:
先为View类添加成员变量:
CMetaFileDC m_dcMetaFile;
构造函数中初始化:
m_dcMetaFile.Create();

再更改画图代码:
void CGraphicView::OnLButtonUp(UINT nFlags, CPoint point) 
{
// TODO: Add your message handler code here and/or call default

CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
m_dcMetaFile.SelectObject(pBrush);

switch(m_nDrawType)
{
case 1:
m_dcMetaFile.SetPixel(point,RGB(0,0,0));
break;
case 2:
m_dcMetaFile.MoveTo(m_ptOrigin);
m_dcMetaFile.LineTo(point);
break;
case 3:
m_dcMetaFile.Rectangle(CRect(m_ptOrigin,point));
break;
case 4:
m_dcMetaFile.Ellipse(CRect(m_ptOrigin,point));
break;
}
//CGraph graph(m_nDrawType,m_ptOrigin,point);
//m_ptrArray.Add(&graph);
/* OnPrepareDC(&dc);
dc.DPtoLP(&m_ptOrigin);
dc.DPtoLP(&point);
CGraph *pGraph=new CGraph(m_nDrawType,m_ptOrigin,point);
m_ptrArray.Add(pGraph);*/
CScrollView::OnLButtonUp(nFlags, point);
}
图形的保存和重绘 - andylanzhiyong - C++学习

  以上只是把图画进了元文件,用户看不见
要想看见,重写OnDraw(),并让窗口重画,如拉大窗口尺寸
重写OnDraw()
void CGraphicView::OnDraw(CDC* pDC)
{
CGraphicDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here

CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
pDC->SelectObject(pBrush);

HMETAFILE hmetaFile;
//关闭元文件,获得元文件句柄
hmetaFile=m_dcMetaFile.Close();
//播放当前的元文件
pDC->PlayMetaFile(hmetaFile);  
//创建一个元文件,以便用户再次绘图
m_dcMetaFile.Create();
//播放先前的元文件
m_dcMetaFile.PlayMetaFile(hmetaFile);
//释放元文件资源
DeleteMetaFile(hmetaFile);
}

接着实现两个功能
单击菜单项“保存”按钮,所画图形以图片形式保存到电脑文件夹中
单击菜单项“打开”按钮,读取所画图片到View中
添加“打开”“保存”命令函数:
//保存
void CGraphicView::OnFileSave() 
{
// TODO: Add your command handler code here
HMETAFILE hmetaFile;
hmetaFile=m_dcMetaFile.Close();
CopyMetaFile(hmetaFile,"meta.wmf");
m_dcMetaFile.Create();
DeleteMetaFile(hmetaFile);
}

//打开
void CGraphicView::OnFileOpen() 
{
// TODO: Add your command handler code here
HMETAFILE hmetaFile;
hmetaFile=GetMetaFile("meta.wmf");
m_dcMetaFile.PlayMetaFile(hmetaFile);
DeleteMetaFile(hmetaFile);
Invalidate();
}

保存文件方式2:兼容设备描述表
先为View添加一个成员变量
CDC m_dcCompatible;

重写函数
void CGraphicView::OnLButtonUp(UINT nFlags, CPoint point) 
{
// TODO: Add your message handler code here and/or call default
CClientDC dc(this);
CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
//判断是否已创建兼容DC(不能重复创建)
if(!m_dcCompatible.m_hDC)
{
m_dcCompatible.CreateCompatibleDC(&dc);
//利用客户区大小设置兼容位图大小
CRect rect;
GetClientRect(&rect);
CBitmap bitmap;
bitmap.CreateCompatibleBitmap(&dc,rect.Width(),rect.Height());
//将位图选人DC
m_dcCompatible.SelectObject(&bitmap);
//将位图数据贴到DC中
m_dcCompatible.BitBlt(0,0,rect.Width(),rect.Height(),&dc,0,0,SRCCOPY);
m_dcCompatible.SelectObject(pBrush);
}
switch(m_nDrawType)
{
case 1:
m_dcCompatible.SetPixel(point,RGB(0,0,0));
break;
case 2:
m_dcCompatible.MoveTo(m_ptOrigin);
m_dcCompatible.LineTo(point);
break;
case 3:
m_dcCompatible.Rectangle(CRect(m_ptOrigin,point));
break;
case 4:
m_dcCompatible.Ellipse(CRect(m_ptOrigin,point));
break;
}
CScrollView::OnLButtonUp(nFlags, point);
}

图形的保存和重绘 - andylanzhiyong - C++学习
 
void CGraphicView::OnDraw(CDC* pDC)
{
CGraphicDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
CRect rect;
GetClientRect(&rect);
pDC->BitBlt(0,0,rect.Width(),rect.Height(),&m_dcCompatible,0,0,SRCCOPY);
}





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值