Introduction
I present here two classes which can be used for:
- Flicker free drawing
- Buffering drawing, for example, the background
The advantages of these two classes are:
- There are multiple buffers possible for several purposes. Unlike the code of several other
CMemDC
classes at other sites, there is a distinction between the buffers and the code which is used to access these buffers. - When we use
GetSafeCDC()
for all drawing operations, we never get a problem during printing or previewing because we simply bypass in this case, the pointer to CDC
which is given to OnDraw
. This simple method will never fail. - 16 and 32 bit compatible
- The buffers can be allocated once. If we have a large screen, we do not allocate a new big bitmap for each
OnDraw
event. If only a part of the screen needs to be redrawn, it is still possible to declare and use a temporary buffer. - If the buffer allocation fails due to limited system resources, all drawings will be done unbuffered
- If we have drawing operations which do last a long time, it is possible to show the user at regular time intervals (for example, each second) intermediate results. The implementation for this is simple: Just call
CopyToScreen(1000)
during these operations. This will copy all seconds the current content of the background buffer to the screen.
Note: During preview, the CDC
supplied to OnDraw
is internally a CPreviewDC
. This is an internal MFC class. This class does have some functions which are overloaded and not virtual. So when I used other CMemDCs
implementation, I had errors during printing and previewing because those CMemDC
did not call the functions of CPreviewDC
but called the corresponding functions of CDC
.
Using the Classes
There are a lot of possibilities how to use this classes. Look at the declarations in MemDc.h.
An example of usage, explained step by step:
- Define one or more
CBufferMemDC
in the header of your CView
derived class. In my case, I have defined two buffers. One for the general background which is static
and one for the information which I had to redraw more often on the background. It is also possible to allocate an additional buffer for the final result of the drawing to buffer the total window client area for the case where the user does switch between the applications for example with Alt-Tab.
Example:
CBufferMemDC m_BufferBackground;
CBufferMemDC m_BufferFlickerFreeDrawing;
- Add the following function to your
CView
derived class:
static void CalcSizeTotalAreaWnd( CDC* pDC, const YourView* pView,
CRect& totalAreaWnd ) {
if ( pDC->IsPrinting() ){
pDC->GetClipBox(&totalAreaWnd);
} else {
pView->GetClientRect( totalAreaWnd );
}
}
- Put the implementation of your
OnDraw
function in another function. For example:
OnRedraw( CDC* pDC).
- Modify your
OnDraw
function:
void MyView::OnDraw( CDC* pDC )
{
CRect totalAreaWnd;
CalcSizeTotalAreaWnd( pDC, this, totalAreaWnd );
CMemDC memDC( pDC, totalAreaWnd, totalAreaWnd,
&m_BufferBackground );
if ( pDC->IsPrinting() || m_BufferBackground.IsDirty()){
OnRedraw( memDC.GetSafeCDC() );
memDC.CopyToScreen(0);
}
}
My own implementation is more complex because I had to buffer not only the background but also several intermediate states during drawing. But this was no problem with these two classes because these two classes do solve the two main parts of such problems: How to handle a buffer and how to do the buffering.
At the end, I have to say that I was astonished at how small the final code was.
License
This article has no explicit license attached to it, but may contain usage terms in the article text or the download files themselves. If in doubt, please contact the author via the discussion board below.
A list of licenses authors might use can be found here.