OnUpdate(CCmdUI *pCmdUI) response too late for toolbar button
My problem is this, when save is in progress and I want to disable the save button in menu as well as the corresponding button in toolbar (part of rebar).
void CTestDoc::OnUpdateFileSave(CCmdUI *pCmdUI)
{
pCmdUI->Enable(!m_bBusy);
}
So when I start saving, I set m_bBusy to TRUE and than to FALSE when done. While the file menu works perfectly with this call the toolbar button in the rebar response is late.
I noticed the button in toolbar change the state only when OnFileSave() is finished executing and terminates (I had to omit setting the flag to FALSE at the end to see this effect).
How can I make it to respond correctly? Should I programatically enable and disable it..if so how? Obviosly I want to disable the toolbar button when saving just begins.
[812 byte] By [
zspirit] at [2007-11-20 11:55:48]

# 1 Re: OnUpdate(CCmdUI *pCmdUI) response too late for toolbar button
If you do the saving in the same thread, no other messages are processed until you finish saving, of course. Create a second, working, thread for saving your data.
cilu at 2007-11-11 4:02:12 >

# 2 Re: OnUpdate(CCmdUI *pCmdUI) response too late for toolbar button
I have to admit, I am confused a little.
If your saving routine is not running in a separate thread, you would not be able to see menu item state therefore this is not a case.
If you are using separate thread, you should see a change immediately after flag changed and save dialog (if used) is dismissed.
So I think I have missed something and if this is a case, my advice would be to force an update right after setting save flag:
m_bBusy = TRUE;
CWnd *pFrame = AfxGetMainWnd();
pFrame->SendMessageToDescendants(WM_IDLEUPDATECMDUI,
(WPARAM)TRUE, 0, TRUE, TRUE);
JohnCz at 2007-11-11 4:03:12 >

# 3 Re: OnUpdate(CCmdUI *pCmdUI) response too late for toolbar button
I have to admit, I am confused a little.
If your saving routine is not running in a separate thread, you would not be able to see menu item state therefore this is not a case.
If you are using separate thread, you should see a change immediately after flag changed and save dialog (if used) is dismissed.
So I think I have missed something and if this is a case, my advice would be to force an update right after setting save flag:
m_bBusy = TRUE;
CWnd *pFrame = AfxGetMainWnd();
pFrame->SendMessageToDescendants(WM_IDLEUPDATECMDUI,
(WPARAM)TRUE, 0, TRUE, TRUE);
This is great, now the save button is immediatly disabled but it gives rise on other issue too. If I open another file, the save button and menu should correspond to that accordingly and while the menu option does (= it is enabled for a new file/doc/view), the toolbar button stays disabled because the other file save is in progress.
Yes this is all in single thread. I do use PeekMessage in the save loops in hope that user messages will be processed but the toolbar is exception.
MSG msg;
while (::PeekMessage(&msg, NULL, NULL, NULL, PM_NOREMOVE))
{
AfxGetThread()->PumpMessage();
}
Does it mean the best and recommended way for (say) a lengthy save would be to do it in another thread? I am going to cut down on the save time as well but that is a seperate issue for now.
# 4 Re: OnUpdate(CCmdUI *pCmdUI) response too late for toolbar button
I see, you are using kind of local message loop.
If you set m_bBusy flag properly, toolbar button state should should follow.
It is difficult to discuss your issue without analyzing a code.
Do you think you could post your project or test project illustrating this problem?
As for a question regarding using a separate threat is the best way of handling long background processing. Local message loop was used in 16-bit Windows OS that was not preemptive.
JohnCz at 2007-11-11 4:05:10 >

# 5 Re: OnUpdate(CCmdUI *pCmdUI) response too late for toolbar button
I also noticed delay when using the cmd ui thing. I stumbled on a solution to make it work quicker--setup a timer. Not sure why but setting a timer of something like < half a second increases the cmdui response time. Just adding that 2 cents..
# 6 Re: OnUpdate(CCmdUI *pCmdUI) response too late for toolbar button
The way I set the busy flag is very straight forward:
void CTestDoc::OnFileSave()
{
m_bBusy = TRUE;
//CWnd *pFrame = AfxGetMainWnd();
//pFrame->SendMessageToDescendants(WM_IDLEUPDATECMDUI,
// (WPARAM)TRUE, 0, TRUE, TRUE);
FileSave();
m_bBusy = FALSE;
}
I did some more debugging on update mechanism and it does seem to work rightly for menu but just not the toolbar.
void CTestDoc::OnUpdateFileSave(CCmdUI *pCmdUI)
{
pCmdUI->Enable(!m_bBusy);
static int n;
n++;
TRACE("OnUpdateFileSave: [%d] %d\r\n", n, m_bBusy);
}
While the save is in progress and I bring down the File menu, I do see the above handled called and updating the menu correctly. Unfortunately this does not happen for the toolbar button when save is in progress even if I minimize and than maximize the application. If I don't do anything after save, I see the update handler is called for toolbar button only when save is complete and by than the value of m_bBusy is already FALSE.
I will try if I can produce this problem seperately so I can post it but I am going after why toolbar update handler is not called on time but menu item is.
# 7 Re: OnUpdate(CCmdUI *pCmdUI) response too late for toolbar button
In MFC menu item is updated whenever window is receiving WM_INITMENU message is received that is before menu becomes visible.
Other UI items are updated when application is in idle state.
By processing a long task, you simply block or delay this update by not allowing application to go into an idle state. That is In MFC menu item is updated whenever window is receiving WM_INITMENU message is received that is before menu becomes visible.
Other UI items are updated when application is in idle state.
By processing a long task, you simply block or delay this update by not allowing application to go into an idle state. That is why long processing should be performend in a separate thread.
Any other approach is not going to fix a problem.
why long processing should be performend in a separate thread.
Any other approach is artificial.
JohnCz at 2007-11-11 4:08:17 >

# 8 Re: OnUpdate(CCmdUI *pCmdUI) response too late for toolbar button
I have concocted a demo application for mocking long save routine.
Run demo and do not move mouse after pressing save button.
Move mouse or press any button on the keyboard after the beep and you will see button changing state immediately.
The reason for button not being updated is the fact that after save is done, application did not enter an idle state since.
Uncomment AfxGetMainWnd()->PostMessage line and run app again. This time, button is updated since thread placed a message in the apps queue and that allows application entering idle processing.
In a sample I have used WM_CANCELMODE just in case somebody popped a menu while saving code was executed.
JohnCz at 2007-11-11 4:09:12 >

# 9 Re: OnUpdate(CCmdUI *pCmdUI) response too late for toolbar button
Thats an excellent point! I have to use CTRL + S to produce that behaviour with mouse not on the toolbar because with mouse on toolbar the button always change the state..maybe need a super perfect click but I got the point, it could easily be overlooked!
I think m_bSaving should probably stay as member variable though and be passed to the thread function. That way when you switch the window, save would become available again accordingly. In the current configuration 'Save' retains its state once it disables across different doc/views. Thanks!