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.
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.
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.
The steps required to create a child dialog that will appear in a parent dialog box are as follows:
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:
Style: Child
Border: None
More styles: Visible and Control must be ticked 
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).
#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 ...
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); }
To put the child dialog into a parent dialog box:
ParentDialog (say), and based on CDialog).
CRHGenericChildDialog to match the size of the child dialog. Give this control the ID IDC_CHILDPLACEMARKER (say).

ChildDialog data member (called vChildDialog, say) to ParentDialog.
ParentDialog::OnInitDialog() (in ClassView, right-click on ParentDialog, choose "Add Windows Message Handler ...", select WM_INITDIALOG, click "Add and Edit").
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.
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(); }
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:
OnHScroll()).
CSliderCtrl::SetPos()). So our child dialog and its parent dialog box communicate similarly, as follows:
CRHGenericChildDialog::CRHPostMessageToParent()), which is handled in the class for the parent dialog box by a message handler routine (e.g. OnCHANGED_RGB()).
ChildDialog::SetRGB()). 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)

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)

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.
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.
SelectObject() mistake that I made. I originally saw the article on Joe's excellent site (thanks very much Joe!). | You must Sign In to use this message board. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||