I want to show a modeless dialog on the screen and display some information in it.
However if I use it the following way, it has some problems:
function()
{
showdialog(XXX).
//heavy work.
update the dialog..
//heavy work.
update the dialog...
}
It seems the dialog displayed, but it does not draw any information in it. It only draw all information when the function is over.
How can I modify the modeless dialog so it will display the information immediately?
Don't try to do your heavy work all at once. Have the dialog post itself a message in the WM_APP range in OnInitDialog. The WM_APP handler can do part of the heavy work, then do another PostMessage and return. In this way, you allow the message pump to process window messages in between your chunks of processing.
As a rule of thumb, heavy computations should never be placed in the GUI thread. Since it is a modeless dialog, the dialog will not own the message loop. The ProcessMessage() solution will work, but is IMO not the right way. My suggestion is: 1) Spawn a new thread in OnInitDialog() 2) Have the separate thread post messages to the dialog when something interesting happens. One of these interesting things is that the work is done.
Note, however, that this will mean that you need to perform proper synchronization.
In OnInitDialog, start a worker thread to perform the computations. Post a user message from the worker thread to update the dialog.
This is superior to the ProcessMessages implementation for several reasons:
The code for doing the calculations can be separated out of the UI code, where it does not belong.
The UI remains responsive while the actual calculations are being performed. ProcessMessages allows multiple UI updates during the single calculation function, but the UI will still be blocked during the actual calculations.
Dialog code:
The worker thread:
There are a few things you can do.
(1) You could post the dialog a message from inside the CDialog::OnInitDialog method and then handle the long function in the message handler of that posted message. That way the dialog will first be displayed and then later the long function will get run.
(2) The second option is to make sure the message loop gets some processing time. So if your long function is some sort of loop just add the occasional call to the ProcessMessages to make sure the message queue is kept empty:
Edit: It certainly is possible to use threads is such a situation, but doing so is not always without risk and complexity.
Using threads with a GUI means having to deal with multiple message queues which then means using API's like PostThreadMessage and that introduces a new set of issues to be wary of.
For an example of one such issue refer to this link:
http://msdn.microsoft.com/en-us/library/ms644946(VS.85).aspx
where is says:
I use the process message approach in the Zeus IDE and it works very well at making sure the GUI remains responsive to the user. It is also has the advantage of being very easy to implement.