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

  • Today's enterprise datacenter can be one of the most complex business environments with dozens (for smaller business), hundreds (for larger and midsize business), even thousands (for hyperscale businesses) of servers that must be managed and monitored. At this level, just managing the cords can be challenging — let alone keeping up with the growing need for more agility and scalability within the datacenter. Simply put, companies are aggressively looking for less complexity and more agility from their …

  • Entire organizations suffer when their networks can't keep up and new opportunities are put on hold. Waiting on service providers isn't good business. In these examples, learn how to simplify network management so that your organization can better manage costs, adapt quickly to business demands, and seize market opportunities when they arise.

Most Popular Programming Stories

More for Developers

RSS Feeds

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