WynApse Home Page
Home    Blog    About    Contact       
Latest Article:


My Tags:
My Sponsors:







Lifetime Member:

web tracker

Custom MFC Base Classes in C++


Go to Page 2

Testing the base class

To prove the CCustomDialog class is functional, bring up the class wizard, select the CCustomDialog class, and add a member function for the WM_INITDIALOG message. Take the default, and then press "Edit Code". In place of the "TODO..." line, insert something like:

AfxMessageBox(“CCustomDialog OnInitDialog”, MB_OK);

This won't do anything unless we also modify our two CCustomDialog-based classes. In CCustomMFCBaseClassesDlg.cpp, modify the base-class call in OnInitDialog():

CCustomDialog::OnInitDialog();

The CAbout class does not currently handle the WM_INITDIALOG method. In a manner similar to midifying the CCustomDialog, add a WM_INITDIALOG handler to the CAbout class. Since this code is added after our base class substitution, Class Wizard will automatically be aware of CCustomDialog, and no changes to that part of the code are required.

Build and run to text. Because of the AfxMessageBox placement, the message appears prior to either dialog appearing. This is a good test of the execution of our base class.

At this point the hard work is finished. Any functionality you would like to have appear in every dialog class can now be added to a single class, and will immediately work in every dialog in your project, such as skinned borders or non-client buttons.

Drawing the Background

In 2006, drawing a bitmapped background into a dialog is not a huge deal, but there may still be someone out there wondering how to accomplish this. In 1999, this was a reasonably hot topic, and the ability to push the same look-and-feel into all dialogs with one change is still very cool.

First we need to get our bitmap into the project.

Begin with the BG.BMP file in the ‘res’ directory of your project. In Visual Studio, from the menu select Insert->Resource>Bitmap->Import. Select BG.BMP in the project res directory and press Import. This will add the resource with the ID IDB_BITMAP1. Double-click the right-hand client area of Visual Studio, but outside the bitmap area. If you click on the bitmap you will modify the image. The double-click will bring up properties of the bitmap. I changed the ID to be IDB_BG.

Once more, invoke Class Wizard. This may be a good time to mention that I make sure the Class Wizard toolbar item is readily available. For reference, the image is in the ‘View’ category in Tools->Customize.

Inside Class Wizard, make sure the Message Map tab is selected, and select CustomDialog as the Class. Under Messages, select WM_PAINT, double-click, and accept the default OnPaint member function. Select Edit code to bring up the dialog code. Explaining the code that effects the dialog painting is probably more than needs to be included here. Please email me if you would like to see that code explained.

Essentially, the bitmap is loaded from its bound location in the application’s resources, and selected into a memory device context.

The memory device context is then stretched to fit into our dialog’s client area, causing either an expand or contract to take place. A few housekeeping chores also take place, but essentially this is it. The interesting thing to note here is that the device context manipulated is that of each of our original dialogs, all done by that code in our new base class.

Replace the Wizard-created “TODO …” line with the following:

CBitmap bmDlg;
bmDlg.LoadBitmap(IDB_DJ);
CDC dcMemory;
dcMemory.CreateCompatibleDC(&dc);
CBitmap *pBitmapOld = dcMemory.SelectObject(&bmDlg);

CRect RectDlg;
GetWindowRect(&RectDlg);
BITMAP bm;
bmDlg.GetBitmap(&bm);
dc.StretchBlt(0, 0, RectDlg.Width(), RectDlg.Height(),
   &dcMemory, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
dcMemory.SelectObject(pBitmapOld);

Build and run the application to check your results.

You will notice that the About dialog box picked up the background while the main dialog did not. A little investigation will show why. If you open the class view of Visual Studio, you’ll notice that CAbout does not handle the OnPaint method. Therefore that task is passed on to the base class, CCustomDialog, and we just wrote the code to do that task.

Why, then, does CCustomMFCBaseClassesDlg, which does handle OnPaint, not work as planned? First, CCustomMFCBaseClassesDlg handles OnPaint for displaying an icon when minimized. If we look at the OnPaint() code, we find an else clause that calls the base class. In most cases, calling CDialog methods would work just fine, but in this particular case, we have our own OnPaint(), and we should be calling CCustomDialog::OnPaint() instead.

Make this change, and before building, comment out our now-unnecessary AfxMessageBox line in CCustomDialog::OnInitDialog().

If all goes well, you should be seeing bitmapped backgrounds on both dialogs.

Go to Page 2



Microsoft MVP

Member of WPF and Silverlight Insiders

Creative Commons License

Copyright © 2006-2012, WynApse