Using ON_UPDATE_COMMAND_UI with all controls in a Dialog

CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

From the previous messages in this thread, you
can see how it is possible to use the ON_UPDATE_COMMAND_UI macro
with Dialog boxes by overriding the PreTranslateMessage(MSG
*pMsg) and calling UpdateDialogControls(CCmdUI*, BOOL). However,
what has not been discussed so far and one reason why the App
Wizard does not offer the option of adding update handlers to any
controls in a dialog is that these controls are likely to require
more than just simple window enabling or disabling. As a result,
you might run into a couple of problems.

Consider a dialog with a CComboBox control, if all that is
required is to enable and disable this control depending on a
certain condition, then the ON_COMMAND_UPDATE_HANDLER provides a
convenient method to perform this operation:


void CMyDialog::OnUpdateMyComboBox(CCmdUI* pCmdUI)
{
pCmdUI->Enable(m_bShowCombo);
}

However, if it is also necessary to update the selection of the
CComboBox as well as enabling and disabling it then you might
code the following:


void CMyDialog::OnUpdateMyComboBox(CCmdUI* pCmdUI)
{
// Get the combo box
CComboBox* pMyCombo = (CComboBox *) pCmdUI->m_pOther;

// Update the selection according to our member variable
pMyCombo->SetCurSel(m_nSel);

pCmdUI->Enable(m_bShowCombo);
}

However, unfortunately the code above would lead you into all
sorts of trouble. First of all, every time the
UpdateDialogControls(CCmdUI*, BOOL) function is called (which
will ultimately send out the desired ON_UPDATE_COMMAND_UI
messages), the ComboBox as a result of the code in its update
handler will change its current selection. All this is going to
cause enough flicker to make it an irritating problem. The
solution is as simple as is obvious; don’t update the
selection if it will result in the same selection being made.


void CMyDialog::OnUpdateMyComboBox(CCmdUI* pCmdUI)
{
CComboBox* pMyCombo = (CComboBox *) pCmdUI->m_pOther;

int nCurSel = pMyCombo->GetCurSel();

if (nCurSel != m_nSel)
pMyCombo->SetCurSel( m_nSel );

pCmdUI->Enable(m_bShowCombo);
}

Albeit that the above
scenario isn’t going to occur very often there are times when
something similar will be required. However, we will still have
another more immediate problem; that is, the user will not be
able to make a selection using the ComboBox. Try it and you’ll
see why. If they try to, ON_UPDATE_COMMAND_UI messages will
spring from all over the place and our combo box will be
constantly trying to set the current selection.

The solution to this problem is slightly more taxing, but only
just. Have a look at the following code:


// Does the current window have the focus
bool CMyDialog::HasFocus(const CWnd* pWndCtrl) const
{
ASSERT(::IsWindow(pWndCtrl->m_hWnd));
// if (pWndCtrl->m_hWnd == GetFocus()->m_hWnd) is insufficient, so…

// Get window with focus
CWnd* pFocusWnd = GetFocus();

// Ensure its not null and is a window. Can occur if application loses and regains focus
if (pFocusWnd == NULL || !::IsWindow(pFocusWnd->m_hWnd))
return true;

// Don’t update if the control has the focus
if (pFocusWnd->GetDlgCtrlID() == pWndCtrl->GetDlgCtrlID())
return true;

return false;
}

So now, all that is necessary is to place a call to the
HasFocus() function (which does a bit more than checking for just
focus) and do nothing if we do have the focus.


void CMyDialog::OnUpdateMyComboBox(CCmdUI* pCmdUI)
{
CComboBox* pMyCombo = (CComboBox *) pCmdUI->m_pOther;

If (HasFocus(pMyCombo)
return;

int nCurSel = pMyCombo->GetCurSel();

if (nCurSel != m_nSel)
pMyCombo->SetCurSel( m_nSel );

pCmdUI->Enable(m_bShowCombo);
}

So with some very simple
code, you can update all the controls in your dialog. If you only
have a few controls then it really isn’t worth it. However, if
you have a fair few of them and in cases where their state
changes regularly and perhaps even relies on the state of other
controls in the dialog this could be a good way to go. Simply it
is as follows:

Don’t update if you have the focus
Don’t update if you aren’t changing any values

The demo exe and source
below use the ON_UPDATE_COMMAND_UI macro with a little more
vigour. The contents of one Combo box is updated to reflect the
selection in another, CEdits perform similar things as other
controls. Have a look why dont you.

Caveat Emptor

Oh yes the But…I almost forgot the But… But,
ON_UPDATE_COMMAND_UI handling is done during your application
OnIdle() function. If you consume loads of on idle time
processing your handlers, you may find Windows gets a little fed
up and the HDD will go into paging overdrive. As it happens,
windows has some of its own stuff to do during OnIdle and if it
doesn’t get to do it… Saying that though, I’ve never had any
problems and neither should you if keep your update handlers on
the light side.

Download demo project (.exe) – 6 KB

Download source – 11 KB

Date Last Updated: January 25, 1999

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read