PRB: MeasureItem Not Called for Popup Item on Owner-Draw Menu

ID: Q143209


The information in this article applies to:
  • The Microsoft Foundation Classes (MFC), included with:
    • Microsoft Visual C++, 32-bit Editions, versions 1.0, 2.0, 2.1, 2.2, 4.0
    • Microsoft Visual C++ for Windows, 16-bit edition, versions 1.0, 1.5, 1.51, 1.52


SYMPTOMS

The CMenu::MeasureItem() function for an owner-draw menu isn't called for those menu items that bring up submenus.


CAUSE

This is a limitation of the self-drawing capability of MFC owner-draw menus.


RESOLUTION

For owner-draw menus that contain sub-popup menus, handle the WM_MEASUREITEM in the owning window. See the "Sample Code" section in this article for an example.


STATUS

This behavior is by design.


MORE INFORMATION

A menu item that brings up a submenu has no real ID associated with it. Instead the ID for this popup placeholder is actually the HMENU for the submenu associated with that item. As for all owner-draw menu items, Windows will send a WM_MEASUREITEM message to the application, specifying the address of a MEASUREITEMSTRUCT structure in lParam. The application should fill in this structure with the dimensions of the menu item. Now because the submenu item has an HMENU instead of an ID, this is the value that is passed in the idFrom variable of this structure. Essentially, an application that handles this message must recognize when this is an HWND for a valid submenu item. As of MFC 4.0, MFC's implementation of CWnd::OnMeasureItem() does not make this determination correctly.

An examination of the MFC source will reveal the problem. When CWnd::OnMeasureItem() is called by the receipt of this message, it uses FindPopupMenuFromID() to find the menu associated with a particular ID, so that the call pMenu->MeasureItem(...) can be made. Unfortunately FindPopupMenuFromID() does not check the case where the ID might be an HMENU. It will always return NULL in this case; therefore, the call to MeasureItem() will never be made.

Sample Code

The following sample code demonstrates how to implement OnMeasureItem when the menu item in question is a submenu. m_hMenuSub is a member variable that was initialized when the menu was created. If the item is not a submenu, the MFC self-drawing menu code can still be used.

/* Compile options needed:  Default
*/ 
void COwnerWindow::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT
                                                  lpMeasureItemStruct)
{
    if ( lpMeasureItemStruct->CtlType == ODT_MENU &&
         IsMenu((HMENU)lpMeasureItemStruct->itemID) &&
         lpMeasureItemStruct->itemID == (UINT)m_hMenuSub )
    {
        // MFC's self-drawing won't work in this case
        // go ahead and handle it here
        lpMeasureItemStruct->itemWidth = 100;
        lpMeasureItemStruct->itemHeight = 20;
    }
    else
        // let MFC's self-drawing handle it
        CFrameWnd::OnMeasureItem(nIDCtl, lpMeasureItemStruct);
} 

© Microsoft Corporation 1999, All Rights Reserved.
Contributions by Jason Strayer, Microsoft Corporation

Additional query words: 1.00 1.50 2.50 2.51 2.52 2.00 2.10 2.20 3.00 3.10 3.20 4.00

Keywords : kbcode kbMFC KbUIDesign kbVC
Version : 1.00 1.50 1.51 1.52 | 1.00 2.00
Platform : NT WINDOWS
Issue type :


Last Reviewed: December 3, 1999
© 2000 Microsoft Corporation. All rights reserved. Terms of Use.