Click here to Skip to main content
Email Password   helpLost your password?

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:

Putting a Child Dialog into a parent dialog box

To put the child dialog into a parent dialog box:

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:

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

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)

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.

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

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
Generalchild dialog into child dialog
Lukas Müller
11:53 11 Aug '09  
If I use a child dialog like a tab page (property page) and add a other child dialog
into these tab page then the dialog freeze after leave focus.
AnswerRe: child dialog into child dialog
Chris Hills
11:51 14 Aug '09  
I suspect it's to do with the Control attribute of the child dialog. If you create the child dialog from a template then make sure that the Control check box is checked in the More Styles tab of the child dialog's properties. If you create it using CWnd::Create() then make sure the style includes DS_CONTROL.
GeneralRe: child dialog into child dialog
Lukas Müller
7:08 29 Aug '09  
Now all is working fine.
Thank you for your excellent help. Smile
GeneralUpdate control automatically when match some condition
Member 4295420
17:16 16 Nov '08  
Hi...I did used your sample code, and it is great! But unfortunately, when i try to automatically update the editbox (in parentarraydialog type), it couldn't update to the correct editbox. Any idea on this?
AnswerRe: Update control automatically when match some condition
Chris Hills
1:49 17 Nov '08  
It's a bit difficult to say what the problem is without seeing exactly what it is that's going wrong. If you send me some source code (or better still, all the files required to build the application - use the Email link below) then I'll have a look at it.
GeneralDisplaying other children from parent
Trupti Mehta
5:42 29 May '08  
I have many child dialogs namely CPage1, CPage2, CPage3....
Parent class is DataEntryDialog

In CPage1, I want to let parent to update an object that holds all entry data & know to hide cpage1 & show cpage2
Updating data object in parent is to be done by almost all child
Similarly, in CPage4, I have 2 events i.e. on 1 event call CPage5 & on other do something else.

I am new in this work & can't update data object from child to parent. And don't have idea of how to work around with lparam & wparam to call ShowWindow(false) & ShowWindow(true) respectively.

Please help me out. Any clue for to work out with this issue.

Thanks

Terry

GeneralRe: Displaying other children from parent
Chris Hills
8:22 5 Jun '08  
Again, I suggest that you send me the code that you've done so far, including the various dialog boxes you mention, the parent and CPage1, CPage2, CPage3...
GeneralRe: Displaying other children from parent
Trupti Mehta
22:30 5 Jun '08  
For updating the object in parent, I made an object in parent & pass the reference in each child. So what ever changes are made in child is automatically refelcted in parent.

For showing child dialogs:
In parent I have :


