MFC(绘图与保存,孙鑫C++第十一讲笔记整理)

前面画图步骤直接上略了,因为跟第十讲的步骤是一样的,这里不再累赘

1.创建4个菜单,为其添加消息响应,用成员变量保存绘画类型。添加LButtonDown和Up消息。

 

2.当窗口重绘时,如果想再显示原先画的数据,则需要保存数据。为此创建一个新类来记录绘画类型和两个点。

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::OnLButtonUp(UINT nFlags, CPoint point)中加入如下代码

 //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);*///加入到指针数组中

在GraphicView.h中有如下代码

 CPtrArray m_ptrArray;

  在OnDraw中重画时调出数据

 for(int i=0;i<m_ptrArray.GetSize();i++)

 

3.在CView::OnPaint()调用了OnDraw(),但在void CGraphicView::OnPaint()中MFC的Wizard没有调用OnDraw(),要注意这个区别。如果你此时想调用,必须手动添加代码。 OnDraw(&dc);

 

4.让窗口具有滚动条的功能。

  第1.将CGraphicView的头文件中的CView全部替换成CSrollView

  第2.添加如下的代码

void CGraphicView::OnInitialUpdate()

{

 CScrollView::OnInitialUpdate();

 

 // TOD Add your specialized code here and/or call the base class

 SetScrollSizes(MM_TEXT,CSize(800,600));//设置映射模式,设定窗口大小。OK!

}

 

5.坐标系的转换,此处不再详细介绍,需要时请查阅相关资料。

 

6.解决重绘时线跑到上面的问题。为什么会错位?因为逻辑坐标和设备坐标没有对应起来。

解决方法:

 在OnLButtonDown画完图后,保存之前。调用

/* OnPrepareDC(&dc);//重新设置逻辑坐标的原点!!!

 dc.DPtoLP(&m_ptOrigin);//设备坐标转化为逻辑坐标

 dc.DPtoLP(&point);

 CGraph *pGraph=new CGraph(m_nDrawType,m_ptOrigin,point);

 m_ptrArray.Add(pGraph);*/

 

7.另外两种方法来保存数据。

 一种是用CMetaFileDC

 另一种是利用兼容DC,重绘时利用 pDC->BitBlt(0,0,rect.Width(),rect.Height(),&m_dcCompatible,0,0,SRCCOPY);

 

[cpp]  view plain copy
  1. void CHuiTuBaoView::OnLButtonUp(UINT nFlags, CPoint point)   
  2. {  
  3.     // TODO: Add your message handler code here and/or call default  
  4.       
  5.   
  6.     /*CClientDC ccdc(this); 
  7.     CBrush *cbrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH)); 
  8.     ccdc.SelectObject(cbrush); 
  9.  
  10.     switch(m_leixing) 
  11.     { 
  12.     case 0: 
  13.         ccdc.SetPixel(point,RGB(0,0,0)); 
  14.         break; 
  15.  
  16.     case 1: 
  17.         ccdc.MoveTo(m_yuandian); 
  18.         ccdc.LineTo(point); 
  19.         break; 
  20.  
  21.     case 2: 
  22.         ccdc.Rectangle(&CRect(m_yuandian,point)); 
  23.         break; 
  24.  
  25.     case 3: 
  26.         ccdc.Ellipse(&CRect(m_yuandian,point)); 
  27.         break; 
  28.     default: 
  29.         break; 
  30.     }*/  
  31.   
  32.   
  33.     //CHUATU huatu(m_leixing,m_yuandian,point);//对象的声明周期在右大括号结束之后就销毁了,所以不可行  
  34.     //m_carray.Add(&huatu);  
  35.   
  36.     CHUATU *huatu=new CHUATU(m_leixing,m_yuandian,point);//使用指针,在堆栈分配了空间,与整个程序的声明周期一致,可行  
  37.     m_carray.Add(huatu);  
  38.     Invalidate();  
  39.   
  40.     CView::OnLButtonUp(nFlags, point);  
  41. }  

 


 

[cpp]  view plain copy
  1. void CHuiTuBaoView::OnDraw(CDC* pDC)  
  2. {  
  3.     CHuiTuBaoDoc* pDoc = GetDocument();  
  4.     ASSERT_VALID(pDoc);  
  5.     // TODO: add draw code for native data here  
  6.   
  7.   
  8.     CBrush *cbrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));  
  9.     pDC->SelectObject(cbrush);  
  10.   
  11.     for(int i=0;i<m_carray.GetSize();++i)  
  12.     {  
  13.         switch(((CHUATU*)m_carray.GetAt(i))->m_cleixing)  
  14.         {  
  15.         case 0:  
  16.             pDC->SetPixel(((CHUATU*)m_carray.GetAt(i))->m_czhondian,RGB(255,0,0));  
  17.             break;  
  18.           
  19.         case 1:  
  20.             pDC->MoveTo(((CHUATU*)m_carray.GetAt(i))->m_cyuandian);  
  21.             pDC->LineTo(((CHUATU*)m_carray.GetAt(i))->m_czhondian);  
  22.             break;  
  23.   
  24.         case 2:  
  25.             pDC->Rectangle(&CRect(((CHUATU*)m_carray.GetAt(i))->m_cyuandian,((CHUATU*)m_carray.GetAt(i))->m_czhondian));  
  26.               
  27.             break;  
  28.   
  29.         case 3:  
  30.             pDC->Ellipse(&CRect(((CHUATU*)m_carray.GetAt(i))->m_cyuandian,((CHUATU*)m_carray.GetAt(i))->m_czhondian));  
  31.             break;  
  32.         default:  
  33.             break;  
  34.         }  
  35.     }  
  36.   
  37. }  


上面使用CPtrArray来保存CHUATU的指针,那能不能使用我们熟悉的Vector动态数组来操作呢。试试便知

 

试验证明是可以的。

在CXXView头文件中写上

include<vector>

using namespace std;

然后定义成员变量

vector<CHUATU*>vv;

[cpp]  view plain copy
  1. void CHuiTuBaoView::OnLButtonUp(UINT nFlags, CPoint point)   
  2. {  
  3.     // TODO: Add your message handler code here and/or call default  
  4.       
  5.   
  6.     /*CClientDC ccdc(this); 
  7.     CBrush *cbrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH)); 
  8.     ccdc.SelectObject(cbrush); 
  9.  
  10.     switch(m_leixing) 
  11.     { 
  12.     case 0: 
  13.         ccdc.SetPixel(point,RGB(0,0,0)); 
  14.         break; 
  15.  
  16.     case 1: 
  17.         ccdc.MoveTo(m_yuandian); 
  18.         ccdc.LineTo(point); 
  19.         break; 
  20.  
  21.     case 2: 
  22.         ccdc.Rectangle(&CRect(m_yuandian,point)); 
  23.         break; 
  24.  
  25.     case 3: 
  26.         ccdc.Ellipse(&CRect(m_yuandian,point)); 
  27.         break; 
  28.     default: 
  29.         break; 
  30.     }*/  
  31.   
  32.   
  33.     //CHUATU huatu(m_leixing,m_yuandian,point);  
  34.     //m_carray.Add(&huatu);  
  35.   
  36.     /*CHUATU *huatu=new CHUATU(m_leixing,m_yuandian,point); 
  37.     m_carray.Add(huatu); 
  38.     Invalidate();*/  
  39.   
  40.     CHUATU *huatu=new CHUATU(m_leixing,m_yuandian,point);  
  41.     vv.push_back(huatu);  
  42.     Invalidate();  
  43.   
  44.     CView::OnLButtonUp(nFlags, point);  
  45. }  


 

