Flicker free drawing (2)

This class was contributed by Andreas Leitner.

This is a small class that makes it easy to create windows that are
updated flicker-free. Once I had to code a window that displayed “hard
to calculate” data. Since I needed to update the contents in constant time
(say every second) I got this ugly flickering on my machine.

There is an article dealing with the same problem on this site (Flicker
free drawing using memory DC by  Keith Rule
). The main difference
between our approaches is that Keith extends the class CDC and I extended
CWnd. I think both versions have got advantages and disadvantages. I
will try to point out the difference at the end of this article.

What I needed was a window that displayed its contents without flickering.
I archieve the flicker free mode with a well known trick: First paint everything
on a bitmap, then copy the bitmap into the the window. Since this aproach
is a bit slower than the common way, I decided that the end-user may decide
wether to use the fast mode (in case that his machine is good enough that
even this mode doesn’t flicker), or the flicker-free mode.

The new class is called CadvWnd (based
on CWnd):

The first 2 attributes that came on my mind were:

void SetFlickerFree(BOOL bFlickerFree);
BOOL IsFlickerFree();

I think it is rather easy to guess what those functions should do. What
I needed further was a sort of OnPaint function.
But since I will need this function-name for internal use I took an other
function (in fact two again to definitly force a difference between foreground
and background).

 virtual void InternalRedrawFG(CDC* pDC, CRect rcPaint);
 virtual void InternalRedrawBG(CDC* pDC, CRect rcPaint);

InternalRedrawFG should be overridded for
foreground drawing and InternalRedrawBG for
the background. Once the bitmap is painted it will be copied into the window
every time it needs to be updated. Of course the window checks messages
like WM_SIZE and recreates and repaints the bitmap. But how does the client
tell the window that the contents has changes and the bitmap needs to be
repainted or even recreated?

void ReCreateBitmap();
void SetContentsChanged(BOOL yes = TRUE);
BOOL IsContentsChanged();

ReCreateBitmap is the direct way to recreate
the bitmap (Mabe you as a client of the class will never need to call this
one:). More often you will have to call SetContentsChanged(TRUE).
When you do this, the next time the window will be repainted, the bitmap
also will be. Just call this function if the data changes on which the
window contents is based.

This class has even got a few extra features. I thought it is often
the case that you need a special background color so I made also this available
easy (of course you can add a mode for a background picture too). By now
there are two background modes: BM_DEF_WND_COL
and BM_CUST_COL. If you select SetBackgroundMode(
0, BM_DEF_WND_COL )
the window will behave like default, but if
you call SetBackgroundMode( RGB(255,0,0), BM_CUST_COL
)
the background will be painted red. Here come the function declarations:

const int GetBackgroundMode();
void SetBackgroundMode(COLORREF Color, int Mode = BM_CUST_COL); // To set the std mode just set col black and change the mode value 
COLORREF GetBackgroundColor();


 

 There is also a nice new function that you should override in
your derived class if you have child windows in your window.

virtual BOOL CreateChildren();

This function will be called in the right moment regardless if you create
this window through subclassing (often used in dialogs) or through a “create”
call (often used if you make it a child of another CWnd
(derived) class).

 


What do you need to derive a class from CadvWnd?


Be sure to include the header of CadvWnd in
your new class and derive it as public from it. A minimal implementation
just needs to override InternalRedrawFG as
shown in the following example.

#include "advWnd.h"
class CMyWnd : public CadcWnd
{
    public:
    virtual void InternalRedrawFG(CDC* pDC, CRect rcPaint)
    {
        pDC->TextOut( 10, 10, "Nonsense rulez ?!?");
    }
};


But what is the difference between CadvWnd and
CMemDC (by Keith Rule)?


As I mentioned at the begining Keith Rule deals also with the “flickering”
topic in his artice called “Flicker free drawing using memory DC“.
The main advantage of CMemDC in my
opinion is that you can use it everytime it comes to painting. CadvWnd
will cause you some problems using a CView derived
class, because here you have to override OnDraw to
change the drawing behavior of your window. I think one would have
to derive CView from CadvWnd
to solve this, but (to be honest) I never tried. Therefore the advantage
of CadvWnd is that you just override InternalRedrawFG
and then can easiely switch between fast and flickering mode. (Which
is sure a nice option in the main settings dialog). You can use InternalRedrawFG
just like OnPaint without any difference. Also in some cases CadvWnd
is faster than the pure CMemDC implementation,
because CadvWnd only recreates the offscreen
bitmap when you force it too (via SetContentsChanged,
or ReCreateBitmap). This is an important issue
if you need a long time to caclulate the image. Plus CadvWnd
offers a few other things that make life easier like the unified creation
method with CreateChildren and the additional
virtual function for background painting (inclusiv the extra background
mode with a predefined color).

Finaly here is the source. I used this class
a few times and saw no remaining bugs by now, if you see some (: please
mail me. Have fun!

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read