图形的保存和重绘

一、图形的保存与重绘

1,添加一个通常的类(General Class)CGraphic,用于保存图形要素
2,添加成员变量
 UINT m_nDrawType;
 CPoint m_ptOrigin;
 CPoint m_ptEnd;
3,添加构造函数
 CGraphic::CGraphic(UNT m_nDrawType,CPoint m_ptOrigin,CPoint m_ptEnd)
 {
  this->m_nDrawType=m_nDrawType;
  this->m_ptOrigin=m_ptOrigin;
  this->m_ptEnd=m_ptEnd;
 }
4,在View类中定义一个集合类对象CPtrArray m_ptrArray;
5,图形绘制完成后保存其要素;
 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);
  dc.LineTo(point);
  break;
 case 3:
  dc.Rectangle(CRect(m_ptOrigin,point));
  break;
 case 4:
  dc.Ellipse(CRect(m_ptOrigin,point));
  break;
 default:
  break;
 } 
 //CMyGraph graph(m_nDrawType,m_ptOrigin,point); //OnLButtonUp退出时,graph对象析构
 //m_ptrArray.Add(&graph);//保存了graph对象的地址,但graph将在函数退出时已经析构
 CMyGraph *pGraph;
 pGraph=new CMyGraph(m_nDrawType,m_ptOrigin,point);
  //用new分配的内存都是在堆上,只有显式调用delete时才会释放,因此对象生命周期延长
 m_ptrArray.Add(pGraph);
6,图形重绘(OnDraw中实现)
void CGraphsaveView::OnDraw(CDC* pDC)
{
    CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
 pDC->SelectObject(pBrush);

 for (int i=0;i<m_ptrArray.GetSize();i++)
 {
  switch(((CMyGraph *)m_ptrArray.GetAt(i))->m_nDrawType)
  {
  case 1:
   pDC->SetPixel(((CMyGraph *)m_ptrArray.GetAt(i))->m_ptEnd,RGB(0,0,0));
   break;
  case 2:
   pDC->MoveTo(((CMyGraph *)m_ptrArray.GetAt(i))->m_ptOrigin);
   pDC->LineTo(((CMyGraph *)m_ptrArray.GetAt(i))->m_ptEnd);
   break;
  case 3:
   pDC->Rectangle(CRect(((CMyGraph *)m_ptrArray.GetAt(i))->m_ptOrigin,    ((CMyGraph *)m_ptrArray.GetAt(i))->m_ptEnd));
   break;
  case 4:
   pDC->Ellipse(CRect(((CMyGraph *)m_ptrArray.GetAt(i))->m_ptOrigin,    ((CMyGraph *)m_ptrArray.GetAt(i))->m_ptEnd));
   break;
  default:
   break;
  }
 }
}
二、OnPaint 与OnDraw
 OnPaint是WM_PAINT的消息处理函数
 OnDraw是虚函数,CView的OnDraw函数是在OnPaint中调用的
 void CView::OnPaint()
 {
  CPaintDC dc(this);
  OnPrepareDC(&dc);
  OnDraw(&dc);
 }
 若对子类的WM_PAINT消息进行捕获,且不调用OnDraw函数就无法执行OnDraw函数

三、坐标空间(查看MSDN:coordinate spaces [Win32])
世界坐标系空间:旋转,斜切,反射
页面空间:
设备空间:
物理设备空间:
SetWorldTransform

页面空间(逻辑空间)到设备空间的转换
逻辑空间中的矩形被称为窗口,设备坐标中的矩形被称为视口
Windows把窗口原点映射到视口原点,把窗口范围映射到视口范围,就完成了这种转换(参看powerpoint)

窗口(逻辑)坐标转换为视口(设备)坐标的两个公式:
xViewport = xWindow-xWinOrg+xViewOrg
yViewport = yWindow-yWinOrg+yViewOrg
视口(设备)坐标转换为窗口(逻辑)坐标的两个公式:
xWindow = xViewport-xViewOrg+xWinOrg
yWindow = yViewport-yViewOrg+yWinOrg

改变窗口/视口原点:SetWindowOrg,SetViewPortOrg