[cpp]  view plain copy
  1. void CHuiTuBaoView::OnDraw(CDC* pDC)  
  2. {  
  3.     CHuiTuBaoDoc* pDoc = GetDocument();  
  4.     ASSERT_VALID(pDoc);  
  5.     // TODO: add draw code for native data here  
  6.   
  7.   
  8.     CBrush *cbrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));  
  9.     pDC->SelectObject(cbrush);  
  10.   
  11.     /*for(int i=0;i<m_carray.GetSize();++i) 
  12.     { 
  13.         switch(((CHUATU*)m_carray.GetAt(i))->m_cleixing) 
  14.         { 
  15.         case 0: 
  16.             pDC->SetPixel(((CHUATU*)m_carray.GetAt(i))->m_czhondian,RGB(255,0,0)); 
  17.             break; 
  18.          
  19.         case 1: 
  20.             pDC->MoveTo(((CHUATU*)m_carray.GetAt(i))->m_cyuandian); 
  21.             pDC->LineTo(((CHUATU*)m_carray.GetAt(i))->m_czhondian); 
  22.             break; 
  23.  
  24.         case 2: 
  25.             pDC->Rectangle(&CRect(((CHUATU*)m_carray.GetAt(i))->m_cyuandian,((CHUATU*)m_carray.GetAt(i))->m_czhondian)); 
  26.              
  27.             break; 
  28.  
  29.         case 3: 
  30.             pDC->Ellipse(&CRect(((CHUATU*)m_carray.GetAt(i))->m_cyuandian,((CHUATU*)m_carray.GetAt(i))->m_czhondian)); 
  31.             break; 
  32.         default: 
  33.             break; 
  34.         } 
  35.     }*/  
  36.   
  37.     for(vector<CHUATU*>::iterator itera=vv.begin();itera!=vv.end();++itera)  
  38.     {  
  39.         switch((*itera)->m_cleixing)  
  40.         {  
  41.         case 0:  
  42.             pDC->SetPixel((*itera)->m_czhondian,RGB(255,0,0));  
  43.             break;  
  44.   
  45.         case 1:  
  46.             pDC->MoveTo((*itera)->m_cyuandian);  
  47.             pDC->LineTo((*itera)->m_czhondian);  
  48.             break;  
  49.   
  50.         case 2:  
  51.             pDC->Rectangle(&CRect((*itera)->m_cyuandian,(*itera)->m_czhondian));  
  52.             break;  
  53.   
  54.         case 3:  
  55.             pDC->Ellipse(&CRect((*itera)->m_cyuandian,(*itera)->m_czhondian));  
  56.             break;  
  57.   
  58.         }  
  59.     }  
  60.   
  61. }  


可以使用很多方法解决,不要丢了我们前面学习的C++知识喔。

 

下面是有关GDI映射的问题,具体也可以看我的Windows32GDI映射的博客

 

 

 

 

 

 

  OnPrepareDC会随时根据滚动窗口的位置来调整视口的原点

 

下面是一个关于设置坐标位置的例子。

手动设置滚动条

1class CXXView : public CView--->class CXXView : public CScrollView

2把cpp文件中的CView全部替换成CScrollView

3设置滚动条的属性

[cpp]  view plain copy
  1. void SetScrollSizes( int nMapMode, SIZE sizeTotal, const SIZE& sizePage = sizeDefault, const SIZE& sizeLine = sizeDefault );  

 

在CXXView中添加一个虚函数OnInitUpdate函数

4添加一条代码,这个函数是在调用OnDraw之前调用的

[cpp]  view plain copy
  1. void CHuiTuBaoView::OnInitialUpdate()   
  2. {  
  3.     CScrollView::OnInitialUpdate();  
  4.       
  5.     // TODO: Add your specialized code here and/or call the base class  
  6.   
  7.     SetScrollSizes(MM_TEXT,CSize(800,600));  
  8.       
  9. }  


然后就可以显示滚动条了:

 

