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!