Tuesday, 25 September 2007

Double Buffer Graphics in C# + GDI

Hi all,

recently, I was building a test application that needed some basic graphic drawing to show some physical values in real time. I wanted to do it simple and fast, so I didn´t want to deal with all the DirectX stuff (devices, resources, etc). That´s why I went into the simple Windows Forms GDI solution.

I wrote the program and run fine but, as expected, flickering appeared all around when animation came into scene. This is something that was obviously going to happen, so I decided to remember the old times and search for a double buffer drawing solution.

It is very simple to fix this behavior, just draw everything appart, to a different surface, and then dump the whole picture to the screen. Among the different solutions I found over the internet, one of the best and most simple is the code included below (NT Almond. 2003):

Just include it in a class and perform all the rendering through its Graphics object.

et voilá!



using System;
using System.Drawing;

namespace GDIDB
{
///


/// Class to implement Double Buffering
/// NT Almond
/// 24 July 2003
///

///
public class DBGraphics
{
private Graphics graphics;
private Bitmap memoryBitmap;
private int width;
private int height;

///
/// Default constructor
///

public DBGraphics()
{
width = 0;
height = 0;
}

///
/// Creates double buffer object
///

/// Window forms Graphics Object
/// width of paint area
/// height of paint area
/// true/false if double buffer is created
public bool CreateDoubleBuffer( Graphics g, int width, int height )
{
if ( width <= 0 height <= 0 ) return false; if ( width != this.width height != this.height memoryBitmap == null graphics == null ) { if ( memoryBitmap != null ) { memoryBitmap.Dispose(); memoryBitmap = null; } if ( graphics != null ) { graphics.Dispose(); graphics = null; } this.width = width; this.height = height; memoryBitmap = new Bitmap( width, height ); graphics = Graphics.FromImage( memoryBitmap ); } return true; } ///
/// Renders the double buffer to the screen
///

/// Window forms Graphics Object
public void Render( Graphics g )
{
if ( memoryBitmap != null )
g.DrawImage( memoryBitmap, new Rectangle( 0, 0, width, height ), 0, 0, width, height, GraphicsUnit.Pixel );
}

///
///
///

/// true if double buffering can be achieved
public bool CanDoubleBuffer()
{
return graphics != null;
}

///
/// Accessor for memory graphics object
///

public Graphics g
{
get
{
return graphics;
}
}
}
}

Code found here, among other sites:
http://www.koders.com/csharp/fid8D1742BF7E30AEB520A0548A95C99DD48CDAA645.aspx

2 comments:

Augusto Ruiz said...

Hmmm... Did you try to do something like:

public class DoubleBufferedPanel : Panel
{
public DoubleBufferredPanel()
{
this.DoubleBuffered = true;
}
}

And that's it...

Great blog!

Enhorabuena!

Iñaki Ayucar said...

Man! This is one of that situations where you feel soooooo stupid...

Well, muchas gracias, I´m posting about this...