accessing variable from the child dialog - c++

I have a child dialog. I initiate other child dialog.
In the second dialog i have the following code for list box.
I need to access the m_selcomponents in the first child dialog. Itried to access this like
dlg->m_selcomponents. But it's getting null. How can i do this? Thank You for help.
int count = m_OutList.GetCount();
for ( i = 0; i <m_OutList.GetCount(); i++)
{
m_OutList.GetText( buf[i], text );
m_selcomponents->Add(text);
}
MSelCFLCompDlg *SelCflCompDlg= new MSelCFLCompDlg(&allcomponents, &m_cflcomponents,m_FileDecimal,this) ;
if(SelCflCompDlg->DoModal()==IDOK) { selectedcomponents.Append(*SelCflCompDlg->m_selcomponents); }
MSelCFLCompDlg::MSelCFLCompDlg(CStringArray *all, CStringArray *sel,int, CWnd* pParent /*=NULL*/)
: CDialog(MSelCFLCompDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(MSelCFLCompDlg)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
m_allcomponents = all;
m_selcomponents = sel;
}

When you create the child dialog box, pass a pointer to the parent dialog box to the child dialog box constructor. If you show us a bit more of your code I can perhaps explain in a bit more detail.

Related

How to OnInitDialog every CPropertyPage in MFC?

I have 2 CPropertyPage objects; right now, the second page will only hit OnInitDialog if I click on the second page.
How can I initialize it right away when program starts?
You can add PSP_PREMATURE to the dwFlags field of each property page's m_psp data member (a PROPSHEETPAGE structure). This forces the actual creation of that page (thus calling its OnInitDialog() function) when the parent property sheet is created, rather than waiting until the page is selected.
The only online documentation I can find for this is now 'deprecated', but the technique does still work.
dwFlags ... PSP_PREMATURE The page is created when the property sheet is created. Usually, the page is not created until the
first time it is selected.
You can add this flag in the constructor for each page; something like this:
class MyPropPage : public CPropertyPage
{
public:
MyPropPage(UINT idd) : CPropertyPage(idd) {
m_psp.dwFlags |= PSP_PREMATURE; // Add the 'premature' flag on construction
//...
}
//...
};
You might want to use a WM_TIMER message in your CPropertySheet like this:
BOOL CMyPropertySheet::OnInitDialog()
{
SetTimer(1, 1, NULL);
return CPropertySheet::OnInitDialog();
}
void CMyPropertySheet::OnTimer(UINT_PTR nIDEvent)
{
if (nIDEvent == 1)
{
KillTimer(1);
SetActivePage(1); // initialize second tab
SetTimer(2, 1, NULL);
}
else if (nIDEvent == 2)
{
KillTimer(2);
SetActivePage(0); // back to first tab
// to hide the initialization process, you might want to create
// CMyPropertySheet with the WS_VISIBLE style disabled and wait
// until all pages are initialized:
ShowWindow(SW_SHOW);
}
CPropertySheet::OnTimer(nIDEvent);
}

How to handle message send from view class to dialog?

I have SDI application that hand view, doc and mainframe. In view class, I have button to open another dialog, let say Chartering dialog. I would like to open that dialog and send initial value from view to assign some variable at dialog, but I can not catch message event at dialog class. Below as my code:
// button onclick to show new dialog
charteringDlg = new CharteringDlg();
// show chartering dialog
if(charteringDlg->Create(IDD_DIALOG_CHATTERING, GetDesktopWindow()))
{
bChartering = true;
charteringDlg->MoveWindow(900,300,450,300);
charteringDlg->ShowWindow(SW_SHOW);
int temp = 12;
GetMain()->SendMessage(UWM_MYMESSAGE_CHARTERING, 0,(LPARAM)&temp);
}
and in chartering dialog I handle message like below
ON_MESSAGE(UWM_MYMESSAGE_CHARTERING, &CharteringDlg::OnSetShowTemp)
chartering function
LRESULT CharteringDlg::OnSetShowTemp(WPARAM, LPARAM lParam)
{
int * s = (int *)lParam;
return 0;
}
I set break point at OnSetShowTemp() function but it cannot jump there.
Any idea would be great appreciated.
For assigning an initial value to one of your dialog's members you don't need to send it a message.
You can just assign the value directly:
So instead of
GetMain()->SendMessage(UWM_MYMESSAGE_CHARTERING, 0,(LPARAM)&temp);
you should have something like:
charteringDlg->thevalueorwhatever = 12;
And BTW:
GetMain()->SendMessage(UWM_MYMESSAGE_CHARTERING, 0,(LPARAM)&temp);
is wrong anyway, you should send the message to the dialog and not to the main window:
charteringDlg->SendMessage(UWM_MYMESSAGE_CHARTERING, 0,(LPARAM)&temp);

