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

  • Read the ebook Hybrid Cloud & Data Fabric for Dummies to learn how a Data Fabric can ease data management complexity within a hybrid cloud and help you maximize the control of your data — from anywhere at any time. Find out how to: Seamlessly and dynamically move data across private and public cloud resources Keep data secure and minimize business disruptions …

  • With the cloud transforming application development and deployment — enabling organizations to improve flexibility, automate processes, and decrease time to market — some big questions remain. One of the most important issues an organization must address is how it can best employ the smarter tools and limitless scale that the cloud offers. One way that enterprises take advantage of the benefits of the cloud is by deploying their own private cloud. Read this white paper to learn how private clouds …

Most Popular Programming Stories

More for Developers

RSS Feeds

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