Exercises
Exercise 25.1: What happens if you don't clear the cMemoryDC?
Comment out the line _pMemDC->clear(clearrect); from the cGraphicsMFC: :clear(const CRect &clearrect) code in graphicsmfc.h and see what happens. Drag a corner of the window to resize it. Can you figure out what's going on?
Exercise 25.2: Invalidate and flicker
Change the CPopView:: OnEraseBkgnd
method to call the default CView
method. Look at the flicker.
Exercise 25.3: Writing your own memory CDC code
Occasionally students rebel at using the cMemoryDC
class. 'I want to use my own code; if I have to do this at our job, I want to be able to do it myself.' But do keep in mind that the MemoryDC.* files (and all the other software in this book) are well-tested public domain freeware that you are explicitly authorized to reuse in any way, shape or form, with no acknowledgement necessary. But even so, there are individualistic souls who want to be sure they can do it unaided. And who can blame them? There is a sense, after all, in which you never completely understand code unless you have written it yourself, and then corrected your inevitable errors in the compiler, and then maybe even stepped through the code in the debugger. So this exercise asks you to write a screen-persistent version of Pop in which you don't use our cMemoryDC
class. Here's how.
Put a static CDC _memCDC variable into CPopView
followed by a CBitmap _memBitmap and a couple of int _memcx, _memcy. We can live without the CBrush
variable. Imitate the cMemoryDC
constructor code inside the CPopView
constructor. The initialization is the trickiest thing about a cMemoryDC, so this will be the hardest part of your work. Do it like this after using the GetSystemMetrics
to set _memcx and _memcy to match the screen measurements.
CDC cDC_display;
CBitmap pBitmap_old;
cDC_display.CreateDC("DISPLAY", NULL, NULL, NULL);
_memDC.CreateCompatibleDC(&cDC_display);
_memBitmap.CreateCompatibleBitmap(&cDC_display, _memcx, _memcy));
pBitmap_old = _memDC.SelectObject(&_memBitmap);
pBitmap_old->DeleteObject();
Copy this very exactly; resist the temptation to simplify things by leaving out the seemingly extra steps involving the temporary cDC_display variable. These steps are necessary. Now go to CPopView::OnDraw. Imitate the cMemoryDC clear, using PatBlt
with the WHITENESS
as the last argument. And use BitBlt
to imitate the copyTo
code.
You don't need to change the CPopView
destructor, because the destructor will automatically call destructors on the CPopView
data fields in the order they appear, which means _memDC.DeleteDC() will happen, and then _memBitmap.DeleteObject(). Of course if you'd created similar objects on a temporary basis somewhere, you might want to kill them off yourself, just to be sure that the CDC
dies before the CBitmap
(because if the CBitmap
were to die first the CDC
would have a cranky ant-fit!).
And don't forget to override CView::OnEraseBkgnd(CDC *pDC)
to do nothing at all but return TRUE;. If you forget this, your screen can still flicker, as the default behavior of any call to Invalidate()
is to first call OnEraseBkgnd, and that function's default behavior is to erase the view with the background brush.
|