Update for Owner Drawn Menu with Icons (2)

This menu is another modification of owner draw menus (#2 if you want to know). I have corrected an error I found (use of uninitialized variable in DrawItem), change item measurement (now the height is the bigger from icon height or menu height) and changed the menu concept from using separate icons for each item to use of image list (CImageList) so all the icons are in one bitmap. For more information see original article by Ben Ashley

What's new

  • Icon size is not determined every time it's needed but is stored in member variables
  • Fixed few unnecesary lines of code

What to use them ?

To be able to use owner draw popup menu items it is neccesary to add following to the main window class:
In the message map:
ON_WM_MEASUREITEM()
In the declaration (header) file:
afx_msg void OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct);
And in the definition (source) file:

static CMenu* FindPopupMenuFromID(CMenu* pMenu, UINT nID)
{
	ASSERT_VALID(pMenu);
	// walk through all items, looking for ID match
	UINT nItems = pMenu->GetMenuItemCount();
	for (int iItem = 0; iItem < (int)nItems; iItem++)
	{
		CMenu* pPopup = pMenu->GetSubMenu(iItem);
		if (pPopup != NULL)
		{
			// recurse to child popup
			pPopup = FindPopupMenuFromID(pPopup, nID);
			// check popups on this popup
			if (pPopup != NULL)
				return pPopup;
		}
		else if (pMenu->GetMenuItemID(iItem) == nID || (UINT)pMenu->GetSafeHmenu() == nID)
		{
			// it is a normal item inside our popup
			pMenu = CMenu::FromHandlePermanent(pMenu->m_hMenu);
			return pMenu;
		}
	}
	// not found
	return NULL;
}

void CMainWnd::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
	if (lpMeasureItemStruct->CtlType == ODT_MENU)
	{
		ASSERT(lpMeasureItemStruct->CtlID == 0);
		CMenu* pMenu;

		_AFX_THREAD_STATE* pThreadState = AfxGetThreadState();
		if (pThreadState->m_hTrackingWindow == m_hWnd)
		{
			// start from popup
			pMenu = CMenu::FromHandle(pThreadState->m_hTrackingMenu);
		}
		else
		{
			// start from menubar
			pMenu = GetMenu();
		}

		pMenu = FindPopupMenuFromID(pMenu, lpMeasureItemStruct->itemID);
		if (pMenu != NULL)
			pMenu->MeasureItem(lpMeasureItemStruct);
		else
			TRACE1("Warning: unknown WM_MEASUREITEM for menu item 0x%04X.\n", lpMeasureItemStruct->itemID);
	}
	else
	{
		CWnd* pChild = GetDescendantWindow(lpMeasureItemStruct->CtlID, TRUE);
		if (pChild != NULL && pChild->SendChildNotifyLastMsg())
			return;     // eaten by child
	}
	// not handled - do default
	Default();
}

Download code 5K

Last updated on: August 27, 1998.



Comments

  • good

    Posted by xxl19792003 on 08/24/2010 03:33am

    good

    Reply
  • Thanks to Jaroslav Pisk !

    Posted by Legacy on 01/29/2004 12:00am

    Originally posted by: RyuSungMin

    Modified FindMenuItem returns pointer of submenu and uId
    CMenu* CCatDDEMgr::FindMenuItem(CMenu* pMenu, CString MenuString, UINT& uId)
    {
    ASSERT_VALID(pMenu);
    int cnt = pMenu->GetMenuItemCount();
    for(int i = 0; i < cnt; i++)
    {
    CString str;
    CMenu* pPopup = pMenu->GetSubMenu(i);
    if(pPopup)
    {
    if (pPopup->GetMenuString(i, str, MF_BYPOSITION) &&
    (strcmp(str, MenuString) == 0))
    {
    uId = pPopup->GetMenuItemID(i);
    return pPopup;
    }
    else
    {
    pPopup = FindMenuItem(pPopup, MenuString, uId);
    if(pPopup)
    {
    return pPopup;
    }
    }
    }
    else
    if (pMenu->GetMenuString(i, str, MF_BYPOSITION) &&
    (strcmp(str, MenuString) == 0))
    {
    uId = pMenu->GetMenuItemID(i);
    return pMenu;
    }
    }
    return NULL;
    }

    Reply
  • One logical error

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

    Originally posted by: Paul Nurminsky

    Your code contain a logical error
    
    if the item with nID is a submenu
    FindPopupMenuFromID will return the submenu instead of menu.
    To fix this problem you should :
    static CMenu* FindPopupMenuFromID(CMenu* pMenu, UINT nID)
    {
    ASSERT_VALID(pMenu);
    // walk through all items, looking for ID match
    UINT nItems = pMenu->GetMenuItemCount();
    for (int iItem = 0; iItem < (int)nItems; iItem++)
    {
    CMenu* pPopup = pMenu->GetSubMenu(iItem);
    if (pPopup != NULL)
    {
    if((UINT)pPopup->GetSafeHmenu() == nID )
    {
    //!!! return our menu
    return pMenu;
    }
    // recurse to child popup
    pPopup = FindPopupMenuFromID(pPopup, nID);
    // check popups on this popup
    if (pPopup != NULL)
    return pPopup;
    }
    else
    if (pMenu->GetMenuItemID(iItem) == nID )
    {
    // it is a normal item inside our popup
    pMenu = CMenu::FromHandlePermanent(pMenu->m_hMenu);
    return pMenu;
    }
    }
    // not found
    return NULL;
    }

    Reply
  • Update to CMenuSpawn

    Posted by Legacy on 11/02/1998 12:00am

    Originally posted by: Alex Waddell

    The Menu Spawn class currently only supports checked menu items if there is no bitmap associated with the menu item. Add this line to the Draw() routine to enable "checked" menu items for items that have a bitmap.

    Add this line in to the Draw() and you can get "checked" items with the bitmap (instead of just checked items without bitmaps).

    if (pItem->iImageIdx >= 0)
    {
    int ay = (rcImage.Height() - szImage.cy) / 2;
    int ax = (rcImage.Width() - szImage.cx) / 2;
    >> if (bChecked)
    >> pDC->DrawEdge (rcImage, BDR_SUNKENOUTER, BF_RECT);
    >> else if (bSelect && bEnab)
    pDC->Draw3dRect(rcImage,cr3dHilight,cr3dShadow);
    else
    if (!bBackBitmap) pDC->Draw3dRect(rcImage,crMenu,crMenu);

    if (bEnab)
    {
    ...
    }

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

Top White Papers and Webcasts

  • Live Event Date: August 20, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT When you look at natural user interfaces as a developer, it isn't just fun and games. There are some very serious, real-world usage models of how things can help make the world a better place – things like Intel® RealSense™ technology. Check out this upcoming eSeminar and join the panel of experts, both from inside and outside of Intel, as they discuss how natural user interfaces will likely be getting adopted in a wide variety …

  • Protecting business operations means shifting the priorities around availability from disaster recovery to business continuity. Enterprises are shifting their focus from recovery from a disaster to preventing the disaster in the first place. With this change in mindset, disaster recovery is no longer the first line of defense; the organizations with a smarter business continuity practice are less impacted when disasters strike. This SmartSelect will provide insight to help guide your enterprise toward better …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds