Using ON_UPDATE_COMMAND_UI with menu items and controls

.

Warning: The class presented in this article uses the undocumented MFC member function CCmdUI::DoUpdate

Example project with dialog using this technique

You will have used the ON_UPDATE_COMMAND_UI macro in MFC with your various menu commands. This macros is used to implement the message handler for the UPDATE_COMMAND_UI "message" sent by the MFC framework. This message allows you to set the state (enabled/disabled, checked/unchecked etc) of your menu and toolbar items by calling the various OnUpdateXXX functions that you supply.

Quite often, it would be useful to use this same "auto-update" facility with the controls of a dialog box. Unfortunately, MFC does not provide this functionality for you. In this article, I present a dialog class, derived from CDialog, that allows you to use the familiar ON_UPDATE_COMMAND_UI macros with any control on a dialog box.

This approach has the advantage of centralising your dialog controls state logic and is very useful for complicated dialogs where the state of many controls is determined by the state of other controls on the dialog.

The class, CCmdUIDialog, implements the necessary code to call your OnUpdateXXX functions. You simply derive your dialog class from CCmndUIDialog instead of CDialog, and manually add the ON_UPDATE_COMMAND_UI macros to your class.

Class declaration:

#if !defined(AFX_CMDUIDIALOG_H__7D35F4B8_7531_11D1_8FA7_000000000000__INCLUDED_)
#define AFX_CMDUIDIALOG_H__7D35F4B8_7531_11D1_8FA7_000000000000__INCLUDED_

#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
// CmdUIDialog.h : header file
// 

/////////////////////////////////////////////////////////////////////////////
// CCmdUIDialog dialog

class CCmdUIDialog : public CDialog
{
// Construction
public:
	CCmdUIDialog(LPCTSTR lpszTemplateName, CWnd* pParentWnd = NULL);
	CCmdUIDialog(UINT nIDTemplate, CWnd* pParentWnd = NULL);
	CCmdUIDialog();
	BOOL ContinueModal();

// Implementation
protected:

	// Generated message map functions
	//{{AFX_MSG(CCmdUIDialog)
	// NOTE: the ClassWizard will add member functions here
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

//{{AFX_INSERT_LOCATION}}
// Microsoft Developer Studio will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_CMDUIDIALOG_H__7D35F4B8_7531_11D1_8FA7_000000000000__INCLUDED_)

Class Implementation:

// CmdUIDialog.cpp : implementation file
//

#include "stdafx.h"
#include "delme.h"
#include "CmdUIDialog.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CCmdUIDialog dialog


CCmdUIDialog::CCmdUIDialog(LPCTSTR lpszTemplateName, CWnd* pParentWnd)
	: CDialog(lpszTemplateName, pParentWnd)
{
}

CCmdUIDialog::CCmdUIDialog(UINT nIDTemplate, CWnd* pParentWnd)
	: CDialog(nIDTemplate, pParentWnd)
{
}

CCmdUIDialog::CCmdUIDialog()
{
}


BOOL CCmdUIDialog::ContinueModal()
{
	// Iterate all child windows and instruct to update themselves
	CWnd* pWndChild=GetWindow(GW_CHILD);
	int iIndex=0;
	while (NULL!=pWndChild)
	{

		CCmdUI state;
		state.m_nID=::GetWindowLong(*pWndChild, GWL_ID);
		state.m_nIndex=iIndex++;
		state.m_pOther=pWndChild;

		// ***CCmdUI::DoUpdate is undocumented MFC***
		state.DoUpdate(this, FALSE);

		pWndChild=pWndChild->GetWindow(GW_HWNDNEXT);
	}

	// Must call the base class
	return CDialog::ContinueModal();
}

BEGIN_MESSAGE_MAP(CCmdUIDialog, CDialog)
	//{{AFX_MSG_MAP(CCmdUIDialog)
		// NOTE: the ClassWizard will add message map macros here
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CCmdUIDialog message handlers



To use the class and update handlers

First, derive your dialog class from CCmdUIDialog instead of CDialog. Next, add update command handlers for each control you require this feature for, using the following technique:

Enter the name of the update function in the protected section of your dialog header file

Each update function has the signature void OnUpdateXXX(CCmdUI* pCmdUI); where XXX might describe the control for this handler. These update functions should be places immediatley after the //}}AFX_MSG comment in your header file. This will ensure that all of the command handlers are grouped together.

Add a ON_UPDATE_COMMAND_UI macro in your dialog source (.cpp) file.

This macro takes the resource ID of the dialog control and the name if the update function to call. For a dialog control called IDC_CHECK1 with a handler function called OnUpdateCheck1 , the macro entry would read