然后用老师讲的方法,可以解决坐标映射问题,上面的PPT有讲问题的现象和解决方法

[cpp]  view plain copy
  1. void CHuiTuBaoView::OnLButtonUp(UINT nFlags, CPoint point)   
  2. {  
  3.     // TODO: Add your message handler code here and/or call default  
  4.       
  5.   
  6.     /*CClientDC ccdc(this); 
  7.     CBrush *cbrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH)); 
  8.     ccdc.SelectObject(cbrush); 
  9.  
  10.     switch(m_leixing) 
  11.     { 
  12.     case 0: 
  13.         ccdc.SetPixel(point,RGB(0,0,0)); 
  14.         break; 
  15.  
  16.     case 1: 
  17.         ccdc.MoveTo(m_yuandian); 
  18.         ccdc.LineTo(point); 
  19.         break; 
  20.  
  21.     case 2: 
  22.         ccdc.Rectangle(&CRect(m_yuandian,point)); 
  23.         break; 
  24.  
  25.     case 3: 
  26.         ccdc.Ellipse(&CRect(m_yuandian,point)); 
  27.         break; 
  28.     default: 
  29.         break; 
  30.     }*/  
  31.   
  32.   
  33.     //CHUATU huatu(m_leixing,m_yuandian,point);  
  34.     //m_carray.Add(&huatu);  
  35.   
  36.     /*CHUATU *huatu=new CHUATU(m_leixing,m_yuandian,point); 
  37.     m_carray.Add(huatu); 
  38.     Invalidate();*/  
  39.       
  40.     CClientDC ccdc(this);  
  41.   
  42.   
  43.     OnPrepareDC(&ccdc);  
  44.     ccdc.DPtoLP(&m_yuandian);  
  45.     ccdc.DPtoLP(&point);  
  46.     CHUATU *huatu=new CHUATU(m_leixing,m_yuandian,point);  
  47.     vv.push_back(huatu);  
  48.     Invalidate();  
  49.   
  50.     CScrollView::OnLButtonUp(nFlags, point);  
  51. }  


这样就完美解决了。

OnPaint中调用了OnprepareDC和OnDraw函数,OnprepareDC就是用来调整(设备环境)视口的

 

使用原文件上下文保存图像,CMetaFileDC

在OnLButtonUp中,CMetaFileDC yuanwenjian是成员变量,构造函数中Create

[cpp]  view plain copy
  1. CBrush *cbrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));  
  2.     yuanwenjiandc.SelectObject(cbrush);  
  3.   
  4.     switch(m_leixing)  
  5.     {  
  6.     case 0:  
  7.         yuanwenjiandc.SetPixel(point,RGB(0,0,0));  
  8.         break;  
  9.   
  10.     case 1:  
  11.         yuanwenjiandc.MoveTo(m_yuandian);  
  12.         yuanwenjiandc.LineTo(point);  
  13.         break;  
  14.   
  15.     case 2:  
  16.         yuanwenjiandc.Rectangle(&CRect(m_yuandian,point));  
  17.         break;  
  18.   
  19.     case 3:  
  20.         yuanwenjiandc.Ellipse(&CRect(m_yuandian,point));  
  21.         break;  
  22.     default:  
  23.         break;  
  24.     }  


在OnDraw中

[cpp]  view plain copy
  1. void CHuiTuBaoView::OnDraw(CDC* pDC)  
  2. {  
  3.     CHuiTuBaoDoc* pDoc = GetDocument();  
  4.     ASSERT_VALID(pDoc);  
  5.     // TODO: add draw code for native data here  
  6.   
  7.   
  8.     CBrush *cbrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));  
  9.     pDC->SelectObject(cbrush);  
  10.   
  11.   
  12.     HMETAFILE hmetafile;  
  13.     hmetafile=yuanwenjiandc.Close();  
  14.     pDC->PlayMetaFile(hmetafile);  
  15.     yuanwenjiandc.Create();  
  16.     DeleteMetaFile(hmetafile);}//一定要关闭,否则出错  


