在图形图像显示过程中,计算机从显示缓冲区取数据然后显示,很多图形的操作都很复杂需要大量的计算,很难访问一次显示缓冲区就能写入待显示的完整图形数据,通常需要多次访问显示缓冲区,每次访问时写入最新计算的图形数据。而这样造成的后果是一个需要复杂计算的图形,你看到的效果可能是一部分一部分地显示出来的,造成很大的闪烁不连贯。而使用双缓冲,可以使你先将计算的中间结果存放在另一个缓冲区中,但全部的计算结束,该缓冲区已经存储了完整的图形之后,再将该缓冲区的图形数据一次性复制到显示缓冲区。 使用双缓冲是为了防止显示图形时的闪烁延迟等不良体验。
public void Show(System.Windows.Forms.Control control) { Graphics gc = control.CreateGraphics(); // 创建缓冲图形上下文 (类似 Win32 中的CreateCompatibleDC) BufferedGraphicsContext dc = new BufferedGraphicsContext(); // 创建指定大小缓冲区 (类似 Win32 中的 CreateCompatibleBitmap) BufferedGraphics backBuffer = dc.Allocate(gc, new Rectangle(new Point(0, 0), control.Size)); gc = backBuffer.Graphics; // 获取缓冲区画布 /* 像使用一般的 Graphics 一样绘图 */ Pen pen = new Pen(Color.Gray); foreach (Step s in m_steps) { gc.DrawLine(pen, s.Start, s.End); } // 将双缓冲区中的图形渲染到指定画布上 (类似 Win32 中的)BitBlt backBuffer.Render(control.CreateGraphics()); }利用默认的双缓冲 在应用程序中使用双缓冲的最简便的方法是使用 .NET Framework 为窗体和控件提供的默认双缓冲。通过将 DoubleBuffered 属性设置为 true。
this.DoubleBuffered=true;使用 SetStyle 方法可以为 Windows 窗体和所创作的 Windows 控件启用默认双缓冲,在窗体或者控件的构造函数中添加如下代码即可:
SetStyle(ControlStyles.ResizeRedraw,true); SetStyle(ControlStyles.OptimizedDoubleBuffer,true); SetStyle(ControlStyles.AllPaintingInWmPaint,true);手动管理双缓冲
//1、在内存中建立一块“虚拟画布” Bitmap bmp = new Bitmap(200,200); //2、获取这块内存画布的Graphics引用 Graphics bufferGraphics = Graphics.FromImage(bmp); //3、在这块内存画布上绘图 bufferGraphics.Clear(this.BackColor); bufferGraphics.DrawRectangle(Pens.Black,0,0,bmp.Width -1,bmp.Height -1); bufferGraphics.DrawEllipse(Pens.Red,10,10,100,50); bufferGraphics.DrawLine(Pens.Green,10,100,100,200); //4、将内存画布画到窗口中 using(Graphics g = e.Graphics) { g.DrawImage(bmp, 10, 10); } //5. 释放资源 bmp.Dispose(); bufferGraphics.Dispose();对于更高级的双缓存情形,可以使用 .NET Framework 类实现自己的双缓存逻辑。负责单独分配和管理图形缓冲区的类是BufferedGraphicsContext 类。每个应用程序都有自己的默认BufferedGraphicsContext 来管理此应用程序的所有默认双缓冲。提供调用Current 可以检索对此实例的引用。通过调用Allocate 方法可以创建与屏幕上的绘图图面关联的BufferedGraphics 类的实例。此方法创建一个与特定呈现图面(如窗体或控件)关联的BufferedGraphics 实例。创建 BufferedGraphics 实例后,可以将图形绘制到由该实例的Graphics 属性表示的缓冲区。 执行所有图形操作后,可通过调用Render 方法将缓冲区的内容复制到屏幕上。
BufferedGraphicsContext currentContext = BufferedGraphicsManager.Current; BufferedGraphics myBuffer = currentContext.Allocate(e.Graphics,e.ClipRectangle); Graphics g = myBuffer.Graphics; g.Clear(this.BackColor); g.DrawRectangle(Pens.Black, 10, 10, 200, 200); g.DrawEllipse(Pens.Red, 10, 10, 100, 50); g.DrawLine(Pens.Green, 10, 100, 100, 200); myBuffer.Render(e.Graphics); //呈现图像至关联的Graphics myBuffer.Dispose(); g.Dispose();