15 мая 2023 года "Исходники.РУ" отмечают своё 23-летие!
Поздравляем всех причастных и неравнодушных с этим событием!
И огромное спасибо всем, кто был и остаётся с нами все эти годы!

Главная Форум Журнал Wiki DRKB Discuz!ML Помощь проекту


Wait cursors and ignoring messages

Peter Moss -- pmoss@bbn.com
Thursday, December 26, 1996

Environment: VC++ 4.2-flat, NT 4.0

I have a funny little problem that I was wondering if anyone has a neat 
solution for.

I have a case where I need to let my process go off and compute its little 
head off for anywhere from 5-30 seconds.  During that time, I don't want the 
user to do anything since the computation affects the state of the Doc, so I 
don't want the user to be able to change anything else.  I thought, I would 
just do the following and be done with it:

CWaitCursor wait;
DoLengthyProcessing();
return;

The hourglass appears and the code works great except for one thing: if the 
user clicks around with the hourglass cursor, messages get accumulated in the 
queue and are processed after we return from the above code.  This caused 
undesirable effects on the state of my Doc.

My solution was to create a worker thread to do the lengthy processing.  Then 
in the UI thread I had to do a few kludgy things to get the desired behavior.

1. In CMainFrame, I maintain a BOOL m_bThreadActive variable.  I set this to 
TRUE when the worker thread is doing its thing, and FALSE when it is suspended 
waiting for a call to wake up.

2. I override CMainFrame::OnSetCursor().  I set the cursor to IDC_WAIT when 
m_bThreadActive = TRUE.

3. The only way I could figure out how to ignore messages was to provide a 
CMainFrame::PreTranslateMessage() override that checks for m_bThreadActive.  
It looks something like:

BOOL CMainFrame::PreTranslateMessage(MSG* pMsg) 
{
 // TODO: Add your specialized code here and/or call the base class
 if (m_bThreadActive) {
  // Worker thread active. Filter any msgs you want to go thru here
  if (pMsg->message != WM_WORKER_THREAD_FINISHED)
   return(TRUE);
 }

 return CFrameWnd::PreTranslateMessage(pMsg);
}

where WM_WORKER_THREAD_FINISHED is a user-defined msg that is sent via 
PostMessage() by the worker thread when it is done. (I use the technique 
modeled after the MTDemo app in Jeff Prosise's "Programming Windows 95 with 
MFC".)  This works, but I'm a bit uneasy about filtering all msgs except the 
one that signals that the worker thread is done.

Although this works for me, I was wondering if there was an easier way to 
accomplish what I'm trying.  Any thoughts?

Thanks,
Pete Moss
pmoss@domaincorp.com





Avinash Saxena -- avi@outlooksoftware.com
Friday, December 27, 1996

Why don't you disable the window which accumulates messages while the =
lengthy processing is going on ? That it it will not accept any messages =
for accumulation.

Else, after your lengthy processing go thru the message queue and =
discard all the messages not required.

Avi

----------
From: 	Peter Moss[SMTP:pmoss@bbn.com]
Sent: 	Thursday, December 26, 1996 2:29 PM
To: 	mfc-l@netcom.com
Cc: 	Peter Moss
Subject: 	Wait cursors and ignoring messages

Environment: VC++ 4.2-flat, NT 4.0

I have a funny little problem that I was wondering if anyone has a neat=20
solution for.

I have a case where I need to let my process go off and compute its =
little=20
head off for anywhere from 5-30 seconds.  During that time, I don't want =
the=20
user to do anything since the computation affects the state of the Doc, =
so I=20
don't want the user to be able to change anything else.  I thought, I =
would=20
just do the following and be done with it:

CWaitCursor wait;
DoLengthyProcessing();
return;

The hourglass appears and the code works great except for one thing: if =
the=20
user clicks around with the hourglass cursor, messages get accumulated =
in the=20
queue and are processed after we return from the above code.  This =
caused=20
undesirable effects on the state of my Doc.

My solution was to create a worker thread to do the lengthy processing.  =
Then=20
in the UI thread I had to do a few kludgy things to get the desired =
behavior.

1. In CMainFrame, I maintain a BOOL m_bThreadActive variable.  I set =
this to=20
TRUE when the worker thread is doing its thing, and FALSE when it is =
suspended=20
waiting for a call to wake up.

2. I override CMainFrame::OnSetCursor().  I set the cursor to IDC_WAIT =
when=20
m_bThreadActive =3D TRUE.

3. The only way I could figure out how to ignore messages was to provide =
a=20
CMainFrame::PreTranslateMessage() override that checks for =
m_bThreadActive. =20
It looks something like:

BOOL CMainFrame::PreTranslateMessage(MSG* pMsg)=20
{
 // TODO: Add your specialized code here and/or call the base class
 if (m_bThreadActive) {
  // Worker thread active. Filter any msgs you want to go thru here
  if (pMsg->message !=3D WM_WORKER_THREAD_FINISHED)
   return(TRUE);
 }

 return CFrameWnd::PreTranslateMessage(pMsg);
}

where WM_WORKER_THREAD_FINISHED is a user-defined msg that is sent via=20
PostMessage() by the worker thread when it is done. (I use the technique =

modeled after the MTDemo app in Jeff Prosise's "Programming Windows 95 =
with=20
MFC".)  This works, but I'm a bit uneasy about filtering all msgs except =
the=20
one that signals that the worker thread is done.

Although this works for me, I was wondering if there was an easier way =
to=20
accomplish what I'm trying.  Any thoughts?

Thanks,
Pete Moss
pmoss@domaincorp.com



Kevin Johnson -- kevinj@microcrafts.com
Friday, December 27, 1996

[Mini-digest: 2 responses]

I'm not certain what your needs are for this, but would putting up a
little dialog box (progress type thing, whatever seems best to you) that
eats up whatever messages the user ends up creating (and having your
worker thread busy doing its job).

This way, you can pull up a dialog and ignore the cancel/close/terminate
messages as you see fit, without affecting the rest of your application.

Best of luck,
--Kevin

>----------
>From: 	pmoss@bbn.com[SMTP:pmoss@bbn.com]
>Sent: 	Thursday, December 26, 1996 12:29 PM
>To: 	mfc-l@netcom.com
>Cc: 	pmoss@bbn.com
>Subject: 	Wait cursors and ignoring messages
>
>Environment: VC++ 4.2-flat, NT 4.0
>

>
>1. In CMainFrame, I maintain a BOOL m_bThreadActive variable.  I set
>this to 
>TRUE when the worker thread is doing its thing, and FALSE when it is
>suspended 
>waiting for a call to wake up.
>
>2. I override CMainFrame::OnSetCursor().  I set the cursor to IDC_WAIT
>when 
>m_bThreadActive = TRUE.
>
>3. The only way I could figure out how to ignore messages was to
>provide a 
>CMainFrame::PreTranslateMessage() override that checks for
>m_bThreadActive.  
>It looks something like:
>
>BOOL CMainFrame::PreTranslateMessage(MSG* pMsg) 
>{
> // TODO: Add your specialized code here and/or call the base class
> if (m_bThreadActive) {
>  // Worker thread active. Filter any msgs you want to go thru here
>  if (pMsg->message != WM_WORKER_THREAD_FINISHED)
>   return(TRUE);
> }
>
> return CFrameWnd::PreTranslateMessage(pMsg);
>}
>
>where WM_WORKER_THREAD_FINISHED is a user-defined msg that is sent via 
>PostMessage() by the worker thread when it is done. (I use the
>technique 
>modeled after the MTDemo app in Jeff Prosise's "Programming Windows 95
>with 
>MFC".)  This works, but I'm a bit uneasy about filtering all msgs
>except the 


-----From: Michael McIntosh 

Try this,

CWaitCursor wait;
AfxGetMainWnd()->EnableWindow(FALSE);
DoLengthyProcessing();
AfxGetMainWnd()->EnableWindow(TRUE);
return;

[Michael McIntosh]  



P.J. Tezza -- pj@exemplarsoftware.com
Tuesday, December 31, 1996

Use a progress dialog of some kind with a cancel button. In your =
computation code, call the progress dialog's message loop occasionally =
(or post a message to do so). This will give you these benefits:

1) The user can cancel. For a ten second delay, anything less is poor =
software design.
2) The user can estimate how long the work will take and possibly =
perform other tasks (such as getting coffee).
3) The clicks will not accumulate.
4) You can remove your message filter hack. I am not sure what the =
thread is for, but maybe you can remove it as well.

Your choice of progress indicator can be a standard progress meter, text =
messages, etc. For a quick example, use the Component Gallery to insert =
a Progress Dialog.

PJ
pj@exemplarsoftware.com





| Вернуться в корень Архива |