Click here to Skip to main content
15,881,836 members
Articles / Desktop Programming / MFC
Article

A class for child dialogs

Rate me:
Please Sign up or sign in to vote.
4.92/5 (60 votes)
3 Nov 20037 min read 269.6K   5.1K   98   84
How to put a child dialog in a dialog box

Introduction

In an earlier article, I showed how interacting controls in a dialog box can be encapsulated in a custom control that handles all the interactions between the controls. An even better way to handle interacting controls is to put them into a child dialog. This article presents a simple class that helps you to put a child dialog into a dialog box.

Background

I was developing a MFC application to play MIDI files, and one of the dialog boxes seemed to end up being much too complicated. It was handling the interactions between an array of volume controls, one per track, and a parallel array of buttons for muting the tracks. I decided it would be better to have some sort of object containing the volume control slider and the mute button for a single track, any interactions between them being handled within the object, and the dialog box could then have an array of such objects.

In C terms, instead of having a structure containing two parallel arrays of objects, I wanted an array of structures, each structure containing two related objects.

A web search for advice on how to do this with controls, yielded information on custom controls, so my first attempt to handle the interacting controls used a custom control and is described here. Then I sorted out a better way of doing it, which is to put the interacting controls into a child dialog box, and this article describes how to do that.

Example program

The example program accompanying this article takes part of the standard Color selection dialog box, and handles the interaction between the Hue, Saturation, Luminosity, Red, Green and Blue controls by putting them in a child dialog. The HSL values affect the RGB values, and vice versa, but the parent dialog box doesn't have to know anything about this, it just interacts with the child dialog in terms of RGB values. The child dialog also shows the current color.

Creating a Child Dialog

