How to close a dialog box using do modal - c++

Okay basically I have an MFC application with lots of dialogs that need to be cycled through. Basically when you click one button to go to another dialog, I want the previous dialog to close. Right now the dialogs are just displayed over the top of each other. How do I get the dialog to close once the new dialog has opened? Here is some example code:
void CMachine2Dlg::OnBnClickedNewmc()
{
NameDlg Dlg;
Dlg.DoModal()
}

What you can do is hide the parent dialog when you DoModal() the new dialog and destroy it after the new dialog ends. I have not tested the ShowWindow() below but you get the idea, if it doesn't hide the dialog look for another similar function.
void CMachine2Dlg::OnBnClickedNewmc()
{
ShowWindow( SW_HIDE);
NameDlg Dlg;
Dlg.DoModal();
EndDialog( 0 );
}

IT will be difficult to chain those dialog the way you mention. Do modal is usually meant to implement exactly what you are experiencing. Ie: dialog pops up over the previous one.
One way to do this is to create the modal dialogs sequence in the class that calls the first dialog and use the return value of the previous dialog to determine if you need to show the second one and so forth.
For ex:
// define a bunch of constants, any number would do,
// I would avoid 0 and 1 as they usually mean success/error
// This code can be returned in the EndDialog call in a method of your choice (say button click handler).
const int c_needNextDialog = 101;
dialog1 dlg1;
if( dlg1.DoModal() == c_needNextDialog )
{
dialog2 dlg2;
if( dlg2.DoModal() == c_needNextDialog )
{
... and so forth
}
}
I'm sure you get the idea...
in your dialog, you return like so (taken directly from msf)
void dialog1::OnSomeAction()
{
// Do something
EndDialog(c_needNextDialog); // This value is returned by DoModal!
// Do something
return; // Dialog closed and DoModal returns only here!
}
I would stay clear of modeless dialog, you will end up with another problem like how to control the flow of dialog and prevent people to click the main window of your application behind.

You could try calling
EndDialog(nResult);

OnOK(), OnCancel() or EndDialog(nResult) will answer your title question.
However, like #tenfour suggested, you should be using a property sheet / wizard. It can also be a single dialog window with several child property page windows that you show or hide depending on what you want to be seen.
For this, you will need:
1 dialog window, maybe with Prev/Next buttons
1 picture box, frame style, not visible, inside the dialog where you want the child windows to appear
n property pages, child style, no border, where you put all the controls.
Create a class for the dialog and each property page, add a member variable of each property page to the dialog, create the property pages and use the frame as a reference to place them. On button click just show/hide the necessary pages.

You could call OnCancel() inside your dialog class. Like: this->OnCancel();

#tenfour suggest a good possible solutions
But if its not possible for you
you should create the dialogs from one basic windows/Dlg
Mydialog dlg1
if(dlg1.DoModal() )
{
//do something
}
else
// do something else
Mydialog dlg2
if(dlg2.DoModal() )
{
//do something
}
else
// do something else
and so on....
This way you don't have easy controll of "what's" going on and you don't have to mess with different windows, messageloops.

Related

C++ MFC Attach different dialogs for each tab in CTabCtrl

I have a small project I'm working on. It has multiple dialogs so what I want to do is to have 1 main Window with multiple tabs in it. I want each tab to represent different dialog. For now I have that : Dialog with CTabCtrl opens as I expect and I have 3 tabs attached to it, when I press (for example) tab 1 it creates a new Modeless instance of my wanted PopUpDialog and it appears right where I want it. All good. But then if I move my main window , my PopUpDialog (which is borderless) stays on the same spot where he pops up at the start. Seems like the "spawn" location of my dialog is mapped to my CTabCtrl Dialog but it's not attached to it. I think I need to make it a child class or something like this . I am new to MFC and programming. I've been looking for answers for past 2 days but many links were deleted because they're too old. This is a little code example of what I'm doing:
void CTabCtrlDialog::OnSelchangeTab(NMHDR *pNMHDR, LRESULT *pResult)
{
CDialogIwantToPopUp *m_Page;
m_Page = new CDialogIwantToPopUp();
m_Page->Create(IDD_POPUP_DIALOG, m_tabTest.GetWindow(IDD_POPUP_DIALOG));
m_Page->ShowWindow(SW_SHOW);
}
This is a function (in my dialog that contains the tab control) that is responsible for click on any tab event.
I find it easiest to use a property sheet in this situation, but if that isn't appropriate for you, you need to ensure each page has the DS_CHILD style (Style: Child in the resource editor property list).
When creating the page, its parent window should be 'this' rather than what you're doing with GetWindow().

