mridey
asked on
Application Modal Dialogs using Modeless Dialogs
Note: I am using WTL, not MFC. I can understand MFC code but I would prefer a WTL or pure Windows answer.
I've got a long processing loop in my application and I would like to display a progress dialog while it's doing its stuff.
Here's the code simplified:
CProgressDlg dlg;
dlg.Create(hParent);
dlg.CenterWindow();
dlg.ShowWindow(TRUE);
while(/*there_is_work_to_d o*/)
{
FlushMessages(); /* message pump */
if (dlg.m_bCancel) * set to true if the cancel button is pressed */
break;
/* do work here and loop again */
}
dlg.DestroyWindow();
Now this works fine, the code executes, the dialog is displayed nicely, but this dialog is a child of my main window and I would like to lock the main window until the work is completed, e.g. I would like the focus to stay on the dialog.
Note: I don't want it System modal, just application modal.
How should I change the code? I don't see how to use the DoModal since I need to run code and just update the progress window once in a while.
Thanks
I've got a long processing loop in my application and I would like to display a progress dialog while it's doing its stuff.
Here's the code simplified:
CProgressDlg dlg;
dlg.Create(hParent);
dlg.CenterWindow();
dlg.ShowWindow(TRUE);
while(/*there_is_work_to_d
{
FlushMessages(); /* message pump */
if (dlg.m_bCancel) * set to true if the cancel button is pressed */
break;
/* do work here and loop again */
}
dlg.DestroyWindow();
Now this works fine, the code executes, the dialog is displayed nicely, but this dialog is a child of my main window and I would like to lock the main window until the work is completed, e.g. I would like the focus to stay on the dialog.
Note: I don't want it System modal, just application modal.
How should I change the code? I don't see how to use the DoModal since I need to run code and just update the progress window once in a while.
Thanks
ASKER
No, it's the problem. If I use DoModal, the call doesn't return and I can't execute the work I need to do while the dialog is displayed. I am not using the dialog to get user input prior to the loop, I'm using the dialog to give feedback to the user while I'm processing their request.
In short, imagine there is a progress bar on the dialog and you're trying to update 100 records in a database.
You want first to display the progress bar then to loop through the 100 records and as you modify them, you update the progress bar. When you're finished (or if the user press cancel), you close the window and stop your work.
In short, imagine there is a progress bar on the dialog and you're trying to update 100 records in a database.
You want first to display the progress bar then to loop through the 100 records and as you modify them, you update the progress bar. When you're finished (or if the user press cancel), you close the window and stop your work.
You can simply use like this
WTL also have DoModal functio for dialog
CProgressDlg dlg;
dlg.DoModal();
GOOD LUCK
WTL also have DoModal functio for dialog
CProgressDlg dlg;
dlg.DoModal();
GOOD LUCK
So then u just set the ponter of the parent window to dialog
And the the dialog will call the public method of the parent
GOOD LUCK
And the the dialog will call the public method of the parent
GOOD LUCK
ASKER
Sorry I don't understand the last comment
1. Add a public method in your Dialog class named SetParent.
2. Pass the parent window poiter to this dialog by this method
3. Add a public method in your parent class. In that method add, your codes that needed to process from the dialog.
4. call the DoModal
5. From the dialog call the parent windows public method through its parent (that already setted through the SetParent method) pointer.
GOOD LUCK
2. Pass the parent window poiter to this dialog by this method
3. Add a public method in your parent class. In that method add, your codes that needed to process from the dialog.
4. call the DoModal
5. From the dialog call the parent windows public method through its parent (that already setted through the SetParent method) pointer.
GOOD LUCK
ASKER
Ok, almost there. No problem doing this.
Just a quick question then, To trigger the call to the parent, I need to do it within a message currently processed by the dialog?
Something like:
OnInitDialog()
{
...
PostMessage(WM_USER ...)
}
OnUserMessage()
{
m_Parent->DoSomeWork()
}
And if so, can I just pump all messages inside DoSomeWork() with the usual PeekMessage/DispatchMessag e loop to ensure that the user interface remain active (so that the dialog can be moved & canceled and the appllication doesn't appear non-responsive.)
Thanks
Just a quick question then, To trigger the call to the parent, I need to do it within a message currently processed by the dialog?
Something like:
OnInitDialog()
{
...
PostMessage(WM_USER ...)
}
OnUserMessage()
{
m_Parent->DoSomeWork()
}
And if so, can I just pump all messages inside DoSomeWork() with the usual PeekMessage/DispatchMessag
Thanks
ASKER
Ok, almost there. No problem doing this.
Just a quick question then, To trigger the call to the parent, I need to do it within a message currently processed by the dialog?
Something like:
OnInitDialog()
{
...
PostMessage(WM_USER ...)
}
OnUserMessage()
{
m_Parent->DoSomeWork()
}
And if so, can I just pump all messages inside DoSomeWork() with the usual PeekMessage/DispatchMessag e loop to ensure that the user interface remain active (so that the dialog can be moved & canceled and the appllication doesn't appear non-responsive.)
Thanks
Just a quick question then, To trigger the call to the parent, I need to do it within a message currently processed by the dialog?
Something like:
OnInitDialog()
{
...
PostMessage(WM_USER ...)
}
OnUserMessage()
{
m_Parent->DoSomeWork()
}
And if so, can I just pump all messages inside DoSomeWork() with the usual PeekMessage/DispatchMessag
Thanks
Don't post message to the parent,
Just call the Function using parent pointer...
Roshmon
Just call the Function using parent pointer...
Roshmon
ASKER
I meant to say that the dialog would post a message to itself (to get out of the OnInitDialog processing). One way or another I need to be in the middle of processing a dialog message when I call the parent function and since the processing of that message could take many many minutes, I need to process the message loop while inside the message of the dialog called by DoModal ...
All this in fact because there is no OnIdle processing within a Modal Dialog.
All this in fact because there is no OnIdle processing within a Modal Dialog.
>> can I just pump all messages inside DoSomeWork() with >>the usual PeekMessage/DispatchMessag e
>>loop to ensure that the user interface remain active
No, No use
that can process the parent messages while in do modal....
If it is a large processing u can either put that into a thread, or call the function from the dialog instead of calling entire loop.
That is u can use PeekMessage, and Dispatch for the Dialog window.....
So Do the looop in dialig instead of parent wiindow
Roshmon
>>loop to ensure that the user interface remain active
No, No use
that can process the parent messages while in do modal....
If it is a large processing u can either put that into a thread, or call the function from the dialog instead of calling entire loop.
That is u can use PeekMessage, and Dispatch for the Dialog window.....
So Do the looop in dialig instead of parent wiindow
Roshmon
ASKER
Thanks, I'll try a few options tomorrow (it's getting late in Australia).
Okay
ASKER
Using DoModal doesn't work in this case, at least not the way I tried it.
This is the code I used for testing:
in the main frame, activated by a menu command:
CProgressDlg dlg;
dlg.DoModal(hParent);
then the class definition
class CProgressDlg : public CDialogImpl<CProgressDlg>
{
public:
enum { IDD = IDD_PROGRESS };
BEGIN_MSG_MAP(CProgressDlg )
MESSAGE_HANDLER(WM_INITDIA LOG,OnInit Dialog)
MESSAGE_HANDLER(WM_USER,On UserMsg)
COMMAND_ID_HANDLER(IDCANCE L, OnCancel)
END_MSG_MAP()
bool m_bCancel;
CProgressBarCtrl m_progress;
CStatic m_text;
LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
m_progress.Attach(GetDlgIt em(IDC_PRO GRESS));
m_text.Attach(GetDlgItem(I DC_TEXT));
m_progress.SetRange32(0,10 0);
m_progress.SetPos(0);
m_progress.SetStep(1);
m_bCancel = false;
PostMessage(WM_USER);
return TRUE;
}
LRESULT OnUserMsg(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
for (int i=0; i<100; i++)
{
FlushMessages();
if (m_bCancel)
break;
Beep(1000,100);
}
EndDialog(0);
return 0;
}
LRESULT OnCancel(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
m_bCancel = true;
return 0;
}
};
The dialog never appears on the screen. I get the series of Beeps as expected then the DoModal returns but the FlushMessages function doesn't help in handling the dialog messages. this is its code:
bool FlushMessages()
{
MSG msg;
while(::PeekMessage(&msg,N ULL,NULL,N ULL,PM_NOR EMOVE))
{
if (msg.message != WM_QUIT)
{
::GetMessage(&msg,NULL,NUL L,NULL);
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
else
return true;
}
return false;
}
Should I be using something else to process the dialog messages in the middle of the processing of the WM_USER message? Such as calling a DialogProc() directly for each message?
Looks like I'm going to have to start a work thread in the processing of the WM_INITDIALOG message and synchronise the two so that the cancel button kills the work thread and the work thread terminate the DoModal when it finishes its work.
I would have preferred to avoid the multithreaded architecture.
Thanks
This is the code I used for testing:
in the main frame, activated by a menu command:
CProgressDlg dlg;
dlg.DoModal(hParent);
then the class definition
class CProgressDlg : public CDialogImpl<CProgressDlg>
{
public:
enum { IDD = IDD_PROGRESS };
BEGIN_MSG_MAP(CProgressDlg
MESSAGE_HANDLER(WM_INITDIA
MESSAGE_HANDLER(WM_USER,On
COMMAND_ID_HANDLER(IDCANCE
END_MSG_MAP()
bool m_bCancel;
CProgressBarCtrl m_progress;
CStatic m_text;
LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
m_progress.Attach(GetDlgIt
m_text.Attach(GetDlgItem(I
m_progress.SetRange32(0,10
m_progress.SetPos(0);
m_progress.SetStep(1);
m_bCancel = false;
PostMessage(WM_USER);
return TRUE;
}
LRESULT OnUserMsg(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
for (int i=0; i<100; i++)
{
FlushMessages();
if (m_bCancel)
break;
Beep(1000,100);
}
EndDialog(0);
return 0;
}
LRESULT OnCancel(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
m_bCancel = true;
return 0;
}
};
The dialog never appears on the screen. I get the series of Beeps as expected then the DoModal returns but the FlushMessages function doesn't help in handling the dialog messages. this is its code:
bool FlushMessages()
{
MSG msg;
while(::PeekMessage(&msg,N
{
if (msg.message != WM_QUIT)
{
::GetMessage(&msg,NULL,NUL
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
else
return true;
}
return false;
}
Should I be using something else to process the dialog messages in the middle of the processing of the WM_USER message? Such as calling a DialogProc() directly for each message?
Looks like I'm going to have to start a work thread in the processing of the WM_INITDIALOG message and synchronise the two so that the cancel button kills the work thread and the work thread terminate the DoModal when it finishes its work.
I would have preferred to avoid the multithreaded architecture.
Thanks
Hi
y u posting message to the same dialog, instead of calling the function directly ?
Roshan Davis
y u posting message to the same dialog, instead of calling the function directly ?
Roshan Davis
ASKER
I'm still trying to understand what you mean by 'Calling the function directly'. It has to be called from somewhere.
So what I tried was to get the dialog during INITDIALOG to post itself a message, to be able to get out of the INITDIALOG processing and then when the WM_USER is being processed by the dialog to to the bulk of the work.
I have in the example above simulated the call to my parent function by replacing it with a Beep().
What happends is that during the processing of the WM_USER message, even with the FlushMessage() function, the application is not processing messages, the dialog is not displayed ... but I get the series of Beeps. Once the loop is completed, the DoModal returns (since the loop terminate with an EndDialog(0). )
So the question remains: How can I get a lot of processing done while the modal dialog is dislayed and if it's done inside a message of the dialog, how do I maintain the message pump to get Paint and mouse movements processed.
Marc
So what I tried was to get the dialog during INITDIALOG to post itself a message, to be able to get out of the INITDIALOG processing and then when the WM_USER is being processed by the dialog to to the bulk of the work.
I have in the example above simulated the call to my parent function by replacing it with a Beep().
What happends is that during the processing of the WM_USER message, even with the FlushMessage() function, the application is not processing messages, the dialog is not displayed ... but I get the series of Beeps. Once the loop is completed, the DoModal returns (since the loop terminate with an EndDialog(0). )
So the question remains: How can I get a lot of processing done while the modal dialog is dislayed and if it's done inside a message of the dialog, how do I maintain the message pump to get Paint and mouse movements processed.
Marc
Only peek and dispatch messages of the dialog.
Add a method in dialog, and call by its name. U r Posting the message to the same dialog itself. Thats what i'm mentioned..
Roshmon
Add a method in dialog, and call by its name. U r Posting the message to the same dialog itself. Thats what i'm mentioned..
Roshmon
ASKER
Yes, the code is aboe. I use:
PostMessage(WM_USER)
in OnInitDialog so the message is posted to the dialog itself.
Even if I add a method to the dialog, where would you call it from. I can call it from the main code (since that code is locked waiting for the DoModal() to complete). I can only call it from a message being processed.
Marc
PostMessage(WM_USER)
in OnInitDialog so the message is posted to the dialog itself.
Even if I add a method to the dialog, where would you call it from. I can call it from the main code (since that code is locked waiting for the DoModal() to complete). I can only call it from a message being processed.
Marc
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Thanks for the help.
WTL also have DoModal functio for dialog
CProgressDlg dlg;
dlg.DoModal();
GOOD LUCK