Update for Owner Drawn Menu with Icons (2)

WEBINAR: On-demand webcast

How to Boost Database Development Productivity on Linux, Docker, and Kubernetes with Microsoft SQL Server 2017 REGISTER >

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

  • The software-defined data center (SDDC) and new trends in cloud and virtualization bring increased agility, automation, and intelligent services and management to all areas of the data center. Businesses can now more easily manage the entire lifecycle of their applications and services via the SDDC. This Aberdeen analyst report examines how a strong foundation in both the cloud and internal data centers is empowering organizations to fully leverage their IT infrastructure and is also preparing them to be able …

  • Whether a mandate to secure all web and mobile apps comes from a newly enlightened CIO or in response to a major security breach, beginning even a small application security program can be a daunting task. How will you know how many digital assets you have, let alone their risk profile? In this webinar we explore how, using a cloud solution like Fortify on Demand, even the largest organizations can begin to scan apps immediately and rapidly scale an application security program. Identify and risk rank assets, …

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date