Not modeless enough (or, maybe, how much modeless can you afford? ;-)
-
Thursday, May 03, 2012 2:02 AM
Because of the good advice of you helpers, I have been able to construct a modeless dialog box
with a button and a progress bar, and some static text, all of which work well by themselves
in a test program. Thanx for your time.
Problem is, when I put it all into my application, it is sort of not modeless enough.
After the test, as sort of an in situ test, I invoked the dialog at the end of my App::InitInstance, with SW_SHOW.
It could be moved around, showed its static text, button, and progress bar.
The following snippet shows how I now want to start it normally:
Terminator *guard; // guard is static in MyApp.h, with an access function.
// Terminator class code comes later
BOOL MyApp::InitInstance() {
..
..
guard= new Terminator(AfxGetMainWnd());
guard->Create(IDD_TERMINATOR, NULL);
guard->ShowWindow(SW_HIDE);
return(TRUE);
} // MyApp::InitInstance
class Terminator : public CDialog {
DECLARE_DYNAMIC(Terminator)
public:
Terminator(CWnd* pParent = NULL); // standard constructor
virtual ~Terminator();
// Dialog Data
enum { IDD = IDD_TERMINATOR };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
DECLARE_MESSAGE_MAP()
public:
afx_msg LRESULT ShowProgress(UINT pct);
CProgressCtrl marcher; // the progress bar
afx_msg void OnBnClickedStop();
virtual BOOL OnInitDialog();
CButton term_button;
}; // class Terminator
--------------------------------------------
// Terminator.cpp
#include "stdafx.h"
#include "Terminator.h"
#include "afxdialogex.h"
#include "resource.h"
#include "bond_log.h"
#include "kb.h"
IMPLEMENT_DYNAMIC(Terminator, CDialogEx)
Terminator::Terminator(CWnd* pParent /*=NULL*/)
: CDialog(Terminator::IDD, pParent) {
} // Terminator constructor
Terminator::~Terminator() {
} // Terminator destructor
void Terminator::DoDataExchange(CDataExchange* pDX) {
CDialog::DoDataExchange(pDX);
DDX_Control(pDX, IDC_PROGRESS1, marcher);
DDX_Control(pDX, ID_STOP, term_button);
} // Terminator::DoDataExchange
BEGIN_MESSAGE_MAP(Terminator, CDialog)
ON_BN_CLICKED(ID_STOP, &Terminator::OnBnClickedStop)
END_MESSAGE_MAP()
// Terminator message handlers
void Terminator::OnBnClickedStop() {
put_terminate_compilation(TRUE); // Sets a flag called terminate_compilation
// in the data segment of another module.
exclaim1("INFO", "Bundle compilation terminated manually by user");
// I see this when I push the TERMINATE pushbutton, when it works.
// exclaim1 is my wrapping of MessageBox, sort of.
CDialog::OnOK();
} // Terminator::OnBnClickedStop
LRESULT Terminator::ShowProgress(UINT pct) {
marcher.SetPos(pct);
return(0);
} // Terminator::ShowProgress
BOOL Terminator::OnInitDialog() {
CDialog::OnInitDialog();
marcher.SetRange(0, 100);
marcher.SetBarColor(RGB(255,0,0));
term_button.ShowWindow(WS_VISIBLE);
return(TRUE);
} // Terminator::OnInitDialog
------------------------------------------------
Here is the relevant snippet from ..........rc:
IDD_TERMINATOR DIALOGEX 0, 0, 245, 110
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Terminate compilation"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "TERMINATE",ID_STOP,86,45,50,14
LTEXT "To terminate compilation, push the button.",IDC_STATIC,21,23,153,8
CONTROL "",IDC_PROGRESS1,"msctls_progress32",WS_BORDER,10,77,227,14
END
--------------------------------------------------
The problem begins when I bring up the dialog and then start up a computation,
as follows:
void make_bundles() {
..
..
get_guard()->ShowWindow(SW_SHOW); // get_guard is an access function
enumerate_something(param); // VERY INTENSIVE AND LONG COMPUTATION INVOLVING EXHAUSTIVE SEARCH
// Sit here and spin until enumerate_something is done.
while (!enumerated);
if (get_guard() != NULL) get_guard()->ShowWindow(SW_HIDE);
return;
} // make_bundles
enumerate_something does the follwing:
bunch of computation, in loop.
formation_counter++;
if (formation_counter == 100) {
if (get_guard()) {
get_guard()->ShowProgress(set_number * fraction_of_bar);
}
formation_counter= 0;
}
get_guard()->ShowProgress causes a very nice red bar to crawl across the progress bar of the dialog.
UNFORTUNATELY:
1) The dialog is now all locked up- I can't move it modelessly.
2) I can't see the static text.
3) I can't see the "TERMINATE" button, so I can't stop the computation
until it is finished, which could be a long long time, forcing me to kill
the whole thing with the task manager.
All Replies
-
Thursday, May 03, 2012 3:42 AM
The foundation of a GUI program is its message pump. If you don't let the message pump run then the GUI can't run. That means you cannot do lengthy computation loops, and you cannot do a spin loop. You must let the message pump respond to user input (and painting updates). That is rule 1 and you are ignoring it.
Move such lengthy work into secondary threads. That lets you compute intensley while concurrently maintaining the GUI.
Multithreading is too big a topic to cover in a forum post. But you can get an education on it from this site:
http://www.flounder.com/mvp_tips.htm
- Marked As Answer by Helen ZhaoModerator Thursday, May 10, 2012 3:01 AM
-
Thursday, May 03, 2012 5:43 AM
I took out the spin loop, and put in a message box after the computation. So, I see the static text and the button, but now nothing in the dialog will respond until I answer the message box. That is, it seems that the dialog is no longer modeless. The intensive computation is no longer happening- I just let it terminate on its own.
Many times I have used this kind of progress dialog with termination, and the marching progress bar is actually happening because there is a computation going on.
Might there be something else happening? If I initialize my app, and SW_SHOW the dialog, and don't trigger my intensive search computation, then I have a modeless dialog where I can have both that dialog and a responding message box both up at the same time, in parallel, as well as responses from menu picks.
I have tried running the search in a thread, for very short computations. The thread never returns the "done" flag.
-
Thursday, May 03, 2012 3:24 PM
A message box is modal, and while it is up it runs a message loop so that the app's painting updates can continue to occur. But being modal, it blocks user input to other parts of the GUI.