void DataEntryDialog::DestroyVisibleChild()
{
CString s;
s.Format(_T("Destroying %d child"), childVisible);
AfxMessageBox(s);
s.Empty();
switch(childVisible) {
case 1:
childPage1.EndDialog(IDOK); // .DestroyWindow();
AfxMessageBox(_T("Destroyed Child 1"));
break;
case 2:
childPage1.EndDialog(IDOK);
childPage2.~CPage2Dlg(); // Destructor calls DestroyWindow()
break;
case 3:
.....
}

afx_msg LRESULT DataEntryDialog::OnSHOW_NEXT_VIEW(WPARAM wparam, LPARAM lparam) {

// AfxMessageBox(_T("Going to sHOW Page 2 "));
int childView = (int)lparam;

DestroyVisibleChild();

CRect rect(4, 2, 5,2);

switch(childView) {
case 1:
childPage1.CRHCreateGenericChildDialog(this, &rect,IDD_PAGE1_DLG, NULL);
childPage1.SetDeptStock(deptStock);
childPage1.SetOperatorsMap(operMap);
childPage1.ShowWindow(SW_SHOW);
break;
case 2:
// Page 2
AfxMessageBox(_T("ABOUT Create Child 2"));
childPage2.CRHCreateGenericChildDialog(this, &rect, IDD_PAGE2_DLG, NULL);
childPage2.SetDeptStock(deptStock);
childPage2.ShowWindow(SW_SHOW);
break;


In child. I call :
void CPage1Dlg::TellParent()
{
// this->ShowWindow(SW_HIDE);
this->CRHPostMessageToParent(WM_SHOW_NEXT_VIEW, 2);

return;
}

// This is to update the object, whenever show is called
void CPage1Dlg::OnShowWindow(BOOL bShow, UINT nStatus)
{
CDialog::OnShowWindow(bShow, nStatus);

// If Show is true & called via ShowWindow()
// Update the control vars with deptStock data
if (bShow && nStatus == 0) {
this->m_number = this->deptStock.GetOperator().GetOperatorNo();
this->m_operName = this->deptStock.GetOperator().GetOperName();

UpdateData(false);
}
return;
}


This code shows next page & all but now started giving ASsertion Failure in UpdateData lines whereever called. To eliminate UpdateData I am trying to GetWindowText & convert from CString to int, float, etc. But sommehow cannot convert it in any way. A discussion is on in message board for that too :
http://www.codeproject.com/script/Forums/View.aspx?fid=1647&select=2584949&fr=94#xx0xx[^]

Chris, Please try to help me in these 2 queries & solve them. I am really in very bad shape, trying very hard to resolve the problems, but somehow things don't work as expected.

Thanks

Terry

GeneralIn PostMessageToParent, I want to pass an object !!
Trupti Mehta
4:57 29 May '08  
Hello Chris,

Thanks a lot for this nice code. It shows the child dialog perfectly as I wanted it to be.

My application has several child dialogs, I want to bring one after another or some other series based on user's selection of buttons in child classes. Initially I have just added 1 child class to the parent. Child & Parent class are made just as you have mentioned. This all child classes represent a form of data entry. On first child, I get some info & want to pass that to the parent. I have an object "DeptStock" that handles all info of the data entry. In TellParent(), I want to pass DeptStock object to my parent. I tried using :
DeptStock odet;
odet.SetOperator(m_operator);
this->CRHPostMessageToParent(OPERATOR_CHANGED, odet);

I get error message :
error C2664: 'CRHPostMessageToParent' : cannot convert parameter 2 from 'class DeptStock' to 'long'
        No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
Error executing cl.exe.

Can you or anyone help me what changes should I do to achive the goal. Any help is highly appreciated.

Thanks in advance.

Thanks

Terry

AnswerRe: In PostMessageToParent, I want to pass an object !!
Chris Hills
8:20 5 Jun '08  
Sorry for the delay in getting back to you. If you send me the code that's causing problems I'll have a look at it. And also the code that you describe as "shows the child dialog perfectly" - that might give me a clue as to what the problem is.
GeneralRe: In PostMessageToParent, I want to pass an object !!
Trupti Mehta
22:17 5 Jun '08  
Chris, thanks for the response. I figured out that PostMessage needs a long & thne we can convert it to our desired object. So I send (int)&deptStock object to PostMessageToParent. & in parent I typecast DeptStock ds = (DeptStock&)lParam.

Chris, I am facing other problem with child dialogs. The problem is whenever I call UpdateData, I get message of Assertion Failure & An unsupported operation was attempted. Their is no way I would trace it or debug it. I am working with eVC++4 & Win CE. For more info on the problem, please visit: http://www.codeproject.com/script/Forums/View.aspx?fid=1647&msg=2583231[^]

I would be glad if you can help me out with the error.

Thanks

Terry

AnswerRe: In PostMessageToParent, I want to pass an object !!
Chris Hills
3:39 6 Jun '08  
You need to be careful when passing the address of an object with PostMessage that the object still exists when the message is processed. If the object is on the stack it almost certainly won't. If you need to pass the address of an object on the stack then use SendMessage.

I'll have a look at your other problem later.
GeneralHow can I send messages between child dialogs?
sshhit
21:11 24 Jul '07  
How CAN I achieve this?
AnswerRe: How can I send messages between child dialogs?
Chris Hills
1:40 5 Aug '07  
Sorry for the delay in replying, I've been on holiday.

CRHGenericChildDialog is derived from CDialog, which is derived from CWnd, so you should be able to use pCRHGenericChildDialog->PostMessage() or pCRHGenericChildDialog->SendMessage().

There is also CRHGenericChildDialog::CRHPostMessageToParent(), which sends a message from the child dialog to its parent.
QuestionAdding a button to the child dialog
petrus11
2:12 2 Dec '06  
Hello!
I added a button to the child dialog and also added a onButton() method in the child class.
If I tab the focus to the button and then press the enter (return) key
nothing happens. If I set a breakpoint in the method I see that the method will never be called.
If I click the button the method is executed.

Do you know why the method is'nt execued when hitting the enter key.
Is there some more propery that have to be set.

Regards Petrus
AnswerRe: Adding a button to the child dialog
Chris Hills
3:12 2 Dec '06  
I do this sort of thing and it works for me. There must be some attribute that I'm setting and you're not. If you send me some code that shows this problem I'll have a look at it.
GeneralRe: Adding a button to the child dialog
petrus11
22:09 3 Dec '06  
I used your project supplied here.
I just added a button using the resource toolbar with resorce Id =IDC_BUTTON1.
And then added a onButton method using classwizard , nothing more.
I also added a ON_WM_KEYDOWN method. And that method is never
called when the button got focus either.


BEGIN_MESSAGE_MAP(ChildDialog, CDialog)
//{{AFX_MSG_MAP(ChildDialog)
ON_NOTIFY(UDN_DELTAPOS, IDC_SPINH, OnDeltaposSpinh)
ON_NOTIFY(UDN_DELTAPOS, IDC_SPINS, OnDeltaposSpins)
ON_NOTIFY(UDN_DELTAPOS, IDC_SPINL, OnDeltaposSpinl)
ON_NOTIFY(UDN_DELTAPOS, IDC_SPINR, OnDeltaposSpinr)
ON_NOTIFY(UDN_DELTAPOS, IDC_SPING, OnDeltaposSping)
ON_NOTIFY(UDN_DELTAPOS, IDC_SPINB, OnDeltaposSpinb)
ON_BN_CLICKED(IDC_BUTTON1, OnButton1)
ON_WM_KEYDOWN()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()


void ChildDialog::OnButton1()
{
SetRGB(255,0,0);

}

/Regards Petrus
GeneralMultiple Parent Messages
James Wise
15:41 29 Nov '06  
Hi i have implemented the parent child dialogs etc. and most things things work ok.....
Except i am trying to have the child dialog send a number of different messages to the parent dialog.
The problem is that only the very first message handler i have added appears to work??

I have a right click menu in the child class, which then triggers one of several messages, each of the message functions looks like...

CRHPostMessageToParent(CLOSE_THIS_VIEW, CRHGetDialogID() );
or
CRHPostMessageToParent(START_TWO_WAY, CRHGetDialogID() );

Both of the functions gets called in the child class, but only the CLOSE_THIS_VIEW ever gets handled by the parent class?
Is there any reason why multiple message handlers in the parent class/dialog should not work?


Also i have noticed that the OnCLOSE_THIS_VIEW( WPARAM wparam, LPARAM lparam ) function (which is the handler that DOES work) in the parent class gets called a lot, eg. every time i move the window? is this supposed to happen, or does it indicate i have setup something incorrectly?

Cheers,
James
GeneralRe: Multiple Parent Messages
Chris Hills
0:38 30 Nov '06  
If you send me some code that shows this problem I'll have a look at it.
GeneralProblem
rrrado
23:57 8 Oct '06  
It seems I've found a problem with this solution. I use my on class using this approach.
The difference is that my app is MFC dialog application where main dialog has child Tab control which contains child dialogs for each tab item. For example CDialog1 for tab 1. When I place some child dialogs with the controls I need to repeat into CDialog1, TAB key is not working to switch between controls. (I have Control style set for child dialog).
What is even worse when I put focus to control of child dialog, then switch to another application and then back to my application, my application hangs in forever loop somewhere inside MFC or windows code.
Spy++ shows it happens after WM_ACTIVATE and WM_ACTIVATETOPLEVEL.

When I use the same class on simple dialog without tab, it works good.

Any idea what could be wrong? Here is minimal project if somebody would have a time to check it: test.zip[^]

Thank you very much in advance


rrrado

AnswerRe: Problem
rrrado
0:31 11 Oct '06  
It seems I've got it working. For case anybody else would be interested I've called
SetWindowLong(GetSafeHwnd(),GWL_EXSTYLE,WS_EX_CONTROLPARENT);

for tab control, tab control's child dialog and also child dialog containing controls





rrrado

GeneralRe: Problem
rrrado
0:33 11 Oct '06  
It could be also good tip in the article. I just hope there won't be other problems with this which I haven't found yet


rrrado

GeneralInsert ActiveX Control in to the child dialog
Ionut Codrut
2:06 16 Sep '06  
Hello!
It is possible to insert an ActiveX control in to the child dialog? it doesn't work for me.

Regards!
Ioan
AnswerRe: Insert ActiveX Control in to the child dialog
Chris Hills
12:35 17 Sep '06  
Ever since I read http://www.flounder.com/billjoy.htm[^] I have steered very clear of anything to do with ActiveX, so I'm afraid I don't know the answer.
GeneralReusing Controls
Steve_pqr
8:35 11 Sep '06  
I really like the idea of combining controls into a child dialog which can then be treated as a single independent entity - except that it isn't, if I want to use the same child dialog in another program I have to redefine it as it is effectively 'tied' to the parents resource file. Am I correct in thinking this way and if so is there a way round it...

Thanks for a great topic,



Last Updated 4 Nov 2003 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010