I made a very simple MFC application that call a Dialog when I click in a button, and send a MessageBox after 5 seconds.
The problem is, when I was in the second dialog and I dismiss the MessageBox from the parent (not click OK button of MessageBox. I click in a blank part of the second dialog) I cannot close this dialog (The second dialog) when I click OK or CANCEL button.
Why?
Part of Code:
Main Dlg:
BOOL Cmult_rc_testDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
SetTimer(1, 5000, NULL);
return TRUE; // return TRUE unless you set the focus to a control
}
void Cmult_rc_testDlg::OnBnClickedButton1()
{
CDlg1 a;
a.DoModal();
}
void Cmult_rc_testDlg::OnTimer(UINT_PTR nIDEvent)
{
KillTimer(nIDEvent);
MessageBox(L"oi");
CDialog::OnTimer(nIDEvent);
}
The second Dialog is default code generated by MFC wizard.
Not sure I understand your question entirely . . . it sounds like you're trying to close the parent window when the message box is still shown?
If that's the case, the parent window owns the message box, and is not allowed to acquire focus until the message box is closed. You could try using
::MessageBox(NULL, L"oi", L"MessageBox", MB_OK);
instead of MessageBox, which will create a message box that allows you to focus back on the original window still (The :: means to use the global namespace version of MessageBox, which is the Windows native call as opposed to MFC).
Related
I have a dialog box which i use for picking colors. It consists of a buttons that represent colors and an edit control with buddy spin button.
When i create the dialog i call SetCapture() in order to get the clicks and whenever they are outside of the dialog it should closes.
Everything works fine until i click on a edit control or on it's buddy. After that CMyDialog::OnLButtonDown() will not be called, because i suppose that the capture is lost.
I tried calling SetCapture() in ON_EN_CHANGE message handler but it does not solve the problem.
My qestion is:
Where should i call SetCapture() in order to close the dialog when i have already clicked on the edit control or it's spin button?
The approach that i have taken is not right at all. Turns out that ON_WM_NCACTIVATE message should be handled and the dialog should be closed if
CDialog::OnNcActivate( bActive ) returns false.
the function looks like this :
BOOL CMyDialog::OnNcActivate( BOOL bActive )
{
BOOL bResult = CDialog::OnNcActivate( bActive );
if( !bActive )
{
PostMessage( WM_CLOSE );
}
return bResult;
}
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).
I have a console application that uses GetAsyncKeyState();, but if the user is on looking at another window and pressed a button, GetAsyncKeyState(); picked it up (I already knew that).
Without having to do GetActiveWindow();, how else could I check if my window is the one on top?
EDIT: GetConsoleWindow() == GetForegroundWindow() worked.
This thing worked for me:
HWND name;
name=GetForegroundWindow();
while(!_kbhit()){
if(name==GetForegroundWindow())
printf("Mine window is active\n");
else
printf("Mine window is not active\n");
}
To get the active Window you can call GetActiveWindow. GetFocus will return the handle of the window that has the input focus. This window can be a control as well. So you can check against your window handle and see if it has the focus.
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.
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.