The steps required to create a child dialog that will appear in a parent dialog box are as follows:

  • Use Dialog Editor and ClassWizard in the normal way to create the child dialog box and its associated class (called ChildDialog (say), and based on CDialog), also to lay out the controls in the child dialog box and create associated member variables in the class. But note the following:
    • Change the properties of the child dialog box (by right-clicking on its border, then choosing Properties) as follows:
      • Style: Child
      • Border: None
      • More styles: Visible and Control must be ticked
    • Delete the OK and Cancel buttons from the child dialog box (otherwise the child dialog will disappear from its parent if you click them).
    • Drag the guidelines to the edge of the box and place the controls right up to the edge (otherwise the child dialog will have a gap all round it).

      Image 1

  • Add any code and data to ChildDialog to make the child dialog box work as required, including any interactions required between the controls (that's the whole point of putting the controls into a child dialog).
  • In ChildDialog.h, #include "GenericChildDialog.h" and change the derivation of ChildDialog from CDialog to CRHGenericChildDialog. Replace the standard constructor for ChildDialog with one without parameters. (It's not essential to do this, but I found it makes other things much easier.) Add a declaration of CRHGetDialogID().
    #include "GenericChildDialog.h"
    ...
    // changed from CDialog
    class ChildDialog : public CRHGenericChildDialog   
    {
    // Construction
    public:
        //ChildDialog(CWnd* pParent = NULL); 
                      // standard constructor - removed
        ChildDialog();                       // added
        virtual int CRHGetDialogID();        // added
        ...
  • In ChildDialog.c, replace the standard constructor for ChildDialog with the new constructor (and move the AFX_DATA_INIT lines to the new constructor, so that ClassWizard puts any initialization it wants in the right place) and add the CRHGetDialogID() routine:
    //ChildDialog::ChildDialog(CWnd* pParent /*=NULL*/)
    //    : CDialog(ChildDialog::IDD, pParent)
    //{
    //}
    // ^^^ standard constructor replaced by
    // constructor without parameters vvv
    ChildDialog::ChildDialog()
    {
        // vvv AFX_DATA_INIT stuff moved from standard constructor
        //{{AFX_DATA_INIT(ChildDialog)
        ... whatever ClassWizard might have put in ...
        //}}AFX_DATA_INIT
    }
    
    int ChildDialog::CRHGetDialogID()
    {
        return(IDD);
    }

Putting a Child Dialog into a parent dialog box

To put the child dialog into a parent dialog box:

  • Use Dialog Editor and ClassWizard in the normal way to create the parent dialog box and its associated class (called ParentDialog (say), and based on CDialog).
  • Use Dialog Editor in the normal way to place a Group Box control in the parent dialog box at the place where you want the child dialog to appear. Only the position of the top left corner of this control is used. Its size is not critical, because it will be resized by CRHGenericChildDialog to match the size of the child dialog. Give this control the ID IDC_CHILDPLACEMARKER (say).

    Image 2

  • Use ClassWizard in the normal way to add a ChildDialog data member (called vChildDialog, say) to ParentDialog.
  • If necessary, create ParentDialog::OnInitDialog() (in ClassView, right-click on ParentDialog, choose "Add Windows Message Handler ...", select WM_INITDIALOG, click "Add and Edit").
  • In ParentDialog::OnInitDialog(), call
    vChildDialog.CRHCreateGenericChildDialog(this, IDC_CHILDPLACEMARKER, 
        Id, &BorderRectangle);

    Id is a WPARAM value that will appear in wparam in any message sent by the child dialog up to the parent dialog box, thereby allowing the parent dialog box to identify where the message came from (this is useful if you have more than one child dialog of the same sort in the parent dialog box). BorderRectangle is a CRect you can use to specify the size of the gap between the child dialog and the Group Box control in the parent dialog box. CRect(4,15,4,6) looks quite good, and is available as CRHGenericChildDialog::CRHRectForGroupBox. You can use different borders, or use NULL if you want the child dialog to appear in place of the Group Box control without any gap round it.

Trying out the Child Dialog

You just need to create the parent dialog box, and the child dialog should now appear in it. If you haven't yet written some code to create the parent dialog box, just add a NewParent item to your main menu, and use ClassWizard in the normal way (using the "Message Maps" tab) to add a COMMAND handler for it. Then create the parent dialog box as a modal dialog box:

void CCc9App::OnNewparent() 
{
    // TODO: Add your command handler code here
    
    ParentDialog vParentDialog;
    vParentDialog.DoModal();
}

Communication between a child dialog and its parent dialog box

To finish off the child dialog, we have to make it communicate with its parent dialog box. The child dialog must tell its parent dialog box when something has happened to the child dialog that the parent needs to know about. And the parent dialog box must be able to tell the child dialog to do various things (exactly what depends on just what functionality the child dialog supports).

This is very similar to how a Windows common control communicates with its parent dialog box:

  • A control informs its parent of any changes by sending a message, which is handled in the class for the parent dialog box by a message handler routine (e.g. OnHScroll()).
  • The parent tells the control what to do by calling a member function (e.g. CSliderCtrl::SetPos()).

So our child dialog and its parent dialog box communicate similarly, as follows:

  • The child dialog informs its parent of any changes by sending a message (by calling CRHGenericChildDialog::CRHPostMessageToParent()), which is handled in the class for the parent dialog box by a message handler routine (e.g. OnCHANGED_RGB()).
  • The parent tells the child dialog what to do by calling a member function (e.g. ChildDialog::SetRGB()).

Using the Child Dialog

Now that we've created a child dialog that handles the interactions between its controls internally, and that communicates with its parent dialog box, we can put one into a dialog box using a placemarker control

void CRHGenericChildDialog::CRHCreateGenericChildDialog(CWnd *pParent, 
                                               int PlaceMarkerCtrlID, 
                                               int Id, 
                                               CRect *ABorderRect)

Image 3

or we can put an array of them into a dialog box using a CRect.

void CRHGenericChildDialog::CRHCreateGenericChildDialog(CWnd *pParent, 
                                               CRect *pPlaceMarkerRect, 
                                               int Id, 
                                               CRect *ABorderRect)

Image 4

The interactions between the HSL controls, the RGB controls and the colored squares are handled entirely within the child dialogs. In this last example, the main dialog box knows only about an array of 5 objects whose interface is just in terms of RGB. This approach is much simpler than having the main dialog box handle the interactions between 65 separate controls.

Finally

If anyone's interested in seeing the original MidiPlay application that prompted this article, you can find it here (click on the "MidiPlay.exe v1.06" link). For a version of Midiplay using custom controls as described in my earlier article, click on the "MidiPlay.exe v1.07" link. For a version of Midiplay using child dialogs as described in this article, click on the "MidiPlay.exe v1.08" link.

History

  • 19th October 2003 - first submitted.
  • 1st November 2003 - major bug fixed (was leaking GDI resources). See Joseph M. Newcomer's article to see the SelectObject() mistake that I made. I originally saw the article on Joe's excellent site (thanks very much Joe!).

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Retired
United Kingdom United Kingdom
I've been programming computers since about 1968. I started at school with Algol 60 on an Elliott 803. From there I progressed through the Z80 and other microprocessors to the PC, DOS and Windows, Pascal, C and C++.

My other interests include astronomy and classical music. All of my contributions to Code Project have arisen from programs I've written in these areas.

Comments and Discussions

 
AnswerRe: combine parent and child into one class ? Pin
Chris Hills20-Apr-06 0:34
Chris Hills20-Apr-06 0:34 
GeneralUsing Tab to switch between controls Pin
rrrado24-Feb-06 4:15
rrrado24-Feb-06 4:15 
AnswerRe: Using Tab to switch between controls Pin
Chris Hills24-Feb-06 8:59
Chris Hills24-Feb-06 8:59 
GeneralRe: Using Tab to switch between controls Pin
rrrado27-Feb-06 2:06
rrrado27-Feb-06 2:06 
GeneralRe: Using Tab to switch between controls Pin
JoeDB7429-Aug-06 18:41
JoeDB7429-Aug-06 18:41 
GeneralRe: Using Tab to switch between controls Pin
Chris Hills29-Aug-06 23:50
Chris Hills29-Aug-06 23:50 
GeneralRe: Using Tab to switch between controls Pin
JoeDB744-Sep-06 18:45
JoeDB744-Sep-06 18:45 
GeneralCFormView implementation Pin
Maxer20-Feb-06 20:42
Maxer20-Feb-06 20:42 
Great work!

Do you think that it is possible to use CFormView as a container of child dialogs ?

Bye from Maxer
AnswerRe: CFormView implementation Pin
Chris Hills24-Feb-06 9:02
Chris Hills24-Feb-06 9:02 
GeneralRe: CFormView implementation Pin
Maxer26-Feb-06 20:34
Maxer26-Feb-06 20:34 
QuestionThe Child Dialog does not apear? Pin
taerry26-Jan-06 22:54
taerry26-Jan-06 22:54 
AnswerRe: The Child Dialog does not apear? Pin
Chris Hills27-Jan-06 9:28
Chris Hills27-Jan-06 9:28 
GeneralChild Dialog in Modeless Dialog Pin
J-B R.3-Jan-06 4:32
J-B R.3-Jan-06 4:32 
GeneralRe: Child Dialog in Modeless Dialog Pin
Chris Hills3-Jan-06 9:54
Chris Hills3-Jan-06 9:54 
QuestionChild Dialog doesn't receive WM_SHOWWINDOW Pin
J-B R.23-Dec-05 4:13
J-B R.23-Dec-05 4:13 
AnswerRe: Child Dialog doesn't receive WM_SHOWWINDOW Pin
Chris Hills24-Dec-05 1:21
Chris Hills24-Dec-05 1:21 
GeneralRe: Child Dialog doesn't receive WM_SHOWWINDOW Pin
J-B R.3-Jan-06 3:32
J-B R.3-Jan-06 3:32 
QuestionHow to make child dialogs draggable? Pin
Member 21987525-Sep-05 0:54
Member 21987525-Sep-05 0:54 
AnswerRe: How to make child dialogs draggable? Pin
Chris Hills10-Sep-05 7:07
Chris Hills10-Sep-05 7:07 
AnswerRe: How to make child dialogs draggable? Pin
Member 219875221-Sep-05 12:23
Member 219875221-Sep-05 12:23 
QuestionHow to deal with if Child Dialog template in DLL? Pin
beyond577627-Jul-05 15:19
beyond577627-Jul-05 15:19 
AnswerRe: How to deal with if Child Dialog template in DLL? Pin
Chris Hills30-Jul-05 10:41
Chris Hills30-Jul-05 10:41 
GeneralGood Work!! Pin
JosephJulian24-May-05 20:15
JosephJulian24-May-05 20:15 
GeneralRe: Good Work!! Pin
Chris Hills25-May-05 9:55
Chris Hills25-May-05 9:55 
Questionseperate Child dilog ? Pin
mohsen nourian7-Nov-04 19:22
mohsen nourian7-Nov-04 19:22 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.