分享

[C#]GDI+在鼠标移动(MouseMove)时画平滑曲线

 quasiceo 2013-04-27

[C#]GDI+在鼠标移动(MouseMove)时画平滑曲线


关于平滑曲线,相信很多人在网上提过这个问题,如何画出平滑曲线?我也很想知道答案,究竟如何才能在MouseMove事件里画出真正平滑又柔和的曲线?注意本文讨论的重点是在MouseMove事件里,并非相对固定的几个点
针对这个问题,网上给出了很多种方案。看到最多的是用类似gdi的moveto,lineto实现,gdi+则是drawline,但这个方案有一个很明显的漏洞:在MouseMove事件里,当用户快速移动鼠标时,我们可以很明显的看到画出的曲线是由直线段拼接而成,一点都不圆滑,这和我们的主题相差太远,所以否决这种方案。
当然网上也给出了另一种方案:DrawCurve
第一次看到这个方法,我就像发现新大陆一样,因为网上给出的效果图确实非常圆滑。
但很可惜,实践证明,用DrawCurve方法在相对固定的几个点下画曲线确实平滑,但一旦移到MouseMove事件里却出现了各种各样的问题,比如锯齿,“毛刺”等,下图就非常直观的呈现出了这些特征

有问题理应要有相应的解决方案,很荣幸,我们找到了Pen的线帽(StartCap/EndCap)和联接样式(LineJoin)两个属性,这两个恰恰是刚刚提到那两个问题的“克星”,线帽用来对付锯齿,而联接样式则是用来对付“毛刺”,只要分别设置这三个属性为Round即可,缺一不可哈:)

未设置线帽的效果

 

未设置联接样式的效果

 

只有三个属性设全了,才能画出“真正”完美的平滑曲线

 

附上测试代码,有兴趣的读者不妨一试

  1. public partial class Form1 : Form  
  2. {  
  3.     private bool initial = true, startDraw;  
  4.     List<Point> pList = new List<Point>();  
  5.   
  6.     public Form1()  
  7.     {  
  8.         InitializeComponent();  
  9.     }  
  10.   
  11.     protected override void OnPaint(PaintEventArgs e)  
  12.     {  
  13.         base.OnPaint(e);  
  14.         if (initial) //窗体刚加载时不重绘  
  15.         {  
  16.             return;  
  17.         }  
  18.         Graphics g = e.Graphics;  
  19.         g.SmoothingMode = SmoothingMode.AntiAlias;  
  20.         using (Pen p = new Pen(Color.Black, 15))  
  21.         {  
  22.             //设置起止点线帽  
  23.             p.StartCap = LineCap.Round;  
  24.             p.EndCap = LineCap.Round;  
  25.   
  26.             //设置连续两段的联接样式  
  27.             p.LineJoin = LineJoin.Round;  
  28.   
  29.             g.DrawCurve(p, pList.ToArray()); //画平滑曲线  
  30.         }  
  31.     }  
  32.   
  33.     private void Form1_MouseDown(object sender, MouseEventArgs e)  
  34.     {  
  35.         if (e.Button == MouseButtons.Left)  
  36.         {  
  37.             initial = false;  
  38.             startDraw = true;  
  39.             pList.Add(e.Location);  
  40.         }  
  41.     }  
  42.   
  43.     private void Form1_MouseMove(object sender, MouseEventArgs e)  
  44.     {  
  45.         if (e.Button == MouseButtons.Left && startDraw)  
  46.         {  
  47.             pList.Add(e.Location);  
  48.             this.Refresh();  
  49.         }  
  50.     }  
  51.   
  52.     private void Form1_MouseUp(object sender, MouseEventArgs e)  
  53.     {  
  54.         if (e.Button == MouseButtons.Left)  
  55.         {  
  56.             startDraw = false;  
  57.         }  
  58.     }  
  59. }  

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多