Introduction
I am quite new to VC++, and I found MFC support of drawing is quite easy to use at first. Just a few lines of code, and you can draw whatever basic shapes on the client area. But when it comes to flicker-free, I had a tough time to dig out the working sequence. Thanks to all CPians, especially Chris Losinger, Joaquín M López Muñoz, Tim Smith, Shog, Nish, Ernest Laurentin, Kemal OZLU, Ravi Bhavnani, vaithsr, for helping me out in my painful days. And I'd like to share what I have learnt so far with other newbies.
Three Messages You Need to Handle
- First of all, in order to get flicker-free drawing, you need to draw everything on a memory DC, then
BitBlt
it to the real DC. This is called double buffering, and it is addressed in many books and articles. - Secondly, you need to overwrite
OnEraseBkgnd
to really get rid of flickering. - Last but not least, you still want the background to be erased when
WM_ERASEBKGND
is sent by other event than your InvalidateRect( &rect_yourDrawArea )
. So you need to overwrite the handler of WM_NCPAINT
, to clear the flag of bypassing OnEraseBkgnd
, so that the background will be painted properly.
Some Tricks
Some tricks to achieve flicker-free while avoiding side effects are:
- When drawing your picture on the memory DC, you can assume a rectangle, whose left top corner is at (0,0). Then when you
BitBlt
it to the real DC, you can specify the real left top corner by x and y argument. In this way, you can move your drawing area easily in the future, since the only place needs to be changed is BitBlt's
x and y argument. - Whenever you are updating your drawing by calling
InvalidateRect(&rect_yourDrawArea)
, set the flag so that OnEraseBkgnd
will be bypassed. And at the end of OnPaint
, clear the flag, so that the background will be erased in other cases. - When the frame is resized, or scroll bar is dragged, or window is reactivated,
WM_NCPAINT
will always be sent to your program. This is the case that you would clear your EraseBkgnd
flag, so that the background will be erased, instead of giving you a see-through client area.
End
The detail is in the source code. Since it is quite self-explanatory, I won't waste my breath here. I hope you find this article useful. Thanks for reading.