如果还想要保存原来的图画,这这样

[cpp]  view plain copy
  1. void CHuiTuBaoView::OnDraw(CDC* pDC)  
  2. {  
  3.     CHuiTuBaoDoc* pDoc = GetDocument();  
  4.     ASSERT_VALID(pDoc);  
  5.     // TODO: add draw code for native data here  
  6.   
  7.   
  8.     CBrush *cbrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));  
  9.     pDC->SelectObject(cbrush);  
  10.   
  11.   
  12.     HMETAFILE hmetafile;  
  13.     hmetafile=yuanwenjiandc.Close();  
  14.     pDC->PlayMetaFile(hmetafile);  
  15.     yuanwenjiandc.Create();  
  16.     yuanwenjiandc.PlayMetaFile(hmetafile);//保存上一次绘画的图案  
  17.     DeleteMetaFile(hmetafile);  
  18. }  


CMetaFile只是保存的是绘图的命令,而不是文件

下面给打开和保存添加事件

[cpp]  view plain copy
  1. void CHuiTuBaoView::OnFileSave()   
  2. {  
  3.  // TODO: Add your command handler code here  
  4.  HMETAFILE hmetafile;  
  5.  hmetafile=yuanwenjiandc.Close();  
  6.  CopyMetaFile(hmetafile,"meta.wmf");  
  7.  yuanwenjiandc.Create();  
  8.  DeleteMetaFile(hmetafile);  
  9. }  
[cpp]  view plain copy
  1. void CHuiTuBaoView::OnFileOpen()   
  2. {  
  3.     // TODO: Add your command handler code here  
  4.     HMETAFILE hmetafile;  
  5.     hmetafile=GetMetaFile("meta.wmf");  
  6.     yuanwenjiandc.PlayMetaFile(hmetafile);  
  7.     DeleteMetaFile(hmetafile);  
  8.     Invalidate();  
  9.   
  10. }  


使用另外一种方法保存,兼容DC

在OnLButtonUp中

[cpp]  view plain copy
  1. CBrush *cbrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));  
  2.     CClientDC ccdc(this);  
  3.   
  4.     if(!compatibledc)  
  5.     {  
  6.         compatibledc.CreateCompatibleDC(&ccdc);  
  7.         CRect rect;  
  8.         GetClientRect(&rect);  
  9.         CBitmap bitmap;  
  10.         bitmap.CreateCompatibleBitmap(&ccdc,rect.Width(),rect.Height());  
  11.         compatibledc.SelectObject(&bitmap);  
  12.         compatibledc.SelectObject(cbrush);  
  13.         compatibledc.BitBlt(0,0,rect.Width(),rect.Height(),&ccdc,0,0,SRCCOPY);//兼容位图跟普通不一样  
  14.     }  
  15.     yuanwenjiandc.SelectObject(cbrush);  
  16.       
  17.     switch(m_leixing)  
  18.     {  
  19.     case 0:  
  20.         compatibledc.SetPixel(point,RGB(0,0,0));  
  21.         break;  
  22.           
  23.     case 1:  
  24.         compatibledc.MoveTo(m_yuandian);  
  25.         compatibledc.LineTo(point);  
  26.         break;  
  27.           
  28.     case 2:  
  29.         compatibledc.Rectangle(&CRect(m_yuandian,point));  
  30.         break;  
  31.           
  32.     case 3:  
  33.         compatibledc.Ellipse(&CRect(m_yuandian,point));  
  34.         break;  
  35.     default:  
  36.         break;  
  37.     }  


OnDraw中

[cpp]  view plain copy
  1. CRect rect;  
  2. GetClientRect(&rect);  
  3. pDC->BitBlt(0,0,rect.Width(),rect.Height(),&compatibledc,0,0,SRCCOPY);  


  • 3
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值