Use the Status Bar to Describe How To Enable Menu Commands and Toolbar Buttons | CodeGuru

Use the Status Bar to Describe How To Enable Menu Commands and Toolbar Buttons

Environment: VC6, W98, NT4 One of the most frustrating scenarios I have as a user is trying to determine how to enable a disabled menu item. You find the command you want to use, but it is grayed out with no indication on what you need to do to enable it. So now as a […]

Written By
CodeGuru Staff
CodeGuru Staff
Oct 3, 2001
2 minute read
CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More

Environment: VC6, W98, NT4

One of the most frustrating scenarios I have as a user is trying to determine how to
enable a disabled menu item. You find the command you want to use, but it is grayed
out with no indication on what you need to do to enable it.

So now as a developer, I put the following code in all of my applications. It uses
the text pane of the status bar (where the “Ready” text appears) to indicate how to
enable disabled menu items when the user moves the cursor over them. It reuses the
ON_UPDATE_COMMAND_UI handlers that you’ve already written to enable/disable menu items.
The only additional step after including these code segments is to add a “\nEnable Text”
to the end of each menu item that indicates how to enable the menu item. For example,

Step 1: Add method declarations to the frame window’s header file

In your CFrameWnd-derived class (e.g. CMainFrame), add the following declaration to the
header file as a protected method:

// This method overrides the CFrameWnd’s handler for the set
// message pane for the status bar.  This code was taken from
// CFrameWnd’s method and modified.  Code was added to
// determine if the control is enabled or not and if disabled
// then indicate how to enable the control or menu item.
LRESULT OnSetMessageString(WPARAM wParam, LPARAM lParam);

Step 2: Include an MFC header file

Add the following include file to the CFrameWnd-derived implementation file (e.g.
MainFrm.cpp):

#include   // for WM_SETMESSAGESTRING and AfxLoadString

Step 3: Add the OnSetMessageString message map

In the CFrameWnd-derived implementation file (e.g. MainFrm.cpp), add the following code
outside of the AFX_MSG_MAP brackets in the message map section (i.e. between
BEGIN_MESSAGE_MAP and END_MESSAGE_MAP):

// Override the setting of the text in the message pane
// of the status bar
ON_MESSAGE(WM_SETMESSAGESTRING, OnSetMessageString)

Step 4: Add the implementation of OnSetMessageString and a helper function

The following code uses the ON_UPDATE_COMMAND_UI handlers already written elsewhere
in the code to determine whether the menu item is enabled or disabled. It gets the
“how to enable” text from the string table for the associated menu item. You will need
to add a third text string for each menu item as detailed in the next step.

// Returns the offset of the given menu item’s ID or -1
// if not found
int GetMenuPosition( CMenu* in_menu, DWORD in_menuItemID )
{
   if ( NULL == in_menu )
      return -1;
   UINT  max = in_menu->GetMenuItemCount();
   for ( UINT i = 0; i < max; i++ )
      if ( in_menuItemID == in_menu->GetMenuItemID( i ) )
         return i;
   return -1;
}

// This method overrides the CFrameWnd’s handler for the
// set message pane for the status bar.  This code was
// taken from CFrameWnd’s method and modified. Code was
// added to determine if the control is enabled or not
// and if disabled then indicate how to enable the control
// or menu item.
LRESULT CMainFrame::OnSetMessageString(WPARAM wParam,
                                       LPARAM lParam)
{
  UINT nIDLast = m_nIDLastMessage;
  m_nFlags &= ~WF_NOPOPMSG;

  // Determine if the menu item that matches the wParam
  // is enabled.  If not, then indicate how to enable it.
  //
  // Load the main frame’s menu.  Note we can’t use
  // GetMenu because the menu may not have been loaded
  // yet and we need to indicate how to enable the toolbar
  // buttons as well.
  CMenu mainMenu;
  if ( 0 != wParam && mainMenu.LoadMenu( IDR_MAINFRAME ) )
  {
    // Go through each submenu of the main frame looking
    // for the ID passed in.
    UINT  max = mainMenu.GetMenuItemCount();
    for ( UINT i = 0; i < max; i++ )
    {
      CMenu*   pMenu = mainMenu.GetSubMenu( i );
      if ( NULL != pMenu )
      {
        // We need to build a CCmdUI to be used when
        // determining if the item is enabled.
        CCmdUI   state;
        state.m_pMenu = pMenu;
        state.m_nIndexMax = pMenu->GetMenuItemCount();
        state.m_nIndex = GetMenuPosition( pMenu, wParam );

        // If the ID passed in is found in the submenu,
        // then have this frame window enable/disable it.
        if ( -1 != state.m_nIndex )
        {
          // First disable the menu item in case it is not
          // handled.
          pMenu->EnableMenuItem( wParam, MF_GRAYED );
            
          // Invoke the UPDATE COMMAND UI handler for this
          // menu item.
          this->OnCmdMsg(wParam,
                         CN_UPDATE_COMMAND_UI,
                         &state,
                         NULL);

          // Get the state of the menu item.
          UINT  menuState = pMenu->GetMenuState( wParam,
                                                 MF_BYCOMMAND );

          // If the menu item is disable or grayed out, then
          // get the text to indicate how to enable it.
          if ( ( 0xFFFFFFFF != menuState ) &&
               ( ( MF_DISABLED & menuState ) ||
               ( MF_GRAYED & menuState ) ) )
          {
            TCHAR szFullText[256];
            CString strEnableText;
            CWnd* pMessageBar = GetMessageBar();

            // Load the string for this ID.  The string after
            // the second ‘\n’ indicates how to enable.
            AfxLoadString(wParam, szFullText);
            AfxExtractSubString(strEnableText,
                                szFullText,
                                2,
                                ‘\n’);

            // If there is enable text, then set the message
            // bar to it, otherwise let the parent class handle it.
            if ( 0 != strEnableText.GetLength() )
            {
              pMessageBar->SetWindowText( strEnableText );
              m_nIDLastMessage = (UINT)wParam; // new ID (or 0)
              m_nIDTracking = (UINT)wParam;    // so F1 on toolbar
                                               // buttons work
              return nIDLast;
            }
          }
        }
      }
    }
  }
  return CFrameWnd::OnSetMessageString( wParam, lParam );
}

Step 5: Add a \n and “how to enable” text to each menu item

The last step in this process is to open the Resource Editor, select the IDR_MAINFRAME
menu, display the properties for each menu item, and add a backslash-n (\n) and the
“how to enable text” to the end of each Prompt. The “how to enable” text might state
what objects need to be selected in the view to enable that command.

Since toolbar buttons use the same resource IDs as the menu items, there is nothing
additional you need to do to display the “how to enable” text when those buttons are
grayed out.

Downloads

Download demo project – 19 Kb

CodeGuru Logo

CodeGuru covers topics related to Microsoft-related software development, mobile development, database management, and web application programming. In addition to tutorials and how-tos that teach programmers how to code in Microsoft-related languages and frameworks like C# and .Net, we also publish articles on software development tools, the latest in developer news, and advice for project managers. Cloud services such as Microsoft Azure and database options including SQL Server and MSSQL are also frequently covered.

Property of TechnologyAdvice. © 2026 TechnologyAdvice. All Rights Reserved

Advertiser Disclosure: Some of the products that appear on this site are from companies from which TechnologyAdvice receives compensation. This compensation may impact how and where products appear on this site including, for example, the order in which they appear. TechnologyAdvice does not include all companies or all types of products available in the marketplace.