Modal dialog not visible - c++

Trying to create modal dialog (CDialogEx) from modeless window form :
void CMainWindow::OnPushButtonClicked ()
{
InputDialog dlg;
int r= dlg.DoModal();
AfxMessageBox("do modal is done");
}
Got no visible input dialog, but DoModal procedure did not returns. Why dialog is not visible?

Related

how to get selchange msg from popUp owner draw ListBox in MFC

I am trying to make my own custom property grid. I have made the owner-draw ListBox. when we click on the dialog box it popup.
but not getting msg when I click on the list.
how to get it?
I am trying with this function but not getting any trigger here when we click on any item on Listbox.
BEGIN_MESSAGE_MAP(x_ListBox, CListBox)
ON_CONTROL_REFLECT(LBN_SELCHANGE, &x_ListBox::OnLbnSelchange)
END_MESSAGE_MAP()
void x_ListBox::OnLbnSelchange()
{
try
{
auto selIdx = GetCurSel();
ReleaseCapture();
GetParent()->DestroyWindow();
}
catch (CException* p)
{
p->Delete();
}
}
I need to send msg to the DialogBox current selected item. is there any way I can get msg from DialogBox when we select an item in ListBox. like ComboBox in the DialogBox m_com.GetLbText(xxx);

Displaying popup dialog when main dialog is on second monitor

I have an interesting situation.
You run any CDialog derived application and move it onto your second monitor.
You then invoke a popup dialog. I am finding that the popup dialog is being displayed in the center of the main monitor and not central to the parent dialog.
For example:
void CMeetingScheduleAssistantDlg::OnOptionsPublishersDatabase()
{
try
{
CPublishersDatabaseDlg dlgPublishers(this);
dlgPublishers.DoModal();
}
catch (_com_error e)
{
LPCTSTR szError = e.ErrorMessage();
AfxMessageBox(szError);
}
catch (CException* e)
{
e->Delete();
AfxMessageBox(_T("CException"));
}
}
How are we supposed to correctly invoke a child popup dialog central to the parent when the parent is on the second monitor?

Close modeless dialog when another window closes

I have a modeless dialog which I'm creating as below,
CPlotDlg * newd = new CPlotDlg ();
newd->Create(IDD_PLOT,this->GetParentOwner());
newd->SetParent(this->GetParentFrame()->GetParent());
newd->ShowWindow(SW_SHOW);
I want to close this dialog when a different window closes (not the parent). How can I achieve this?
Thanks.
Just, save CPlotDlg* to other window which will be used for closing CPlotDlg window.
If the closer window is SomeWhereDlg,
class SomeWhereDlg
{
public:
...
...
CPlotDlg* m_plotDlg;
};
void SomeWhereDlg::SetPlotDlg(CPlotDlg* plotDlg)
{
ASSERT(plotDlg);
if(plotDlg == nullptr) { return;}
m_plotDlg = plotDlg;
}
And then, when create CPlotDlg window, save the pointer.
CPlotDlg* newd = new CPlotDlg ();
//Save newd(CPlotDlg*) to somewhere
//i.e) specific window which will close this newd window
//SomeWhereDlg->SetPlotDlg(newd);
newd->Create(IDD_DIALOG1,this->GetParentOwner());
newd->SetParent(this);
newd->ShowWindow(SW_SHOW);
if a closing event occur, just call Close() or delete, etc via m_plotDlg.
To close the modeless dialog save the pointer as CodeDreamer shows, and call m_plotDlg->DestroyWindow()

Show dialog before main window

I have a windowed application, which crashes after showing information dialog only before QMainWindow is activated.
Information dialog is shown only if passed data is invalid, however it might be a user interaction (file select / drag) or passed as argument, which causes problems. When / how should I show such error dialog than?
Note: When dialog is only shown (with show() method rather than exec()) it doesn't crash, but dialog gets discarded right away even with setModal( true ).
Any ideas? Thanks,
EDIT:
Some code:
int WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, LPSTR lpCmdLine, int nShowCmd)
{
QApplication app(__argc, __argv);
MBViewer viewer;
viewer.show();
return app.exec();
}
MBViewer::MBViewer()
{
setAcceptDrops(true);
m_ui.setupUi(this);
m_viewer = new Viewer_Widget();
m_ui.preview_layout->addWidget(m_viewer);
parse_parameters();
connect_controls();
connect_actions();
}
void MBViewer::connect_controls()
{
(...)
connect( m_viewer, SIGNAL( view_initialized()), this, SLOT( open_file() ));
(...)
}
void MBViewer::open_file()
{
// somefile is set in parse_parameters or by user interaction
if (!somefile.is_valid()) {
m_viewer->reset();
// This will crash application after user clicked OK button
QMessageBox::information( this, "Error", "Error text", QMessageBox::Ok );
return;
}
(...)
}
Try a message box without pointer to your main window like in this example:
QMessageBox msgBox;
msgBox.setText(text.str().c_str());
msgBox.setIcon(QMessageBox::Question);
QPushButton *speed = msgBox.addButton("Speed optimization", QMessageBox::AcceptRole);
QPushButton *memory = msgBox.addButton("Memory optimization", QMessageBox::AcceptRole);
QPushButton *close = msgBox.addButton("Close", QMessageBox::RejectRole);
msgBox.setDefaultButton(speed);
msgBox.exec();
if (msgBox.clickedButton() == memory)
return true;
if (msgBox.clickedButton() == close)
exit(4);
It works even before creating any window (but after QApplication initialization).
When you call app.exec( ),it starts the main message handler loop which is required to be running before you start displaying dialogs. QMessageBox is a modal dialog when used with exec, so will prevent the app.exec function being called. Therefore, it's likely that messages are being sent before the message handler has been initialised and so a crash is observed.
When show() is used, execution of app.exec is allow to process, which is why the crash doesn't happen.
If you want a modal MessageBox at startup, you'll need to launch it after the message handler has been created / initialised. Not the cleanest way, but you could try launching it on a timer to delay the call to exec.

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;
}