Double Buffer
Double Buffer
As much as we would like it not to be the case, graphics can be slow enough to
watch as the screen is refreshed. Our eyes, sensitive to movement and particularly
to edge detection so that we don't walk off of cliffs or run into trees, often pick up
the redraw cycle of computer graphics which, at best is mildly annoying or at worst
can cause headaches, eyestrain and in susceptible people, even fits.
Windows Forms provides an automatic method of double buffering that can be used
by simply setting a few styles in your form or control. For most applications, this is
enough but in certain cases, more control over the process is desirable so manually
double buffering a control is also possible.
First, take a look at the standard and built in method of double buffering. This is
accomplished by setting the styles:
z ControlStyles.AllPaintingInWmPaint
z ControlStyles.UserPaint
z ControlStyles.DoubleBuffer
When these are all set true, the draw process is modified so that instead of your
Paint handler being passed a Graphics for the screen, it is passed a Graphics for an
in-memory bitmap. When you draw to this Graphics object, you are drawing on an
invisible image. At the end of the draw cycle, this bitmap is copied to the main
window automatically and the actual pixels you see are all changed in a fraction of
a second instead of one at a time as the draw cycle progresses.
To set up automatic double buffering for a Form, you would use the following line of
code in the constructor, after the InitializeComponent method call.
C#
this.SetStyle(
ControlStyles.AllPaintingInWmPaint |
ControlStyles.UserPaint |
ControlStyles.DoubleBuffer,true);
VB
me.SetStyle(
ControlStyles.AllPaintingInWmPaint OR _
ControlStyles.UserPaint OR _
ControlStyles.DoubleBuffer,true)
Manual double buffering can be useful if you don't want the system so make
assumptions for you such as whether the background is opaque or transparent or
perhaps if you want to create a more complex buffering system. There are a few
simple rules that you need to follow to get manual double buffering right.
First, don’t create a new back-buffer every draw cycle. Only create or destroy the
http://www.bobpowell.net/doublebuffer.htm 25/03/2009
Double buffering Windows Forms Page 2 of 7
bitmap when the window's client size changes. Second, only create a bitmap of the
size you need. Clearing pixels takes time and so if there are more pixels than you
need, you're just wasting processor cycles. Lastly, use the simplest draw method to
copy the bitmap to the screen. DrawImageUnscaled is the way to go here.
Before the big demo, listing 1 shows all the salient points of a manual double
buffered application.
private Bitmap _backBuffer;
g.Dispose();
e.Graphics.DrawImageUnscaled(_backBuffer,0,0);
VB
g.Dispose()
http://www.bobpowell.net/doublebuffer.htm 25/03/2009
Double buffering Windows Forms Page 3 of 7
C#
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
namespace DoubleBuffer
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
float _angle;
bool _doBuffer;
public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
//
// TODO: Add any constructor code after InitializeComponent call
//
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
}
#endregion
/// <summary>
/// The main entry point for the application.
/// </summary>
http://www.bobpowell.net/doublebuffer.htm 25/03/2009
Double buffering Windows Forms Page 4 of 7
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
Graphics g=null;
if(_doBuffer)
g=Graphics.FromImage(_backBuffer);
else
g=e.Graphics;
g.Clear(Color.White);
g.SmoothingMode=SmoothingMode.AntiAlias;
mx=new Matrix();
mx.Rotate(-_angle,MatrixOrder.Append);
mx.Translate(this.ClientSize.Width/2,this.ClientSize.Height/2,MatrixOrder.Append);
g.Transform=mx;
g.FillRectangle(Brushes.Green,-75,-75,149,149);
mx=new Matrix();
mx.Rotate(_angle*2,MatrixOrder.Append);
mx.Translate(this.ClientSize.Width/2,this.ClientSize.Height/2,MatrixOrder.Append);
g.Transform=mx;
g.FillRectangle(Brushes.Blue,-50,-50,100,100);
if(_doBuffer)
{
g.Dispose();
e.Graphics.DrawImageUnscaled(_backBuffer,0,0);
}
VB
Imports System
Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Collections
Imports System.ComponentModel
Imports System.Windows.Forms
http://www.bobpowell.net/doublebuffer.htm 25/03/2009
Double buffering Windows Forms Page 5 of 7
Imports System.Data
Namespace DoubleBuffer
'/ <summary>
'/ Summary description for Form1.
'/ </summary>
'
' TODO: Add any constructor code after InitializeComponent call
'
'/ <summary>
'/ Clean up any resources being used.
'/ </summary>
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub 'Dispose
'/ <summary>
'/ Required method for Designer support - do not modify
'/ the contents of this method with the code editor.
'/ </summary>
Private Sub InitializeComponent()
Me.components = New System.ComponentModel.Container
Me.timer1 = New System.Windows.Forms.Timer(Me.components)
Me.checkBox1 = New System.Windows.Forms.CheckBox
Me.SuspendLayout()
'
' timer1
'
Me.timer1.Enabled = True
'
' checkBox1
'
Me.checkBox1.Location = New System.Drawing.Point(8, 8)
Me.checkBox1.Name = "checkBox1"
Me.checkBox1.TabIndex = 0
Me.checkBox1.Text = "Double Buffer"
'
' Form1
'
Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
Me.ClientSize = New System.Drawing.Size(292, 273)
Me.Controls.Add(checkBox1)
Me.Name = "Form1"
Me.Text = "Form1"
Me.ResumeLayout(False)
End Sub 'InitializeComponent
#End Region
'/ <summary>
'/ The main entry point for the application.
http://www.bobpowell.net/doublebuffer.htm 25/03/2009
Double buffering Windows Forms Page 6 of 7
'/ </summary>
<STAThread()> _
Shared Sub Main()
Application.Run(New Form1)
End Sub 'Main
g.SmoothingMode = SmoothingMode.AntiAlias
mx = New Matrix
mx.Rotate(-_angle, MatrixOrder.Append)
mx.Translate(Me.ClientSize.Width / 2, Me.ClientSize.Height / 2,
MatrixOrder.Append)
g.Transform = mx
g.FillRectangle(Brushes.Green, -75, -75, 149, 149)
mx = New Matrix
mx.Rotate(_angle * 2, MatrixOrder.Append)
mx.Translate(Me.ClientSize.Width / 2, Me.ClientSize.Height / 2,
MatrixOrder.Append)
g.Transform = mx
g.FillRectangle(Brushes.Blue, -50, -50, 100, 100)
If _doBuffer Then
g.Dispose()
http://www.bobpowell.net/doublebuffer.htm 25/03/2009
Double buffering Windows Forms Page 7 of 7
Excellent!
Good
Average
Poor
Awful
Vote!
view results
powered by blogpoll
http://www.bobpowell.net/doublebuffer.htm 25/03/2009