hen working with the Microsoft Foundation Class Library (MFC
), I occasionally need dialog boxes that look and act similarly but have small differencesdialog boxes that do different things with the same data. While writing a database application, for instance, I needed one dialog screen for users to add records and another for them to edit records. Both screens would have the same fields and they basically would look the same, but the add screen would have something like "Add Record" in the title bar, while the "edit" screen would have "Modify Record" in the title bar. The add screen would always come up blank, whereas the edit screen would always contain record data.
As a Visual C++ developer, the alternatives available to me were not very appealing:
- Create separate dialog boxes with separate CDialog-type classes for each.
- Create one dialog box with one CDialog class, but set up switches in the code to turn on different modes so the dialog can change its behavior and appearance accordingly.
|Figure 1. The Main Dialog: The user gets to the custom screens from here. |
If you use only the tools that Visual C++ 6
gives you, you'll feel forced to take one of these approaches. With number 1, you duplicate code across the different dialog boxes, since each one is similar to the others. For number 2, you have to add many conditional statements to your event handlers, so you can switch between different modes. Both of these approaches make code maintenance difficult.
I have developed a better design scheme for these situations, which I will present in this article. I have included the code for a dialog-based application that shows this design at its bare minimum. Some of the interface functions are included, but are stubbed out to demonstrate the design structure. Some of it is not needed by the sample app, however, in normal circumstances these functions would be used.
|Figure 2. The Common Dialog Resource: This is the dialog that will be customized to appear as 3 different dialog screens. The controls will be made visible/invisible or enabled/disabled as appropriate for the function the user selects.|
The main dialog in my application, which the user sees first, gives three options: Enter Text, Edit Text, and View Text (Figure 1
). Each one activates a customized dialog. I created these dialog screens using what I call a common dialog box. The common dialog box for this app, which I've defined as one dialog box resource, contains an edit control (CEdit
) and three buttons (Figure 2
). I use C++ polymorphism
the code that modifies the common dialog for each custom screen.
The View Text customized screen displays the same Print button that is in the common dialog box, and it is the only screen that does. It allows the user to "print" what they are viewing (it actually just displays a message box for the sake of demonstration). I set the Print button's "Visible" property to false in the resource editor, since it only shows up on the View Text screen.
|Figure 3. The Class Hierarchy: I used Class Wizard to generate CTextDlg from the common dialog resource, and then converted it to an abstract base class.|
The program itself merely saves whatever is typed, allows the user to edit the text, and displays the text. Depending on which function the user selects from the main dialog, the custom screens display the common dialog with some modifications to its appearance and functionality.
How Does It Work?
In general, the design I present holds to a basic object-oriented design precept: put the common functionality in the base class, and put any code that specifically applies to a custom screen in the corresponding derived class. Figure 3 shows the class diagram for the program.