- Table of Contents
- Copyright
- About the Authors
- About the Contributors
- Acknowledgments
- Tell Us What You Think!
- Introduction
- How to Use This Book
- What You Need to Use This Book
- What's New in Visual C++ 6.0
- Contacting the Main Author
- Part I: Introduction
- Chapter 1. The Visual C++ 6.0 Environment
- Part II: MFC Programming
- Chapter 2. MFC Class Library Overview
- Chapter 3. MFC Message Handling Mechanism
- Chapter 4. The Document View Architecture
- Chapter 5. Creating and Using Dialog Boxes
- Handling Dialog Boxes in MFC
- Dialog Box Data Exchange and Validation
- Derived Control Classes in Dialog Boxes
- Modeless Dialog Boxes
- Summary
- Chapter 6. Working with Device Contexts and GDI Objects
- Chapter 7. Creating and Using Property Sheets
- Chapter 8. Working with the File System
- Chapter 9. Using Serialization with File and Archive Objects
- Part III: Internet Programming with MFC
- Chapter 10. MFC and the Internet Server API (ISAPI)
- Chapter 11. The WinInet API
- Chapter 12. MFC HTML Support
- Part IV: Advanced Programming Topics
- Chapter 13. Using the Standard C++ Library
- Chapter 14. Error Detection and Exception Handling Techniques
- Chapter 15. Debugging and Profiling Strategies
- Chapter 16. Multithreading
- Chapter 17. Using Scripting and Other Tools to Automate the Visual C++ IDE
- Part V: Database Programming
- Chapter 18. Creating Custom AppWizards
- Chapter 19. Database Overview
- Chapter 20. ODBC Programming
- Chapter 21. MFC Database Classes
- Chapter 22. Using OLE DB
- Chapter 23. Programming with ADO
- Part VI: MFC Support for COM and ActiveX
- Chapter 24. Overview of COM and Active Technologies
- Chapter 25. Active Documents
- Chapter 26. Active Containers
- Chapter 27. Active Servers
- Chapter 28. ActiveX Controls
- Part VII: Using the Active Template Library
- Chapter 29. ATL Architecture
- Chapter 30. Creating COM Objects Using ATL
- Chapter 31. Creating ActiveX Controls Using ATL
- Chapter 32. Using ATL to Create MTS and COM+ Components
- Part VIII: Finishing Touches
- Chapter 33. Adding Windows Help
- Part IX: Appendix
Derived Control Classes in Dialog Boxes
You can extend the functional ity of any of the standard control classes by deriving your own classes and then use these extended controls in your dialog box.
This technique can let you subtly (or drastically) modify the behavior of the standard Windows controls. Many third-party software vendors supply libraries full of these extended classes to greatly enhance the control capabilities.
Creating a Derived Control
You can use ClassWizard to create a new class derived from an existing MFC control class by clicking the Add Class button and selecting New to display the New Class dialog box, as shown in Figure 5.7. After entering a name for your new control class, you can set the base class to one of the existing MFC control classes.
Figure 5.7 Deriving your own control class.
After you click OK, a new control class appears in your ClassView. This new class just consists of constructor/destructor functions and a message map derived from the existing MFC class.
You don't have to use ClassWizard to generate this derived control class, but it certainly makes things easier, especially when you incorporate the new control in a dialog box, as you'll see later, in the section, "Using the Derived Control in a Dialog Box."
Instead of deriving your custom control from another MFC control class, you can derive it from CWnd directly and write a new control from scratch. This is a fairly laborious job, however, and you probably would find it more beneficial to create the control as an ActiveX control.
Customizing the Derived Control
You change or extend the default functionality of your new derived class by adding message-handler functions to intercept the Windows messages before they are passed to the base class.
You could create a custom Edit control that converts uppercase letters to lowercase letters, for example. You could add a handler to catch the WM_CHAR messages and change any uppercase characters to lowercase, like this:
void CCustomEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
if (nChar>='A' && nChar<='Z')
nChar+=32; // Make it lowercase
DefWindowProc(WM_CHAR,nChar,MAKELONG(nRepCnt,nFlags));
}
If you examine the source code for the MFC control base classes, you'll notice that most call a CWnd function called Default(). This function just calls the DefWindowProc() function passing the details of the last message sent to the window. The DefWindowProc() function then implements the default processing for the Windows message.
Instead of calling the base class CEdit::OnChar() function, the preceding example calls DefWindowProc(), directly passing the modified nChar variable. You'll notice that a corresponding ON_WM_CHAR message-handler macro was added to your derived control's message map, like this:
BEGIN_MESSAGE_MAP(CCustomEdit, CEdit)
//{{AFX_MSG_MAP(CCustomEdit)
ON_WM_CHAR()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
This macro is responsible for separating the nRepCnt and nFlags word values from the original LPARAM parameter sent in the WM_CHAR message. The MAKELONG macro merely recombines these values back into a single LPARAM parameter for the DefWindowProc() function.
You now have a simple customized CEdit-derived class that converts all uppercase characters to lowercase. Obviously, this is quite a simple customization, but by catching other Windows messages in this way, you can customize the standard controls beyond recognition.
Using the Derived Control in a Dialog Box
After you derive a custom control, you can use it in a dialog box as a mapped member variable (as you would any standard MFC control). If you used ClassWizard to create the derived control class, you'll find that your new class is available from the list of control variable types in the Add Member Variable dialog box, Figure 5.8 shows.
Figure 5.8 Mapping your derived class to a dialog box control.
After clicking OK to map the new member variable to your derived class, you'll notice that ClassWizard adds the new member variable to the dialog box's class definition as normal:
CCustomEdit m_ceditCustomEdit;
ClassWizard prompts you with a message box to remind you that you must manually add an #include for the custom control's class definition before the new member variable declaration. If your new derived class is defined in the CustomEdit.h module, for ex ample, you should add the #include before your custom dialog box definition:
#include "CustomEdit.h"
You now should find that when your new dialog box is displayed, the behavior of your new customized control is changed accordingly.
You may not always want to use (or be able to) ClassWizard to map your derived control class to a particular control. If not, you should manually add the member variable declaration for your derived class into the dialog box class definition. You then can call SubclassDlgItem() from OnInitDialog() to hook your derived control class's message map into the specific Windows control.
The term subclassing in this circumstance is different from the object-oriented subclass term and really means use this class to handle the Windows messages for this control. This subclassing normally is performed during the first pass of DoDataExchange() from inside a DDX_Control() routine. You must pass the control ID and a valid parent dialog box pointer to SubclassDlgItem().
To manually subclass the new custom edit box (m_ceditCustomEdit), for example, your OnInitDialog() function may look like this:
BOOL CCustomDlg::OnInitDialog()
{
CDialog::OnInitDialog();
m_ceditCustomEdit.SubclassDlgItem(IDC_CUSTOM_EDIT,this);
return TRUE;
}
If the subclassing succeeds, SubclassDlgItem() returns TRUE. If you already know the HWND handle of the control, you can call SubclassWindow() from the dialog box instead, passing the control's window handle. SubclassWindow() also returns TRUE if the subclassing was successful.
You can add an override for the PreSubclassWindow() virtual function in your derived control class. Your PreSubclassWindow() override is called just before the control's messages are hooked into your derived class's message map. This lets you perform dynamic changes to the subclassing procedure or just some last-minute initialization of your new control-handler class.
You can call UnsubclassWindow() to make the control revert to using the original default (CWnd) handler object.
Modeless Dialog Boxes | Next Section

Account Sign In
View your cart