刚开始学C#绘图时候做用户控件,直接在屏幕的Graphics画笔绘图,频繁刷新画布就明显肉眼可见抖动。那时候研究怎么减少绘图刷新的抖动,就接触到双缓存绘图概念。
源码地址
什么是双缓冲绘图呢?就是如果画笔直接在屏幕画板操作的话,每次绘制都会刷新屏幕,就会很抖动。双缓冲的方法是建立一个屏幕大小的bitmap,先画笔在bitmap上画完之后。再把整个画完的图画到屏幕画板,就极大的减少屏幕刷新,就减少抖动。
我以前找的介绍资料:
在图形图象处理编程过程中,双缓冲是一种基本的技术。我们知道,如果窗体在响应WM_PAINT消息的时候要进行复杂的图形处理,那么窗体在重绘时由于过频的刷新而引起闪烁现象。解决这一问题的有效方法就是双缓冲技术。
因为窗体在刷新时,总要有一个擦除原来图象的过程OnEraseBkgnd,它利用背景色填充窗体绘图区,然后在调用新的绘图代码进行重绘,这样一擦一写造成了图象颜色的反差。当WM_PAINT的响应很频繁的时候,这种反差也就越发明显。于是我们就看到了闪烁现象。
我们会很自然的想到,避免背景色的填充是最直接的办法。但是那样的话,窗体上会变的一团糟。因为每次绘制图象的时候都没有将原来的图象清除,造成了图象的残留,于是窗体重绘时,画面往往会变的乱七八糟。所以单纯的禁止背景重绘是不够的。我们还要进行重新绘图,但要求速度很快,于是我们想到了使用BitBlt函数。它可以支持图形块的复制,速度很快。我们可以先在内存中作图,然后用此函数将做好的图复制到前台,同时禁止背景刷新,这样就消除了闪烁。以上也就是双缓冲绘图的基本的思路。
用双缓冲和不用双缓冲的代码示例:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
namespace DoubleCushionDraw
{
public partial class Form1 : Form
{
int ss = 0;
public Form1()
{
InitializeComponent();
//Draw();
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
//Draw();
//Pen pen = new Pen(Color.Red);
//pen.Width = 1.0F;
//e.Graphics.DrawRectangle(pen, 1, i, 50, 50);
//e.Graphics.DrawRectangle(pen, 60, i, 50, 50);
//e.Graphics.DrawRectangle(pen, 120, i, 50, 50);
//e.Graphics.DrawRectangle(pen, 170, i, 50, 50);
//e.Graphics.DrawRectangle(pen, 220, i, 50, 50);
//e.Graphics.DrawRectangle(pen, 270, i, 50, 50);
//e.Graphics.DrawRectangle(pen, 320, i, 50, 50);
//e.Graphics.DrawRectangle(pen, 370, i, 50, 50);
//String drawString = "Sample Text";
Create font and brush.
//Font drawFont = new Font("Arial", 16);
//SolidBrush drawBrush = new SolidBrush(Color.Yellow);
Create rectangle for drawing.
//float x = 150.0F;
//float y = 150.0F+i;
//float width = 200.0F;
//float height = 50.0F;
//RectangleF drawRect = new RectangleF(x, y, width, height);
Draw rectangle to screen.
//Pen blackPen = new Pen(Color.Yellow);
//e.Graphics.DrawRectangle(blackPen, x, y, width, height);
Set format of string.
//StringFormat drawFormat = new StringFormat();
//drawFormat.Alignment = StringAlignment.Center;
Draw string to screen.
//e.Graphics.DrawString(drawString, drawFont, drawBrush, drawRect, drawFormat);
//timer1.Enabled = true;
//-----------------------------------------------------
//Rectangle rect = e.ClipRectangle;
//BufferedGraphicsContext currentContext = BufferedGraphicsManager.Current;
//BufferedGraphics myBuffer = currentContext.Allocate(e.Graphics, e.ClipRectangle);
//Graphics g = myBuffer.Graphics;
//g.SmoothingMode = SmoothingMode.HighQuality;
//g.PixelOffsetMode = PixelOffsetMode.HighSpeed;
g.Clear(this.BackColor);
//Pen pen = new Pen(Color.Red);
//pen.Width = 1.0F;
//e.Graphics.DrawRectangle(pen, 1, i, 50, 50);
//e.Graphics.DrawRectangle(pen, 60, i, 50, 50);
//e.Graphics.DrawRectangle(pen, 120, i, 50, 50);
//e.Graphics.DrawRectangle(pen, 170, i, 50, 50);
//e.Graphics.DrawRectangle(pen, 220, i, 50, 50);
//e.Graphics.DrawRectangle(pen, 270, i, 50, 50);
//e.Graphics.DrawRectangle(pen, 320, i, 50, 50);
//e.Graphics.DrawRectangle(pen, 370, i, 50, 50);
foreach (Shape shape in Server.ShapeList)
{
if (rect.IntersectsWith(drawobject.Rect))
{
drawobject.Draw(g);
if (drawobject.TrackerState == config.Module.Core.TrackerState.Selected
&& this.CurrentOperator == Enum.Operator.Transfrom)//仅当编辑节点操作时显示图元热点
{
drawobject.DrawTracker(g);
}
}
}
//myBuffer.Render(e.Graphics);
//g.Dispose();
//myBuffer.Dispose();//释放资源
//timer1.Enabled = true;
//---------------------------------------------
//Graphics g = e.Graphics;
//Pen bluePen = new Pen(Color.Blue);
//Bitmap localBitmap = new Bitmap(ClientRectangle.Width, ClientRectangle.Height);
//Graphics bitmapGraphics = Graphics.FromImage(localBitmap);
//LineDrawRoutine(bitmapGraphics, bluePen);
//bitmapGraphics.SmoothingMode = SmoothingMode.AntiAlias;
//g.DrawImage(localBitmap, 0, 0);
//bitmapGraphics.Dispose();
//bluePen.Dispose();
//localBitmap.Dispose();
//g.Dispose();
//timer1.Enabled = true;
}
bool flag = true;
bool flag1 = true;
bool a = false;
private void Draw()
{
if (a)
{
this.Refresh();
}
SolidBrush myBrush = new SolidBrush(this.BackColor );
//优化前
DateTime t1 = DateTime.Now;
Graphics g = this.CreateGraphics();
g.FillRectangle(myBrush ,new Rectangle (0,0,600,600));
LinearGradientBrush brush;
if (flag)
{
brush = new LinearGradientBrush(new PointF(0.0f, 0.0f),
new PointF(700.0f, 300.0f), Color.Red, Color.Blue);
flag = false;
}
else
{
brush = new LinearGradientBrush(new PointF(0.0f, 0.0f),
new PointF(700.0f, 300.0f), Color.Blue, Color.Red);
flag = true;
}
for (int j = 0; j < 60; j++)
{
for (int i = 0; i < 60; i++)
{
g.FillEllipse(brush, i * 10, j * 10, 10, 10);
}
}
Pen pen = new Pen(Color.Lime);
pen.Width = 2.0F;
g.DrawRectangle(pen, 1, ss, 50, 50);
g.DrawRectangle(pen, 60, ss, 50, 50);
g.DrawRectangle(pen, 120, ss, 50, 50);
g.DrawRectangle(pen, 170, ss, 50, 50);
g.DrawRectangle(pen, 220, ss, 50, 50);
g.DrawRectangle(pen, 270, ss, 50, 50);
g.DrawRectangle(pen, 320, ss, 50, 50);
g.DrawRectangle(pen, 370, ss, 50, 50);
//优化后
//DateTime t1 = DateTime.Now;
Bitmap bmp = new Bitmap(600, 600);
Graphics g1 = Graphics.FromImage(bmp);
g1.Clear(this.BackColor);
LinearGradientBrush brush1;
if (flag1)
{
brush1 = new LinearGradientBrush(new PointF(0.0f, 0.0f),
new PointF(700.0f, 300.0f), Color.Red, Color.Blue);
flag1 = false;
}
else
{
brush1 = new LinearGradientBrush(new PointF(0.0f, 0.0f),
new PointF(700.0f, 300.0f), Color.Blue, Color.Red);
flag1 = true;
}
for (int j = 0; j < 60; j++)
{
for (int i = 0; i < 60; i++)
{
g1.FillEllipse(brush1, i * 10, j * 10, 10, 10);
}
}
g1.DrawRectangle(pen, 1, ss, 50, 50);
g1.DrawRectangle(pen, 60, ss, 50, 50);
g1.DrawRectangle(pen, 120, ss, 50, 50);
g1.DrawRectangle(pen, 170, ss, 50, 50);
g1.DrawRectangle(pen, 220, ss, 50, 50);
g1.DrawRectangle(pen, 270, ss, 50, 50);
g1.DrawRectangle(pen, 320, ss, 50, 50);
g1.DrawRectangle(pen, 370, ss, 50, 50);
this.CreateGraphics().DrawImage(bmp, 650, 0);
}
private void timer1_Tick(object sender, EventArgs e)
{
ss = ss + 1;
if (checkBox1.CheckState == CheckState.Checked)
{
a = true;
}
else
{
a = false;
}
// this.Invalidate();
try
{
timer1.Interval = Convert.ToInt32(textBox1.Text);
}
catch (Exception)
{
}
Draw();
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
//Pen pen = new Pen(Color.Red);
//pen.Width = 1.0F;
//e.Graphics.DrawRectangle(pen, 1, i, 50, 50);
//e.Graphics.DrawRectangle(pen, 60, i, 50, 50);
//e.Graphics.DrawRectangle(pen, 120, i, 50, 50);
//e.Graphics.DrawRectangle(pen, 170, i, 50, 50);
//e.Graphics.DrawRectangle(pen, 220, i, 50, 50);
//e.Graphics.DrawRectangle(pen, 270, i, 50, 50);
//e.Graphics.DrawRectangle(pen, 320, i, 50, 50);
//e.Graphics.DrawRectangle(pen, 370, i, 50, 50);
//String drawString = "Sample Text";
Create font and brush.
//Font drawFont = new Font("Arial", 16);
//SolidBrush drawBrush = new SolidBrush(Color.Yellow);
Create rectangle for drawing.
//float x = 150.0F;
//float y = 150.0F+i;
//float width = 200.0F;
//float height = 50.0F;
//RectangleF drawRect = new RectangleF(x, y, width, height);
Draw rectangle to screen.
//Pen blackPen = new Pen(Color.Yellow);
//e.Graphics.DrawRectangle(blackPen, x, y, width, height);
Set format of string.
//StringFormat drawFormat = new StringFormat();
//drawFormat.Alignment = StringAlignment.Center;
Draw string to screen.
//e.Graphics.DrawString(drawString, drawFont, drawBrush, drawRect, drawFormat);
//timer1.Enabled = true;
//-----------------------------------------------------
//Rectangle rect = e.ClipRectangle;
//BufferedGraphicsContext currentContext = BufferedGraphicsManager.Current;
//BufferedGraphics myBuffer = currentContext.Allocate(e.Graphics, e.ClipRectangle);
//Graphics g = myBuffer.Graphics;
//g.SmoothingMode = SmoothingMode.HighQuality;
//g.PixelOffsetMode = PixelOffsetMode.HighSpeed;
g.Clear(this.BackColor);
//Pen pen = new Pen(Color.Red);
//pen.Width = 1.0F;
//e.Graphics.DrawRectangle(pen, 1, i, 50, 50);
//e.Graphics.DrawRectangle(pen, 60, i, 50, 50);
//e.Graphics.DrawRectangle(pen, 120, i, 50, 50);
//e.Graphics.DrawRectangle(pen, 170, i, 50, 50);
//e.Graphics.DrawRectangle(pen, 220, i, 50, 50);
//e.Graphics.DrawRectangle(pen, 270, i, 50, 50);
//e.Graphics.DrawRectangle(pen, 320, i, 50, 50);
//e.Graphics.DrawRectangle(pen, 370, i, 50, 50);
foreach (Shape shape in Server.ShapeList)
{
if (rect.IntersectsWith(drawobject.Rect))
{
drawobject.Draw(g);
if (drawobject.TrackerState == config.Module.Core.TrackerState.Selected
&& this.CurrentOperator == Enum.Operator.Transfrom)//仅当编辑节点操作时显示图元热点
{
drawobject.DrawTracker(g);
}
}
}
//myBuffer.Render(e.Graphics);
//g.Dispose();
//myBuffer.Dispose();//释放资源
//timer1.Enabled = true;
//---------------------------------------------
//Graphics g = e.Graphics;
//Pen bluePen = new Pen(Color.Blue);
//Bitmap localBitmap = new Bitmap(ClientRectangle.Width, ClientRectangle.Height);
//Graphics bitmapGraphics = Graphics.FromImage(localBitmap);
//LineDrawRoutine(bitmapGraphics, bluePen);
//bitmapGraphics.SmoothingMode = SmoothingMode.AntiAlias;
//g.DrawImage(localBitmap, 0, 0);
//bitmapGraphics.Dispose();
//bluePen.Dispose();
//localBitmap.Dispose();
//g.Dispose();
//timer1.Enabled = true;
}
private void LineDrawRoutine(Graphics g, Pen p)
{
//float width = ClientRectangle.Width;
//float height = ClientRectangle.Height;
//float xDelta = width / 20;
//float yDelta = height / 20;
//for (int j = 0; j < 20; j++)
//{
// g.DrawLine(p, 0, height - (yDelta * j)+i, xDelta * j, 0);
//}
//g.DrawRectangle(p, 1, i, 50, 50);
//g.DrawRectangle(p, 60, i, 50, 50);
//g.DrawRectangle(p, 120, i, 50, 50);
//g.DrawRectangle(p, 170, i, 50, 50);
//g.DrawRectangle(p, 220, i, 50, 50);
//g.DrawRectangle(p, 270, i, 50, 50);
//g.DrawRectangle(p, 320, i, 50, 50);
//g.DrawRectangle(p, 370, i, 50, 50);
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
//this.Invalidate();
// Draw();
}
private void Form1_Shown(object sender, EventArgs e)
{
//Draw();
}
private void Form1_Load(object sender, EventArgs e)
{
Draw();
this.Invalidate();
}
}
}