	ON_UPDATE_COMMAND_UI(IDC_CHECK1, OnUpdateCheck1)

This handler should appear between the BEGIN_MESSAGE_MAP and END_MESSAGE_MAP macros and after the //}}AFX_MSG_MAP entry.

Implement the update function

Implement the logic you require in your update function, using the passed CCmdUI pointer to update your dialog control. The passed CCmdUI pointer is based on the dialog control that this habdler is called for.

The attached example application displays a dialog that used the technique described here and also shows how to update more than one control using the same handler function.

Update

Thanks go to Jeff Marino for pointing out this better approach.

Jeff Marino has pointed out an MFC function that handles ON_UPDATE_COMMAND_UI with dialogs and does not require the derived dialog class to call any undocumented MFC stuff. The function is CWnd::UpdateDialogControls.

This just goes to show how large MFC is and that there is a wealth of functionality if only you can find it and how useful your resource is.

To use the UpdateControls function, overload ONE of the PreTranslateMessage or ContinueModal functions like this:

BOOL ::PreTranslateMessage( MSG* pMsg )
{
UpdateDialogControls( this, TRUE );
return CDialog::PreTranslateMessage( pMsg );
}
or
BOOL ::ContinueModal( )
{
UpdateDialogControls( this, TRUE );
return CDialog::ContinueModal( );
}

One should bear in mind that ContinueModal is called about four to five times as often as PreTranslateMessage.



Comments

  • button problem

    Posted by Ningappa on 04/18/2013 04:56am

    in your example, let us take "tranfer" Button, If i want to use MessageBox("SOMETHING") on click upon "Tranfer" button; how will u do that?

    Reply
  • More concessions with herveleger, more take someone aback!

    Posted by wellslifwsi on 03/28/2013 04:21pm

    herve leger outlet herve leger replica herve leger dresses herve leger outlet cheap herve leger dress herve leger outlet replica herve leger dress iphone 5 sale cheap iphone 5 sale iphone unlocked for sale

    Reply
  • More concessions with herveleger, more take prisoner napping!

    Posted by wolemrfjbu on 03/24/2013 01:57pm

    herve leger outlet herve leger outlet herve leger on sale herve leger outlet herve leger dresses herve leger outlet herve leger outlet iphone 4s for sale cheap iphone 4g sale iphone 5 sales

    Reply
  • Use OnInitMenuPopup, its easy

    Posted by yountmg on 03/21/2007 12:31am

    I know this is a little late (for other people like me who want a easy fix), the popup Initialization message still gets sent. I just added in a ON_WM_INITMENUPOPUP() to the the message map outside the automatic update area so it stays in and the matching virtual function. void CMyDlg::OnInitMenuPopup( CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu ) { CDialog::OnInitMenuPopup( pPopupMenu, nIndex, bSysMenu ); // your menu 0:file 1:edit 2:mine if ( nIndex == 2 && !bSysMenu ) { if ( m_bItem1 ) pPopupMenu->CheckMenuItem(ID_M2_I1, MF_CHECKED); else pPopupMenu->CheckMenuItem(ID_M2_I1, MF_UNCHECKED); if ( m_bItem2 ) pPopupMenu->CheckMenuItem(ID_M2_I2, MF_CHECKED); else pPopupMenu->CheckMenuItem(ID_M2_I2, MF_UNCHECKED); } }

    Reply
  • to retirve data from linked list

    Posted by VickyZeal on 01/27/2005 08:22am

    does any one know how to retrieve data from linked list to list box

    Reply
  • How do you disable a control id (IDC) from a dialog box

    Posted by Legacy on 11/27/2001 12:00am

    Originally posted by: George Azzopardi

    Is there some simple way to disable a control, e.g. a radio button or edit box, from a dialog box.  I'm creating a Dialog box using an MFC dll.  Can someone send me a sample code.
    

    Reply
  • disadvantage of using UpdateDialogControls

    Posted by Legacy on 02/14/2001 12:00am

    Originally posted by: Rudy Schalk

    Unless I misunderstand, one major disadvantage of using UpdateDialogControls is that you cannot selectively choose to have only certain controls update automatically. So in cases where you may only want to update several controls in your dialog, the original method would be preferable.

    Reply
  • Need Help on my application program

    Posted by Legacy on 02/12/2001 12:00am

    Originally posted by: Bashar Amin

    Hello,
    I have been trying to write a program for a user interface software. I am thinking of using a main window with some menu bar, dialog boxes and some ActiveX controls.
    Could you please give me some idea about how I can proceed on this project? I appretiate your help.

    Bashar Amin
    Oshkosh, WI

    Reply
  • Update text/status of TrackPopupMenu

    Posted by Legacy on 10/30/2000 12:00am

    Originally posted by: shail srivastav

    Hi,
    I used trackpopoupmenu inside my dialog and i want to enable/disable menu items at run time. ON_UPDATE_COMMAND_UI doesm't seem to work in this case.

    Thanks in advance.
    -Shail

    Reply
  • How to add menubar in a dialog box?

    Posted by Legacy on 10/16/2000 12:00am

    Originally posted by: Anbumani

    Hello,
    If any boday knows about how to add a menu bar in a dialog box..please let me know..
    thankx in advance.
    -anbumani@india.com

    Reply
  • Loading, Please Wait ...

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: December 11, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT Market pressures to move more quickly and develop innovative applications are forcing organizations to rethink how they develop and release applications. The combination of public clouds and physical back-end infrastructures are a means to get applications out faster. However, these hybrid solutions complicate DevOps adoption, with application delivery pipelines that span across complex hybrid cloud and non-cloud environments. Check out this …

  • CentreCorp is a fully integrated and diversified property management and real estate service company, specializing in the "shopping center" segment, and is one of the premier retail service providers in North America. Company executives travel a great deal, carrying a number of traveling laptops with critical current business data, and no easy way to back up to the network outside the office. Read this case study to learn how CentreCorp implemented a suite of business continuity services that included …

Most Popular Programming Stories

More for Developers

RSS Feeds