四.CScrollView(滚动窗口的创建)
1.将View类的基类选为CScrollView
2.在虚函数OnInitialUpdate中设置大小(OnInitialUpdate为窗口创建后第一个调用的函数)
   CScrollView::SetScrollSizes(MM_TEXT,CSize(800,600));

五.图形错位问题(在滚动窗口底部画线,窗口重绘后线向上错位)
1.原因:在OnPaint函数调用时调用了OnPrepareDC,该函数将视口原点上移(由(0,0)移到(0,-150));
 (注意:OnPrepareDC是根据滚动条的位置调整视口原点,若滚动条在顶部,则不改变视口原点)
2.解决办法:在图形保存前OnLButtonUp函数调用时),调用OnPrepareDC,保存视口原点上移后的坐标,这样重绘时的坐标就和保存的坐标一致了.
 OnPrepareDC(&dc);//调整视口原点
 dc.DPToLP(&m_ptOrigin);
 dc.DPToLP(&point);//转换
 CGraphic *pGraphic=new CGraphic(m_nDrawType,m_ptOrigin,point);//保存
 m_ptrArray.Add(pGraphic);

六.图形的保存与重绘(CMetaFile:就像一个画布,但保存的不是图形本身,而是绘制图形的命令)
1.在View类中添加成员变量
 CMetaFile m_dcMetaFile;
2.在View类的构造函数中调用
 m_dcMetaFile.Create();//创建一个内存元文件
3.将绘图dc都改成m_dcMetaFile,这样图形就可以自动保存到元文件对象中
 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;
 default:
  break;
 }
4.在OnDraw函数中关才元文件对象,然后调用PlayMetaFile显示图形
 HMETAFILE hMetaFile;
 hMetaFile=m_dcMetaFile.Close();
 pDC->PlayMetaFile(hMetaFile);//播放pDC中的图形绘制命令,不画重绘前的图形
 m_dcMetaFile.Create();
 m_dcMetaFile.PlayMetaFile(hMetaFile);//播放m_dcMetaFile的图形绘制命令,画重绘前的图形
 DeleteMetaFile(hMetaFile);
 
七.将元文件对象(CMetaFile)保存为文件
1.在菜单项OnFileSave中添加"保存"元文件代码
 CGraphicView::OnFileSave()
 {
  HMETAFILE hMetaFile;
  hMetaFile=m_dcMetaFile.Close();
  CopyMetaFile(hMetaFile,"meta.wmf");//wmf:windows meta file
  m_dcMetaFile.Create();
  DeleteMetaFile(hMetaFile);
 }
2.在菜单项OnFileOpen中添加"打开"元文件代码
 CGraphicView::OnFileOpen()
 {
  HMETAFILE hMetaFile;
  hMetaFile=GetMetaFile("meta.wmf");
  m_dcMetaFile.PlayMetaFile(hMetaFile);
  DeleteMetaFile(hMetaFile);
  Invalidate();
 }

八.利用兼容DC
1.在view类添加成员变量 CDC m_dcCompatible;
2.在OnLButtonUp中保存
 CClientDC dc(this);
 ......
 if(!m_dcCompatible.m_hDC)
 {
  m_dcCompatible.CreateCompatibleDC(&dc);
  CRect rect;
  GetClientRect(&rect);
  CBitmap bitmap;
  bitmap.CreateCompatibleBitmap(&dc,rect.Width(),rect.Height());
  m_dcCompatible.SelectObject(&bitmap);
  m_dcCompatible.BitBlt(0,0,rect.Width(),rect.Height(),&dc,0,0,SRCCOPY);
  //注意兼容BITMAP在选入兼容DC后,还需调用BitBlt将源dc中的颜色表和像素数据块COPY到
  //兼容DC中,不能像普通BITMAP那样选入后即可使用
  m_dcCompatible.SelectObject(pBrush);//选入透明画刷
 }
3.将画图dc改为m_dcCompatible
 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;
 default:
  break;
 }
4.图形的重绘在OnDraw函数中
 CRect rect;
 GetClientRect(&rect);
 pDC->BitBlt(0,0,rect.Width(),rect.Height(),&m_dcCompatible,0,0,SRCCOPY);
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值