CMFCTabCtrl ActiveTab on CMDIChildWndEx::OnMDIActivate and the MenuBar issue

As the title propose, I have an CMDIChildWndEx application(on VS2017, Windows 10 x64). On the ChildFrame, CMyView creates: (A) CMFCTabCtrl (Id=1), 2 CView derived classes: Lets say (B) CViewDerivedA object (Id=2) and (C) CViewDerivedB object (Id=3). The parent of A-C is the parent of CMyView. CMyView adds CDerivedViewA object as tab-0, and CViewDerivedB object as tab-1. CViewDerivedA handle MenuA of the menubar . But, when I open a MDI document, the menu is not enabled, until I switch to tab-1 & back to tab-0. I try the following code, but SetFocus() doesn't work:
// An application sends the WM_MDIACTIVATE message to a multiple-document interface (MDI)
// client window to instruct the client window to activate a different MDI child window.
void CMyChildFrame::OnMDIActivate(BOOL bActivate, CWnd* pActivateWnd, CWnd* pDeactivateWnd)
{
CMDIChildWndEx::OnMDIActivate(bActivate, pActivateWnd, pDeactivateWnd);
if (bActivate)
{
CMFCTabCtrl *pTabCtrl = (CMFCTabCtrl*) GetDlgItem(1);
if (pTabCtrl->GetActiveTab() == 0) // 0 - Silhouette tab, 1 - Hit List tab
{
// CWnd * pWnd = GetDlgItem(2);
// pWnd->SetFocus();
pTabCtrl->SetActiveTab(1);
pTabCtrl->SetActiveTab(0);
}
}
}
In any case, this solution seems to me not "clean", a "workaround". >>>> I assume that the proper way is to tell the pTabCtrl (Id=1) to SetFocus() on the active tab, as it does when I SetActiveTab() next & back. What is the way to make it properly?
I find the solution:
void CMyChildFrame::OnMDIActivate(BOOL bActivate, CWnd* pActivateWnd, CWnd* pDeactivateWnd)
{
CMDIChildWndEx::OnMDIActivate(bActivate, pActivateWnd, pDeactivateWnd);
if (bActivate)
{
CView * pView = (CView*)((CMFCTabCtrl*)GetDlgItem(1))->GetActiveWnd();
SetActiveView(pView);
}
}

How to display values in child MFC dialog box based on variables set in parent dialog box?

I have a MFC project I am working on. In the main dialog box there is a button to open a child dialog box for some user input. This data is then set to variables in the parent dialog box when OK is clicked in the child box. This bit all works perfectly fine.
Right now the text boxes in the child box initialize to preset values in the OnInitDialog() of the child dialog box. I would like these values to initialize to whatever the variable they are connected to in the parent dialog box currently is.
So, for example I have a text box that sets in integer variable called sampleCount. In the child dialog box I have (just showing the code for this variable)
void ChildBox::DoDataExchange(CdataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Text(pDX, IDC_SAMPCOUNT, sampCnt);
}
BOOL FNameIn::OnInitDialog()
{
CDialog::OnInitDialog();
GetDlgItem(IDC_SAMPCOUNT)->SetWindowTextA("1");
return TRUE;
}
Then in the parent dialog box I have
void ParentDialog::OnInput()
{
ChildBox dlg;
if (dlg.DoModal() == IDOK)
{
sampleCount = dlg.sampCnt;
}
}
As I said, this code all works, but every time I open the ChildBox the sampleCount text box is set to 1. If I type in 20, then hit ok and set the sampleCount variable in ParentDialog to 20 I want it to show a 20 in the text box next time I open the child dialog box. The variable could also be set automatically by another function in ParentDialog, so the last value entered in child dialog isn't always correct, it needs to use whatever is currently the value of the variable sampleCount in ParentDialog.
I feel like this should be pretty straight forward but I can't quite figure it out, thanks for the help.
Modify the child dialog's constructor to accept a CString parameter and store that into the child's sampCnt variable. Then the MFC code will display it in the control because of the DDX_Text statement.
Remove the GetDlgItem(IDC_SAMPCOUNT)->SetWindowTextA("1"); line and set the value before calling dlg.DoModal(), like
ChildBox dlg;
dlg.sampCnt = sampleCount;
if (dlg.DoModal() == IDOK)
{ sampleCount = dlg.sampCnt;
}
I think you are creating local variable of ChildBox Dialog
so , even if you are assigning a value to its variable it will not work.
Rather create a pointer variable of ChildBox Dialog
void ParentDialog::OnInput()
{
ChildBox *dlg;
if (dlg->DoModal() == IDOK)
{
sampleCount = dlg->sampCnt;
}
dlg = NULL ;
}

How do I detect if a modeless CDialog has been closed?

I have followed this question to make a non-modal/modeless dialog:
How to display a non-modal CDialog?
I'm using MFC/C++ in VS2008. I'm more fluent with C# and .net than with MFC and C++.
I have a menu item in my form that launches the dialog. There can only be one instance of the dialog opened. The dialog displays fine. I can close it by clicking the X in the corner and it closes when I close the main form. The problem I am having is the dialog cannot be opened again after I click the X to close the dialog. I know it is because the pointer is never set back to NULL.
I have this in my form's header file:
CChildDialog *m_pDialog;
I have this part in my form's constructor:
m_pDialog = NULL;
When clicking on a menu item I have this code in the menu item's method (I modified it from the other SO answer because I only want one instance of the dialog opened):
if(m_pDialog == NULL)
{
// Invoking the Dialog
m_pDialog = new CChildDialog();
BOOL ret = m_pDialog->Create(IDD_CHILDDIALOG, this);
if (!ret) //Create failed.
{
AfxMessageBox(_T("Error creating Dialog"));
}
m_pDialog->ShowWindow(SW_SHOW);
}
Now I know I need to execute this part and set the pointer to NULL, but I don't know where to put this:
// Delete the dialog once done
delete m_pDialog;
m_pDialog = NULL;
Do I need to keep monitoring if the dialog has been disposed? Is there an event triggered to the parent form when the dialog is closed?
If you want to recycle the contents of the window after closing it with X, you have to handle the WM_CLOSE message in your dialog:
void CChildDialog::OnClose()
{
ShowWindow(SW_HIDE);
}
Then in the code that opens the window:
if(m_pDialog == NULL)
{
// Invoking the Dialog
m_pDialog = new CChildDialog();
BOOL ret = m_pDialog->Create(IDD_CHILDDIALOG, this);
if (!ret) //Create failed.
{
AfxMessageBox(_T("Error creating Dialog"));
}
}
m_pDialog->ShowWindow(SW_SHOW); //moved outside the if(m_pDialog == NULL)
Hope it can help
If you want to delete the modeless dialog, then just do so.
If you want to delete the dialog's object when the user closed the modeless dialog you might take a look at WM_PARENTNOTIFY. If a child window is destroyed and the child windows has not the extended window style WS_EX_NOPARENTNOTIFY set, then windows sends a WM_PARENTNOTIFY with wParam=WM_DESTROY to the parent window. You should implement a handler for that message in the parent window and check if it's the modeless dialog that is being destroyed.
I had the question drafted up and was ready to post it, but then I had an idea and ended up solving my own problem. So for anyone else who has an issue with detecting the closing of a modeless dialog, this is what I did:
void Form1::MenuItemMethod()
{
if(m_pDialog == NULL)
{
// Invoking the Dialog
m_pDialog = new CChildDialog();
BOOL ret = m_pDialog->Create(IDD_CHILDDIALOG, this);
if (!ret) //Create failed.
{
AfxMessageBox(_T("Error creating Dialog"));
}
m_pDialog->ShowWindow(SW_SHOW);
}
else
{
// cannot check if visible at the beginning of method because
// pointer could be NULL and will throw an exception
if(m_pDialog->IsWindowVisible())
{
return;
}
m_pDialog->DestroyWindow();
m_pDialog = NULL;
MenuItemMethod();
}
}
I just ended up checking if the modeless dialog is visible after clicking on the form's menu item again. If it is visible, don't do anything. If not, destroy the existing non-visible dialog, set the pointer to NULL, and recursively call the method again. Since the pointer is now NULL, it should recreate the dialog normally and then return to normal operation.
you have to delete the memory in PostNcDestroy like this
void CChildDialog ::PostNcDestroy()
{
CDialog::PostNcDestroy();
GetParent()->PostMessage(WM_WIN_CLOSED,0,0);
delete this;
}
and send a user defined message to the parent window that your window is closed. In the parent window add a message handler for WM_WIN_CLOSED like
LRESULT CMainDialog::OnMyMethod(WPARAM wParam, LPARAM lParam)
{
m_pDialog = NULL;
return 0;
}