1、問題:解決winform動態畫圖閃的問題,網上搜的方法,大部分都是:緩存
凡是直接這麼給人解答問題的,基本都是屬於道聽途說,本身沒試過的。或者根本就沒注意要解決的是「動態」的問題。ide
2、解決方法:動態畫圖不閃的方法以下,先上效果圖(請忽略鼠標樣式,是gif錄製軟件的效果):this
3、代碼:簡單封了個自定義控件,用Action傳入畫圖方法:spa
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」 來畫。code
4、調用的方式以下:orm
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 }