打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
VC/MFC动态画线,画圆,画椭圆,画矩形

2012年12月7日 22:42:14

今天我在csdn网站上通过学习别人的博客学习到了动态画矩形,画线的方法,这使得我对Windows的消息循环机制有了更深刻的理解。首先来总结一下我今天的收获,呵呵有收获就是不错的,说明我进步了,感谢这两篇博文:

VC鼠标拖动动态画矩形框(http://blog.csdn.net/zhouxuguang236/article/details/7686163) 和 VC动态轨迹画线 (http://blog.csdn.net/akof1314/article/details/5547616),更感谢转载前一篇博文的作者(周旭光),是他给了我第二个博文的链接,使得我不用自己去搜索并尝试哪一篇的博文更便于我的学习。

好了下面开始言归正传:

所谓的动态画线,画矩形,画椭圆的本质就是在于消隐问题的解决以及对Windows消息循环机制的理解,消隐问题:因为MFC中有一个函数SetROP2,通过将该函数的参数设置为R2—NOT(当前绘制的像素值设为屏幕像素值的反色,这里面的“屏幕”二字是指你所绘制的图形所占据的那一部分屏幕区域,即直线所占的屏幕区域就是直线所在的那一段线的区域),利用这一点通过在同一区域重复画两次便可以将该区域的形状消隐。

而Windows消息循环机制更好的体现于MouseMove消息响应中,因为要实现动态画线、画矩形这就体现在鼠标在绘图区的移动上,鼠标在绘图区移动时,产生动态的效果,也就是说在mouse 移动的过程中始终在画线、画矩形,这就要求在MouseMove消息响应中有画线、画矩形的相应函数的调用,但正是因为mouse移动的过程中画了很多的线、矩形,所以我们就要在mouse移动的过程中将之前画出的线、矩形消隐掉,才能保证实现了自己所要实现的功能——动态画线、画矩形,但又没有产生多余的线和矩形。

消隐的问题和动态画图的问题关键在于MouseMove消息响应中的函数调用的顺序:

1.首先将上次所画的图形消隐掉

2.画出临时的图形

3.消息循环的机制:循环执行上述代码(这是Windows循环的机制,不需要自己代码实现)

 

在最后的LButtonUp消息响应中,需要将上面的MouseMove消息响应中循环的最后一次中最后所画的临时图形消隐掉,之后根据LButtonUp消息响应中point参数画出最终的图形。综上可知:MouseMove中的代码和LButtonUp中消隐临时图形的代码所要实现的功能就是动态这一过程,而图形的最终绘制还在与LButtonUp消息响应及其point参数。

代码如下:

  1. private:  
  1. //......  
  2.     HCURSOR m_HCross;  
  3.     UINT m_drawType;  
  4.     CPoint m_OldPoint;  
  5.     CPoint m_startPoint;  
  6.     BOOL m_startRect;  
  1. CGISView::CGISView()  
  2. {  
  3.     // TODO: add construction code here  
  4.     //....  
  5.     m_startRect=FALSE;  
  6.     m_startPoint=0;  
  7.     m_OldPoint=0;  
  8.     m_drawType=0;  
  9.     //初始化m_HCross为十字光标  
  10.     m_HCross=AfxGetApp()->LoadStandardCursor(IDC_CROSS);  
  11.   
  12. }  
  1. void CGISView::OnLButtonDown(UINT nFlags, CPoint point)   
  2. {  
  3.     // TODO: Add your message handler code here and/or call default  
  4.     m_startRect=TRUE; //鼠标左键单击,设置可以开始绘制矩形框  
  5.     m_startPoint=point; //记录起始点  
  6.     m_OldPoint=point;//设置老点也为起始点  
  7.     //设置光标为十字光标  
  8.     ::SetCursor(m_HCross);  
  9.   
  10.   
  11.     CView::OnLButtonDown(nFlags, point);  
  12. }  
  1. void CGISView::OnMouseMove(UINT nFlags, CPoint point)   
  2. {  
  3.     // TODO: Add your message handler code here and/or call default  
  4.       
  5.     CClientDC dc(this); //获取设备句柄  
  6.     dc.SetROP2(R2_NOT);//此为关键  
  7.     dc.SetROP2(R2_NOT);//所绘制的图形并没有消失,所以可以验证下面的连续两次颜色取反不是在一次相应中完成  
  8.     //SetRop2 Specifies the new drawing mode.(MSDN)  
  9.          //R2_NOT   Pixel is the inverse of the screen color.(MSDN)  
  10.          //即:该函数用来定义绘制的颜色,而该参数则将颜色设置为原屏幕颜色的反色  
  11.     //这样,如果连续绘制两次的话,就可以恢复原来屏幕的颜色了(如下)  
  12.     //但是,这里的连续两次绘制却不是在一次消息响应中完成的  
  13.     //而是在第一次拖动响应的绘制可以显示(也就是看到的),第二次拖动绘制实现擦出(也就看不到了)  
  14.   
  15.     dc.SelectStockObject(NULL_BRUSH);//不使用画刷  
  16.     if(TRUE==m_startRect) //根据是否有单击判断是否可以画矩形  
  17.     {  
  18.         switch(m_drawType)  
  19.         {  
  20.                  case 1://Rectangle  
  21.   
  22.                 ::SetCursor(m_HCross);  
  23.                         dc.Rectangle(CRect(m_startPoint,m_OldPoint));  
  24.                         dc.Rectangle(CRect(m_startPoint,point));  
  25.                 m_OldPoint=point;  
  26.               
  27.                 break;  
  28.   
  29.              case 2: //Line  
  30.                 ::SetCursor(m_HCross);  
  31.                 //擦去上一次绘制的临时线  
  32.                 dc.MoveTo(m_startPoint);  
  33.                      dc.LineTo(m_OldPoint);     
  34.                   
  35.                 //绘制这一次的临时线  
  36.                        dc.MoveTo(m_startPoint);  
  37.                 dc.LineTo(point);  
  38.   
  39.                 //将临时线的终点复制给m_OldPoint,  
  40.                 //使其在消息循环的过程中将该值传递到  
  41.                 //擦去上一次画线的过程中,以便擦去上一次所画的线  
  42.                 m_OldPoint=point;  
  43.                   
  44.   
  45.   
  46.                 break;  
  47.              case 3:  //Circle  
  48.                 ::SetCursor(m_HCross);  
  49.                                //擦去上一次绘制的临时圆  
  50.                 //设定该圆的y坐标,因为要保证两点的x之差等于y之差  
  51.                 m_OldPoint.y=m_OldPoint.x-m_startPoint.x+m_startPoint.y;  
  52.                 dc.Ellipse(CRect(m_startPoint,m_OldPoint));  
  53.   
  54.                 //绘制临时圆  
  55.   
  56.                 point.y=point.x-m_startPoint.x+m_startPoint.y;  
  57.                 dc.Ellipse(CRect(m_startPoint,point));  
  58.   
  59.                 m_OldPoint=point;  
  60.                 break;  
  61.              case 4:  //Ellipse  
  62.                 ::SetCursor(m_HCross);  
  63.   
  64.                 dc.Ellipse(CRect(m_startPoint,m_OldPoint));  
  65.                 dc.Ellipse(CRect(m_startPoint,point));  
  66.                 m_OldPoint=point;  
  67.                 break;  
  68.              case 5:   //Dot  
  69.   
  70.                 break;  
  71.   
  72.     }  
  1. }  
  1. }  
  1. void CGISView::OnLButtonUp(UINT nFlags, CPoint point)   
  2. {  
  3.     // TODO: Add your message handler code here and/or call default  
  4.     m_startRect=FALSE;//重置绘制矩形框标志  
  5.     ::ClipCursor(NULL);//解锁光标,即将光标恢复为默认光标  
  6.     //消隐最后的一个矩形  
  7.     CClientDC dc(this);//获取设备句柄  
  8. //  dc.SetROP2(R2_NOT); //在MouseMove消息响应中使用过该函数了,所以在这里再一次使用会使得其恢复为屏幕的颜色  
  9.     dc.SelectStockObject(NULL_BRUSH);  //设置画刷为空画刷  
  10.     switch(m_drawType)  
  11.     {  
  12.     case 1: //Retangle  
  13.   
  14.         //利用当前画刷绘制矩形,内部由当前空画刷(NULL_BRUSH)填充。  
  15.         //擦去MouseMove消息响应中的临时矩形  
  16.         dc.Rectangle(CRect(m_startPoint,m_OldPoint));  
  17.         //绘制固定矩形  
  18.         dc.Rectangle(CRect(m_startPoint,point));  
  19.   
  20.         //m_drawType=0;  //该行的可以使得每画一次都要选择所画的形状  
  21.               break;  
  22.   
  23.           case 2:  //Line  
  24.   
  25.         //擦去MouseMove消息响应中绘制的最后一次临时线  
  26.          dc.MoveTo(m_startPoint);  
  27.                    dc.LineTo(m_OldPoint);  
  28.            
  29.          //绘制固定线  
  30.          dc.MoveTo(m_startPoint);  
  31.          dc.LineTo(point);  
  32.         break;  
  33.      case 3:  //Circle  
  34.    
  35.         dc.Ellipse(CRect(m_startPoint,m_OldPoint));  
  36.         dc.Ellipse(CRect(m_startPoint,point));  
  37.         break;  
  38.      case 4:  //Ellipse  
  39.   
  40.         dc.Ellipse(CRect(m_startPoint,m_OldPoint));  
  41.         dc.Ellipse(CRect(m_startPoint,point));  
  42.         break;  
  43.      case 5:  //Dot  
  44.                   dc.SetPixel(point,RGB(0,0,0));  
  45.         break;  
  46.       
  47.     }  
  48.     CView::OnLButtonUp(nFlags, point);  
  49. }  
  1. void CGISView::OnRectangle()   
  2. {  
  3.     // TODO: Add your command handler code here  
  4.     m_drawType=1;//设置所画的为矩形  
  5.       
  6. }  
  7.   
  8. void CGISView::OnLine()   
  9. {  
  10.     // TODO: Add your command handler code here  
  11.     m_drawType=2;  
  12. }  
  13.   
  14. void CGISView::OnEllipse()   
  15. {  
  16.     // TODO: Add your command handler code here  
  17.     m_drawType=4;  
  18. }  
  19.   
  20. void CGISView::OnDot()   
  21. {  
  22.     // TODO: Add your command handler code here  
  23.     m_drawType=5;  
  24.   
  25. }  
  26.   
  27. void CGISView::OnCircle()   
  28. {  
  29.     // TODO: Add your command handler code here  
  30.     m_drawType=3;  
  31. }  

 

以上为自己根据实际编程练习和对博文的学习所领悟到的,如果有哪里理解的不对,还望大家指正,谢谢哈!(代码没有问题,可以正常运行。)

注:代码的排版,我多次修改,并确保整齐,但是一旦我发表后,代码的排版就会发生改变,有几行代码就会变得不规则。

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
剖析Windows消息处理机制
利用VC调用动态链接库中的函数
VC学习的经典书籍
windows下怎么开发c++守护进程? - VC/MFC / 基础类
VC实现串行通信的动态链接库(DLL)
VC++动态链接库编程总结一
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服