Make focused modeless dialog topmost

So I have my main dialog that calls modeless dialogs through this function (this is the legacy code on the project):
void MyClass::ShowDialog(CDialog* dialog)
{
if (!IsWindow(dialog->m_hWnd))
{
return;
}
int nCmdshow1 = dialog->IsWindowVisible() ? SW_HIDE : SW_SHOW;
dialog->ShowWindow( nCmdshow1 );
}
Problem: all sub dialogs stay on top of my main dialog.
Desired behavior: whichever's focused (they are all modeless), be it the main dialog, or sub dialogs, I want it to be the topmost dialog. Thank you!
Note: I already tried on my main dialog's OnInitDialog() these but didn't work:
1. SetWindowPos(&this->wndTop,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE);
2.SetWindowPos(&this->wndTopMost,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE);
EDIT
Also, sub dialogs are created this way:
m_subDlg1->Create( SubDlg1::IDD, this );
As long as there is an owner relation between two windows. the owner of a window can never be on top of the owned window.
Windows in an owner, parent, child relation always behave the same. The owned/child window is always on top of the parent/owner.
If you want to break this, you have to break the owner/child relation. Let all dialog windows have no owner... than they may float freely.
But: I will expect the you program doesn't behave better. Even worse. User might search windows that are deep below covered under other windows. And they will never get in front, when your program gets active.
See the description about parent/child/owned windows here. Also this article might be helpful.
Edit: The problem is that internally the MFC sets the main window as an owner if no parent is given. Only the call to BOOL Wnd::CreateDlgIndirect(LPCDLGTEMPLATE lpDialogTemplate, CWnd* pParentWnd, HINSTANCE hInst) allows to leave pParentWnd NULL.
So you may create the window as normal, but use SetParent(NULL) after it was created. Again the MFC ASSERTs this. SO you may use the API function and the handle of your dialog.

Bitmap in Buttons disappear

