一、问题:解决winform动态画图闪的问题,网上搜的方法,大部分都是:
- “this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);”,甚至直接“this.DoubleBuffered = true;”。
- 先 new 个Bitmap,画在Bitmap上,然后再把Bitmap画在界面上。
凡是直接这么给人解答问题的,基本都是属于道听途说,自己没试过的。或者根本就没注意要解决的是“动态”的问题。
二、解决方法:动态画图不闪的方法如下,先上效果图(请忽略鼠标样式,是gif录制软件的效果):
三、代码:简单封了个自定义控件,用Action传入画图方法:
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="PictureBoxEx.cs" company="hyl">
// hyl
// </copyright>
// <summary>
// 用Action传画图方法。不闪。
// </summary>
// -------------------------------------------------------------------------------------------------------------------- namespace HYL
{
using System;
using System.Drawing;
using System.Windows.Forms; public partial class PictureBoxEx : PictureBox
{
/// <summary>
/// 画图方法
/// </summary>
private Action<Graphics> draw; public PictureBoxEx()
{
this.InitializeComponent(); // 开双缓存(用这种方法,画图不太复杂的话,甚至不开也不闪。。。)
this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);
} public void Rander(Action<Graphics> Draw)
{
this.Invalidate();
this.draw = Draw;
} protected override void OnPaint(PaintEventArgs pe)
{
base.OnPaint(pe); // 画图
this.draw?.Invoke(pe.Graphics);
}
}
}
重点在于要在 “OnPaint” 执行画图代码,也就是说要用 “OnPaint” 里的 “pe.Graphics” 来画。
四、调用的方式如下:
namespace HYL
{
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms; public partial class Form1 : Form
{
List<Line> lines = new List<Line>(); private bool painting; public Form1()
{
this.InitializeComponent();
} private void panel1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
// 左键确定点
if (this.btnLine.Checked)
{
this.lines.Last().Points.Add(new LinePoint { IsTemp = false, Point = e.Location });
this.painting = true;
}
} if (e.Button == MouseButtons.Right)
{
// 右键停止画图
if (this.btnLine.Checked)
{
this.ClearEmptyLines();
} this.painting = false;
this.btnLine.Checked = false;
}
} private void ClearEmptyLines()
{
this.lines = this.lines.Where(l => l.Points.Count > ).ToList();
if (this.lines.Count > )
{
var lastLine = this.lines.Last();
lastLine.ClearTempPoints();
}
} private void panel1_MouseMove(object sender, MouseEventArgs e)
{
if (this.painting)
{
if (this.btnLine.Checked)
{
this.PaintingLine(e);
} this.Draw();
}
} private void PaintingLine(MouseEventArgs e)
{
var lastLine = this.lines.Last();
var lastPoint = lastLine.Points.Last(); if (lastPoint.IsTemp)
{
lastLine.Points.Remove(lastPoint);
} LinePoint newPoint = new LinePoint { IsTemp = true, Point = e.Location };
lastLine.Points.Add(newPoint);
} /// <summary>
/// 画图
/// </summary>
private void Draw()
{
Action<Graphics> draw = g =>
{
Pen pen = new Pen(Color.Black, );
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality; if (this.lines != null)
{
foreach (Line line in this.lines)
{
g.DrawLines(pen, line.GetPoints().ToArray());
}
}
}; this.pictureBoxEx1.Rander(draw);
} private void btnLine_CheckedChanged(object sender, EventArgs e)
{
if (this.btnLine.Checked)
{
this.lines.Add(new Line());
}
else
{
this.ClearEmptyLines();
this.painting = false;
this.Draw();
}
}
} public class Line : ShapeElement
{
public Line()
{
this.Points = new List<LinePoint>();
} // 线里的点
public IList<LinePoint> Points { get; set; } // 获取Point的集合
public IList<Point> GetPoints()
{
return this.Points.Select(p => p.Point).ToList();
} // 清理临时点
public void ClearTempPoints()
{
this.Points = this.Points.Where(p => !p.IsTemp).ToList();
}
} public class LinePoint
{
public Point Point { get; set; } // 是否临时点
public bool IsTemp { get; set; }
}
}