Winform 动态 画图 不闪

  一、问题:解决winform动态画图闪的问题,网上搜的方法,大部分都是:

  1. “this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);”,甚至直接“this.DoubleBuffered = true;”。
  2. 先 new 个Bitmap,画在Bitmap上,然后再把Bitmap画在界面上。

  凡是直接这么给人解答问题的,基本都是属于道听途说,自己没试过的。或者根本就没注意要解决的是“动态”的问题。

  二、解决方法:动态画图不闪的方法如下,先上效果图(请忽略鼠标样式,是gif录制软件的效果):

  

  三、代码:简单封了个自定义控件,用Action传入画图方法:

 1 // --------------------------------------------------------------------------------------------------------------------
 2 // <copyright file="PictureBoxEx.cs" company="hyl">
 3 //   hyl
 4 // </copyright>
 5 // <summary>
 6 //   用Action传画图方法。不闪。
 7 // </summary>
 8 // --------------------------------------------------------------------------------------------------------------------
 9 
10 namespace HYL
11 {
12     using System;
13     using System.Drawing;
14     using System.Windows.Forms;
15 
16     public partial class PictureBoxEx : PictureBox
17     {
18         /// <summary>
19         /// 画图方法
20         /// </summary>
21         private Action<Graphics> draw;
22 
23         public PictureBoxEx()
24         {
26             this.InitializeComponent();
27 
28             // 开双缓存(用这种方法,画图不太复杂的话,甚至不开也不闪。。。)
29             this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);
30         }
31 
32         public void Rander(Action<Graphics> Draw)
33         {
34             this.Invalidate();
35             this.draw = Draw;
36         }
37 
38         protected override void OnPaint(PaintEventArgs pe)
39         {
40             base.OnPaint(pe);
41 
42             // 画图
43             this.draw?.Invoke(pe.Graphics);
44         }
45     }
46 }

  重点在于要在 “OnPaint” 执行画图代码,也就是说要用 “OnPaint” 里的 “pe.Graphics” 来画。

  四、调用的方式如下:

  1 namespace HYL
  2 {
  3     using System;
  4     using System.Collections.Generic;
  5     using System.Drawing;
  6     using System.Linq;
  7     using System.Windows.Forms;
  8 
  9     public partial class Form1 : Form
 10     {
 11         List<Line> lines = new List<Line>();
 12 
 13         private bool painting;
 14 
 15         public Form1()
 16         {
 17             this.InitializeComponent();
 18         }
 19 
 20         private void panel1_MouseDown(object sender, MouseEventArgs e)
 21         {
 22             if (e.Button == MouseButtons.Left)
 23             {
 24                 // 左键确定点
 25                 if (this.btnLine.Checked)
 26                 {
 27                     this.lines.Last().Points.Add(new LinePoint { IsTemp = false, Point = e.Location });
 28                     this.painting = true;
 29                 }
 30             }
 31 
 32             if (e.Button == MouseButtons.Right)
 33             {
 34                 // 右键停止画图
 35                 if (this.btnLine.Checked)
 36                 {
 37                     this.ClearEmptyLines();
 38                 }
 39 
 40                 this.painting = false;
 41                 this.btnLine.Checked = false;
 42             }
 43         }
 44 
 45         private void ClearEmptyLines()
 46         {
 47             this.lines = this.lines.Where(l => l.Points.Count > 1).ToList();
 48             if (this.lines.Count > 0)
 49             {
 50                 var lastLine = this.lines.Last();
 51                 lastLine.ClearTempPoints();
 52             }
 53         }
 54 
 55         private void panel1_MouseMove(object sender, MouseEventArgs e)
 56         {
 57             if (this.painting)
 58             {
 59                 if (this.btnLine.Checked)
 60                 {
 61                     this.PaintingLine(e);
 62                 }
 63 
 64                 this.Draw();
 65             }
 66         }
 67 
 68         private void PaintingLine(MouseEventArgs e)
 69         {
 70             var lastLine = this.lines.Last();
 71             var lastPoint = lastLine.Points.Last();
 72 
 73             if (lastPoint.IsTemp)
 74             {
 75                 lastLine.Points.Remove(lastPoint);
 76             }
 77 
 78             LinePoint newPoint = new LinePoint { IsTemp = true, Point = e.Location };
 79             lastLine.Points.Add(newPoint);
 80         }
 81 
 82         /// <summary>
 83         /// 画图
 84         /// </summary>
 85         private void Draw()
 86         {
 87             Action<Graphics> draw = g =>
 88                 {
 89                     Pen pen = new Pen(Color.Black, 2);
 90                     g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
 91                     g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
 92 
 93                     if (this.lines != null)
 94                     {
 95                         foreach (Line line in this.lines)
 96                         {
 97                             g.DrawLines(pen, line.GetPoints().ToArray());
 98                         }
 99                     }
100                 };
101 
102             this.pictureBoxEx1.Rander(draw);
103         }
104 
105         private void btnLine_CheckedChanged(object sender, EventArgs e)
106         {
107             if (this.btnLine.Checked)
108             {
109                 this.lines.Add(new Line());
110             }
111             else
112             {
113                 this.ClearEmptyLines();
114                 this.painting = false;
115                 this.Draw();
116             }
117         }
118     }
119 
120     public class Line : ShapeElement
121     {
122         public Line()
123         {
124             this.Points = new List<LinePoint>();
125         }
126 
127         // 线里的点
128         public IList<LinePoint> Points { get; set; }
129 
130         // 获取Point的集合
131         public IList<Point> GetPoints()
132         {
133             return this.Points.Select(p => p.Point).ToList();
134         }
135 
136         // 清理临时点
137         public void ClearTempPoints()
138         {
139             this.Points = this.Points.Where(p => !p.IsTemp).ToList();
140         }
141     }
142 
143     public class LinePoint
144     {
145         public Point Point { get; set; }
146 
147         // 是否临时点
148         public bool IsTemp { get; set; }
149     }
150 }

 

posted @ 2017-02-09 16:41  David Huang  阅读(1030)  评论(0编辑  收藏  举报