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 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.
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.