I have a CFormView SDI which calls and opens up a CDialog.
In the CDialog I have a button which has a bitmap displayed.
All works well, until I close the CDialog.
When I open up the same CDialog (using create function), the button appears, and the button's functionality is there, however the bitmap disappears.
Can someone please tell me why the bitmap on the button disappears on subsequent calls to CDialog?
Thank you in advance.
Here is the code:
In the CFormView I have a button that creates the CDialog:
void CTest4View::OnButton1()
{
m_dialog_calculator.Create(IDD_DIALOG1, GetDesktopWindow());
m_dialog_calculator.ShowWindow(SW_SHOW);
}
In the CDialog I have the bitmap put on the button in the InitDialog:
BOOL CCalculator::OnInitDialog()
{
CDialog::OnInitDialog();
if(!bitmapNew.LoadBitmap(IDB_BITMAP_NEW)){
MessageBox("problem in loadbitmap");
}
if(!m_button.SetBitmap(bitmapNew)){
MessageBox("problem in SetBitmap");
}
bitmapOpen.LoadBitmap(IDB_BITMAP_OPEN);
m_buttonOpen.SetBitmap(bitmapOpen);
//==========================
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
Upon further investigation, the problem seems to be in: m_button.SetBitmap(bitmapNew) since this returns FALSE. Can someone please help me?
Quick fix:
void CTest4View::OnButton1()
{
// only create the dialog once
if (m_dialog_calculator.m_hWnd==NULL)
m_dialog_calculator.Create(IDD_DIALOG1, GetDesktopWindow());
m_dialog_calculator.ShowWindow(SW_SHOW);
}
Additional information 1:
The information that OP provided in his question/code is quite little, so I actually have to recreate a similar test project to guess what is wrong with the missing bitmap. What I found is that the CDialog and CBitmap is being created multiple times when the button is pressed, this causes subsequent creation api call to fail, other than the first creation call. The result is some unexpected behavior as you can see now.
The program is supposed to generate some assertion errors when run in debug mode due to the creation failure but I guess the OP compiled it in release mode so all warnings are being suppressed.
The problem occurred because the calculator dialog is created as a modeless dialog as compared to a normal DoModal way of activation. The usual way of doing such modeless dialog is to create the dialog only once, by monitoring the m_hWnd member variable. When the user want the dialog to be dismissed, it is simply being hidden instead of being destroyed. This will avoid all the multiple creation problems altogether.
I guess presently, the calculator dialog is assumed to be closed and destroy by clicking the "X" button on the top right of dialog, well, actually it is only hidden but not actually being destroyed by the default handling of CDialog. The correct way to dismiss the modeless calculator dialog is thus to overide the OnClose event to hide it using ShowWindow(SW_HIDE). To activate it again, use ShowWindow(SW_SHOWNORMAL).

Main dialog destroys before command message handler returns

My program use a modeless dialog to interact with the user and also has a tray icon.
A user can quit the app immediately by using the tray icon.
BOOL OnInitDialog()
{
init data...
}
void OnDestroy()
{
destroy data...
}
void OnSomeButton()
{
CFileDialog dlg;
...
dlg.DoModal(m_hWnd));
access data...
...
}
void OnMenuExit()
{
DestroyWindow();
}
The problem is that when I popup a modal dialog(OnSomeButton), and then quit using the tray icon menu, the main dialog is destroyed first, and then the modal one returns, trying to access some invalid data, causing a crash.
I know i can add some check code before accessing the data, but is there any other way?
Is there any way to ensure OnSomeButton() returns before window destroy?
You need to add your own application level code. There is no system support for this issue primarily because there can be so many pecularities that no generic approach is possible.
Yeah. When you quit from the tray menu, you can send a WM_CLOSE or similar message to your modal dialog that causes it to exit. Even if your main window is destroyed before that OnSomeButton returns you will be okay provided the remainder of that function does not access any class internals (member variables etc). You could ensure this by having the window proc of your modal dialog return an 'abort' code or something when it is closed in this way.

Not able to Show a Dialog Box in its class using SW_SHOW in MFC?

I am trying to create a wizard like structure using dialog boxes...So I replaced the code in CDialog1App as below
CDialog1Dlg* dlg = new CDialog1Dlg;
m_pMainWnd = dlg;
dlg->Create(IDD_DIALOG1);
dlg->ShowWindow(SW_SHOW);
the above worked fine...its displying the dialog box.but I have added another dialog box...
So in the first dialog box if the user clicks Next it has to hide the first dialog box and display the second dialog..
//CDialog1 class
void CDialog1Dlg::OnBnClickedNext()
{
// TODO: Add your control notification handler code here
CDialog2* dialog2 = new CDialog2();
dialog2->Create(IDD_DIALOG2);
dialog2->ShowWindow(SW_SHOW);
this->ShowWindow(SW_HIDE);
}
in the above code am creating an object for the Dialog2 class and trying to show that....
Now the problem is,when I click next its hiding both the windows..What can I do..I tried several types but its still its not workin..Please dont suggest me to do with PropertySheet..It will work with that, i know ...but I want this using Dialog Box for some reason
You're creating the dialog2 with the default parent window (NULL):
dialog2->Create(IDD_DIALOG2);
But the default parent seems to be dialog1 in your case. And since you hide dialog1 which is the parent of dialog2, dialog2 is also hidden.
Find the window (CWnd) of either your main app dialog (if you have one visible apart from your wizard), or use the desktop window as the parent.
For example:
dialog2->Create(IDD_DIALOG2, GetDesktopWindow());