Closing CDialog when it looses the focus
-
Hi I have a COptionsDlg class delivered from CDialog. I open it when user right clicks on the main window:
...
COptionsDlg* dlg=new COptionsDlg();
dlg->Create(COptionsDlg::IDD,this);
dlg->ShowWindow(TRUE);
...Now once it's shown I want to close it when user clicks anywhere outside of COptionsDlg. I tried overriding OnKillFocus() of COptionsDlg but it didn't work. And also one more question: How can I exchange data between my main window and COptionsDlg? Any help would be greatly appreciated :)
-
Hi I have a COptionsDlg class delivered from CDialog. I open it when user right clicks on the main window:
...
COptionsDlg* dlg=new COptionsDlg();
dlg->Create(COptionsDlg::IDD,this);
dlg->ShowWindow(TRUE);
...Now once it's shown I want to close it when user clicks anywhere outside of COptionsDlg. I tried overriding OnKillFocus() of COptionsDlg but it didn't work. And also one more question: How can I exchange data between my main window and COptionsDlg? Any help would be greatly appreciated :)
When you say you override OnKillFocus and it didn;t work, what did you mean? It didn't get called? Don't forget ON_WM_KILLFOCUS()... Did it get called, but the window didn't go? Then you need better code! Look in Generic Picker Dropdown Control[^] for a window that goes *poof* if you click away from it. Iain.
I have now moved to Sweden for love (awwww). If you're in Scandinavia and want an MVP on the payroll (or happy with a remote worker), or need contract work done, give me a job! http://cv.imcsoft.co.uk/[^]
-
When you say you override OnKillFocus and it didn;t work, what did you mean? It didn't get called? Don't forget ON_WM_KILLFOCUS()... Did it get called, but the window didn't go? Then you need better code! Look in Generic Picker Dropdown Control[^] for a window that goes *poof* if you click away from it. Iain.
I have now moved to Sweden for love (awwww). If you're in Scandinavia and want an MVP on the payroll (or happy with a remote worker), or need contract work done, give me a job! http://cv.imcsoft.co.uk/[^]
Iain, thank you for your reply. It gets called. The problem is it crashes when I use DestroyWindow() inside OnKillFocus(). Looks like you had the same problem(quote from your source code):
void CGenericPickerPopup::OnKillFocus(CWnd* pNewWnd)
{
CWnd::OnKillFocus(pNewWnd);ReleaseCapture(); //DestroyWindow(); - causes crash when Custom colour dialog appears.
}
// KillFocus problem fix suggested by Paul Wilkerson.
void CGenericPickerPopup::OnActivateApp(BOOL bActive, HTASK hTask)
{
CWnd::OnActivateApp(bActive, hTask);// If Deactivating App, cancel this selection if (!bActive) EndSelection(CPN\_SELENDCANCEL);
}
Now I tried overriding OnActivateApp():
void COptionsDlg::OnActivateApp(BOOL bActive, HTASK hTask)
{
CDialog::OnActivateApp(bActive, hTask);
if (!bActive)DestroyWindow();
}But nothing seems to be happening. What I'm doing wrong?
-
Iain, thank you for your reply. It gets called. The problem is it crashes when I use DestroyWindow() inside OnKillFocus(). Looks like you had the same problem(quote from your source code):
void CGenericPickerPopup::OnKillFocus(CWnd* pNewWnd)
{
CWnd::OnKillFocus(pNewWnd);ReleaseCapture(); //DestroyWindow(); - causes crash when Custom colour dialog appears.
}
// KillFocus problem fix suggested by Paul Wilkerson.
void CGenericPickerPopup::OnActivateApp(BOOL bActive, HTASK hTask)
{
CWnd::OnActivateApp(bActive, hTask);// If Deactivating App, cancel this selection if (!bActive) EndSelection(CPN\_SELENDCANCEL);
}
Now I tried overriding OnActivateApp():
void COptionsDlg::OnActivateApp(BOOL bActive, HTASK hTask)
{
CDialog::OnActivateApp(bActive, hTask);
if (!bActive)DestroyWindow();
}But nothing seems to be happening. What I'm doing wrong?
Try
EndDialog()
(you should rarely, if ever, call DestroyWindow().) -
Try
EndDialog()
(you should rarely, if ever, call DestroyWindow().) -
Joe Woodbury, thank you for your reply.
EndDialog(IDOK);
That works, but how do I catch the mouseclick outside of the CDialog that I show? I should close it when user clicks outside of the CDialog. Is it possible?Only if you capture the mouse.
-
Joe Woodbury, thank you for your reply.
EndDialog(IDOK);
That works, but how do I catch the mouseclick outside of the CDialog that I show? I should close it when user clicks outside of the CDialog. Is it possible?You should call
DestroyWindow()
to destroy a modeless dialog. In the dialog'sPostNcDestroy()
method, you should delete thethis
pointer."Old age is like a bank account. You withdraw later in life what you have deposited along the way." - Unknown
"Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons
-
Iain, thank you for your reply. It gets called. The problem is it crashes when I use DestroyWindow() inside OnKillFocus(). Looks like you had the same problem(quote from your source code):
void CGenericPickerPopup::OnKillFocus(CWnd* pNewWnd)
{
CWnd::OnKillFocus(pNewWnd);ReleaseCapture(); //DestroyWindow(); - causes crash when Custom colour dialog appears.
}
// KillFocus problem fix suggested by Paul Wilkerson.
void CGenericPickerPopup::OnActivateApp(BOOL bActive, HTASK hTask)
{
CWnd::OnActivateApp(bActive, hTask);// If Deactivating App, cancel this selection if (!bActive) EndSelection(CPN\_SELENDCANCEL);
}
Now I tried overriding OnActivateApp():
void COptionsDlg::OnActivateApp(BOOL bActive, HTASK hTask)
{
CDialog::OnActivateApp(bActive, hTask);
if (!bActive)DestroyWindow();
}But nothing seems to be happening. What I'm doing wrong?
Hehe, you missed the trick. I do SetCapture, so I get "all" mouse messages. Then I check for OnLButtonUp, and check whether the click was on my popup window or not. If not on the window, then Destroy the window. This is the part of the article that owes the most to C Maunder's original colour picker popup. (Only about 10% survives, but this is the biggest bit) Iain.
I have now moved to Sweden for love (awwww). If you're in Scandinavia and want an MVP on the payroll (or happy with a remote worker), or need contract work done, give me a job! http://cv.imcsoft.co.uk/[^]
-
Hehe, you missed the trick. I do SetCapture, so I get "all" mouse messages. Then I check for OnLButtonUp, and check whether the click was on my popup window or not. If not on the window, then Destroy the window. This is the part of the article that owes the most to C Maunder's original colour picker popup. (Only about 10% survives, but this is the biggest bit) Iain.
I have now moved to Sweden for love (awwww). If you're in Scandinavia and want an MVP on the payroll (or happy with a remote worker), or need contract work done, give me a job! http://cv.imcsoft.co.uk/[^]
LOLz, Yes I've really missed it! :-D Thanks man! All I need is to override OnNcDestroy() and OnLButtonUp(), and it's working!!!
BOOL COptionsDlg::OnInitDialog()
{
CDialog::OnInitDialog();
SetCapture();//Thank you Iain
return TRUE;
}void COptionsDlg::OnNcDestroy()
{//Thanks to DavidCrow
CDialog::OnNcDestroy();
delete this;
}void COptionsDlg::OnLButtonUp(UINT nFlags, CPoint point)
{//Thanks to Iain
CDialog::OnLButtonUp(nFlags,point);
CRect rect;
this->GetWindowRect(rect);
DWORD pos=GetMessagePos();
point=CPoint(LOWORD(pos),HIWORD(pos));
if(!rect.PtInRect(point)){this->DestroyWindow();}//close only if click was outside of the window
}Thank you Iain and DavidCrow!!! :-D And one last question: How do I exchange data between my main window and that dialog I show?
-
LOLz, Yes I've really missed it! :-D Thanks man! All I need is to override OnNcDestroy() and OnLButtonUp(), and it's working!!!
BOOL COptionsDlg::OnInitDialog()
{
CDialog::OnInitDialog();
SetCapture();//Thank you Iain
return TRUE;
}void COptionsDlg::OnNcDestroy()
{//Thanks to DavidCrow
CDialog::OnNcDestroy();
delete this;
}void COptionsDlg::OnLButtonUp(UINT nFlags, CPoint point)
{//Thanks to Iain
CDialog::OnLButtonUp(nFlags,point);
CRect rect;
this->GetWindowRect(rect);
DWORD pos=GetMessagePos();
point=CPoint(LOWORD(pos),HIWORD(pos));
if(!rect.PtInRect(point)){this->DestroyWindow();}//close only if click was outside of the window
}Thank you Iain and DavidCrow!!! :-D And one last question: How do I exchange data between my main window and that dialog I show?
Firstly - nicely done on presenting what you did, with credits to the helpers. And helpful to others! As for communicating back... You have many approaches. You could have a structure of information somewhere in the main program, and pass COptionsDlg a pointer to it. Then, if the dialog is closed "properly" (ie, OK button), fill in the structure with the DoDataExchange / UpdateDate method. I would also post a message to your parent window saying "I'm goooone!". That way the parent can tidy up any pointers to your option dialog, and enable any Tools | Options menu. It's a good idea to post on success AND failure, and let the parent window decide whether it cares. You could put IDOK / IDCANCEL in the WPARAM of the PostMessage. You could also drop David's
delete this
bit, keep the options in the dialog, and then delete it all in the PostMessage handler in your main program. How you do it really depends on the details of your software, but I hope that's given you the idea. IainI have now moved to Sweden for love (awwww). If you're in Scandinavia and want an MVP on the payroll (or happy with a remote worker), or need contract work done, give me a job! http://cv.imcsoft.co.uk/[^]
-
Firstly - nicely done on presenting what you did, with credits to the helpers. And helpful to others! As for communicating back... You have many approaches. You could have a structure of information somewhere in the main program, and pass COptionsDlg a pointer to it. Then, if the dialog is closed "properly" (ie, OK button), fill in the structure with the DoDataExchange / UpdateDate method. I would also post a message to your parent window saying "I'm goooone!". That way the parent can tidy up any pointers to your option dialog, and enable any Tools | Options menu. It's a good idea to post on success AND failure, and let the parent window decide whether it cares. You could put IDOK / IDCANCEL in the WPARAM of the PostMessage. You could also drop David's
delete this
bit, keep the options in the dialog, and then delete it all in the PostMessage handler in your main program. How you do it really depends on the details of your software, but I hope that's given you the idea. IainI have now moved to Sweden for love (awwww). If you're in Scandinavia and want an MVP on the payroll (or happy with a remote worker), or need contract work done, give me a job! http://cv.imcsoft.co.uk/[^]
Iain, thanks once more! I tried what you suggested: I created a class that holds the options:
//I think you know graphing calculators...
class WindowOptions {
public:
double xmin;
double xmax;
double xscl;
double ymin;
double ymax;
double yscl;
};When I create my optionsdialog, I'm passing a pointer to variable of WindowOptions class. But I'm unable to compile my project, I'm getting LNK2005 errors. "...You could have a structure of information somewhere in the main program, and pass COptionsDlg a pointer to it. Then, if the dialog is closed "properly" (ie, OK button), fill in the structure with the DoDataExchange / UpdateDate method." Can you give me an example please? Or link where I can read more about it?
-
Iain, thanks once more! I tried what you suggested: I created a class that holds the options:
//I think you know graphing calculators...
class WindowOptions {
public:
double xmin;
double xmax;
double xscl;
double ymin;
double ymax;
double yscl;
};When I create my optionsdialog, I'm passing a pointer to variable of WindowOptions class. But I'm unable to compile my project, I'm getting LNK2005 errors. "...You could have a structure of information somewhere in the main program, and pass COptionsDlg a pointer to it. Then, if the dialog is closed "properly" (ie, OK button), fill in the structure with the DoDataExchange / UpdateDate method." Can you give me an example please? Or link where I can read more about it?
OK, I'll assume you have a small idea about classes, dialog, and dodataexchange. If not, go create some and get an idea! What I meant was similar to...
struct Options
{
double xmin;
...
};class CMyApp
{
...
Options m_Options;
...
};In your main frame, you have a menu handler:
void CMainFrame::OnToolsOptions ()
{
CMyOptionsDlg *pDlg = new CMyOptionsDlg; // make a new options dlg - it will self delete.
CMyApp *pApp = (CMyApp *) AfxGetApp ();
dlg->m_pOptions = &(pApp->m_Options); // give the dialog a pointer to the options struct.dlg->Create (this); // make the dialog window
}void COptionDlg::DoDataExchange (CDataExchange *pDX)
{
ASSERT(m_pOtions);
if (!m_pOptions) return;// get/set a double from an edit box
DDX_Text (pDX, IDC_XMIN, m_pOptions->xmin);
...
}I hope those snippets gave you a better idea of what I was thinking! Iain.
I have now moved to Sweden for love (awwww). If you're in Scandinavia and want an MVP on the payroll (or happy with a remote worker), or need contract work done, give me a job! http://cv.imcsoft.co.uk/[^]
-
OK, I'll assume you have a small idea about classes, dialog, and dodataexchange. If not, go create some and get an idea! What I meant was similar to...
struct Options
{
double xmin;
...
};class CMyApp
{
...
Options m_Options;
...
};In your main frame, you have a menu handler:
void CMainFrame::OnToolsOptions ()
{
CMyOptionsDlg *pDlg = new CMyOptionsDlg; // make a new options dlg - it will self delete.
CMyApp *pApp = (CMyApp *) AfxGetApp ();
dlg->m_pOptions = &(pApp->m_Options); // give the dialog a pointer to the options struct.dlg->Create (this); // make the dialog window
}void COptionDlg::DoDataExchange (CDataExchange *pDX)
{
ASSERT(m_pOtions);
if (!m_pOptions) return;// get/set a double from an edit box
DDX_Text (pDX, IDC_XMIN, m_pOptions->xmin);
...
}I hope those snippets gave you a better idea of what I was thinking! Iain.
I have now moved to Sweden for love (awwww). If you're in Scandinavia and want an MVP on the payroll (or happy with a remote worker), or need contract work done, give me a job! http://cv.imcsoft.co.uk/[^]
Thank you Iain! I'm able to pass data between my dialogs. I have the last question. Promise, the last one :) I can catch outside clicks by using SetCapture & OnLButtonUp, but since I run SetCapture() my options dialog receiving no mouse messages inside(If I click on a button in the dialog, the button doesn't get clicked.) What can I do to fix that?