Introduction
This article explains how my class CDXSurfaceMgr
can be used to
facilitate Double Buffered drawing/graphics.
Double Buffered Drawing
Normally when drawing using the GDI you do all your painting straight into the HDC
that's provided by either BeginPaint
or a CDC
(if you are using
MFC). Iif you draw a
line it immediately appears on the surface of the window you are drawing on. If you
draw a lot of graphic items the screen is updated with each item and this can result in flicker
or stuttering as the surface is filled with the drawing. Double Buffering
can be used to create smooth updates, you build a "frame" of graphics in a non visible
place first then copy the whole thing onto the main windows surface.
There a lots of ways to implement double buffering, one way is to create a
compatible HDC
in memory somewhere and draw into that then Blit (copy) that memory into the visible
windows HDC
. My approach uses a subset of DirectX
called DirectDraw
which can be used to draw 2d Graphics. CDXSurfaceMgr
is written using the
DirectDraw interfaces supplied in VC6 (ddraw.h/lib) and should work on
95/98/Me/2k/XP and NT 4.0
(sp3 - I think).
Using CDXSurfaceMgr
Create an instance of CDXSurfaceMgr
#include "DXSurfaceMgr.h"
...
...
CDXSurfaceManager_NBP dxMgr_;
Initialise the instance like so
int CMfcdxView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
if(!dxMgr_.Initialise(m_hWnd)) return -1;
return 0;
}
This should be done just once, the parameter to the
Initialise
method is the Handle
to the window you want to draw on.
Then when handling the
WM_PAINT
message (the place you would normally do the drawing)
call the
BeginPaint
Method
void CMfcdxView::OnDraw(CDC* pDC)
{
CMfcdxDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
HDC& hdc = dxMgr_.BeginPaint(GetSysColor(COLOR_3DFACE));
if(NULL !=hdc)
{
....
The parameter to BeginPaint
is a COLORREF
that BeginPaint
will use to fill the
background with. BeginPaint
returns an HDC
that that you can then use
to draw things with, either via the standard GDI API;
::SetBkMode(hdc,TRANSPARENT);
::TextOut(hdc,10,10,"Please don't call me reg its not my name", 40);
Or if you are using MFC;
CDC* cdc = CDC::FromHandle(hdc);
cdc->SetBkMode(TRANSPARENT);
cdc->(10,10, CString("All aboard Brendas iron sledge"));
Note all the usual GDI rules apply - if you select a brush remember to reselect the
old one etc.
When you have finished drawing, call the EndPaint
method like so;
dxMgr_.EndPaint();
This will "flip" your drawing onto the main windows surface. and the drawing will
instantaneously appear.
What CDXSurfaceMgr
does
CDXSurfaceMgr
creates a primary surface - one that is visible - and a secondary off screen
surface that is the same size as the primary one but invisible. When you call BeginPaint
an HDC
attached to the secondary surface is returned; you do all your drawing
into this; then EndPaint
Blits(copies) the whole of the secondary surface onto the
primary one and it appears on the window. If you have a capable graphics adapter on your
machine then the Blit is very very fast, if you don't then the operation is obviously not
as fast, but still very functional.
Demos
There are three demos included one that uses WFC and draws rectangles and ellipses moving up
and down the screen, one that uses MFC, and draws a few lines and a bit of text, and one that does
exactly the same again but is just a Win32 program.