• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 607
  • Last Modified:

Owner-draw menu: how to catch clicks on menu items


I created an owner-draw menu (overwriting DrawItem and MeasureItem).  Now it shows fine, but no mouse clicks are passed down to the dialog.  

Two messages, COMMAND and UPDATE_COMMAND_UI, which worked for the standard CMenu, are no longer functional.

I tried filtering by message ID through over-writing WindowProc and OnCommand, but none receive notifications for my menu items.

I vaguely remember seeing something somewhere about this, but for the life of me can't find it now.

Thanks in advance!!
0
aquarius003
Asked:
aquarius003
  • 7
  • 5
1 Solution
 
aquarius003Author Commented:
I'm not sure if this is relevant, but my app is CDialog-derived.
0
 
AndyAinscowCommented:
CDialog based - very important.  The default menu (toolbar) handlers don't work automatically for them.

(For the future consider an SDI based app with a CFormView as the view - looks like a dialog BUT the menu/toolbar support is implemented by default).

Is the menu a context menu or a menu on the dialog like an SDI/MDI based app?
0
 
AndyAinscowCommented:
For a context menu I once found this piece of code (very similar to that in the MFC routing mechanism)

void CmdRouteMenu(CWnd* pWnd,CMenu* pPopupMenu)
{
      CCmdUI state;
      state.m_pMenu = pPopupMenu;
      state.m_pParentMenu = pPopupMenu;
      state.m_nIndexMax = pPopupMenu->GetMenuItemCount();

      for (state.m_nIndex = 0;
           state.m_nIndex < state.m_nIndexMax;
           state.m_nIndex++)
      {
            state.m_nID = pPopupMenu->GetMenuItemID(state.m_nIndex);

            // menu separator or invalid cmd - ignore it
            if (state.m_nID == 0) continue;

            if (state.m_nID == (UINT)-1)
            {
                  // possibly a popup menu, route to child menu if so
                  CMenu* pSub=pPopupMenu->GetSubMenu(state.m_nIndex);
                  if(pSub) CmdRouteMenu(pWnd,pSub);
            }
            else
            {
                  // normal menu item, Auto disable if command is
                  // _not_ a system command.
                  state.m_pSubMenu = NULL;
                  state.DoUpdate(pWnd, FALSE);
            }
      }
}


usage, eg from a control
      CPoint point;
      GetCursorPos(&point);

      CMenu menu;
      VERIFY(menu.LoadMenu(IDR_POPUP_XYZ));

      CMenu* pPopup = menu.GetSubMenu(0);
      ASSERT(pPopup != NULL);
      CWnd* pWndPopupOwner = this;
      CmdRouteMenu(pWndPopupOwner, pPopup);
      pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, pWndPopupOwner);
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
AndyAinscowCommented:
For a main menu bar you need to handle the WM_KICKIDLE message

in .h file
      LRESULT OnKickIdle(WPARAM, LPARAM);

in .cpp file
#include "afxpriv.h"   //required for definition of WM_KICKIDLE

in message map block
      ON_MESSAGE(WM_KICKIDLE, OnKickIdle)

and
LRESULT CMyDlg::OnKickIdle(WPARAM, LPARAM)
{
CMenu* pMainMenu = GetMenu();
 CCmdUI cmdUI;
 for (UINT n = 0; n < pMainMenu->GetMenuItemCount(); ++n)
 {
  CMenu* pSubMenu = pMainMenu->GetSubMenu(n);
  cmdUI.m_nIndexMax = pSubMenu->GetMenuItemCount();
  for (UINT i = 0; i < cmdUI.m_nIndexMax;++i)
  {
   cmdUI.m_nIndex = i;
   cmdUI.m_nID = pSubMenu->GetMenuItemID(i);
   cmdUI.m_pMenu = pSubMenu;
   cmdUI.DoUpdate(this, FALSE);
  }
 }
 return TRUE;
}
0
 
DanRollinsCommented:
Nice summary Andy!
0
 
aquarius003Author Commented:
Andy:

I'm dealing with a standard (not context/pop-up) menu.

Regarding your note to handle WM_KICKIDLE - isn't this related only to updates (ON_UPDATE_COMMAND_UI).

It does not do anything for handling actual mouse clicks on specific items. I need to handle ON_COMMAND.
0
 
AndyAinscowCommented:
KickIdle - yes concerning menu updating BUT you did say in the question you needed that.

Here I can create a menu on a dialog and the code I supplied does cope with both updating and mouse clicks.  I suspect you have crippled something else.

Step 1.
Try it with a menu that is not owner draw.  (It should work).

Step 2.
Check the Menu ID's - maybe you aren't trapping the owner draw menus because the ID's are somehow different.

It's now late in the evening here, I'll be online tomorrow.

ps. Overwriting the WindowProc is NOT necessary, remove it, maybe you have an error there.
0
 
aquarius003Author Commented:
Completely irrelevant side-note: you live quite close to my sister, she is in St. Gallen! :)

I'll try to figure out what's going wrong. I removed WindowProc over-writing, that's not the problem.

The main reason for using owner-drawn menu is that my main dialog has bitmap background, and I couldn't leave the standard menu gray and mis-matched with the rest. It was functioning perfectly well, until I switched it for the owner-drawn (which over-writes only MeasureItem and DrawItem, so I don't see what I'm screwing up).

In any case, thanks for the suggestion, off I go to comb through the code again...
0
 
AndyAinscowCommented:
Half an hour away.
0
 
AndyAinscowCommented:
Just for confirmation.
From what you say the custom menu does display correctly.  
When you click a menu item the menu is dismissed.  
(Same for keyboard selection/activation?).


Maybe you could check the obvious - the Menu ID's haven't been subtly changed, and the less obvious - the menu events are going to the dialog (somehow changed the recipient window to NULL for example).  (Spy++ can be used to monitor messages being passed back and forth).
0
 
aquarius003Author Commented:
Sorry for the delay, I was in a different dimension for a while!

Yes, the custom menu draws/displays correctly, except that no events are passed to it (clicking dismisses it, as you mention).

IDs are fine, no duplicates.

I spent some time scratching my head, and then searched around and came across this: http://www.codeguru.com/cpp/controls/menu/article.php/c3719/

It has other issues, but doesn't have the problem I've seen. I'll fiddle around it for a while, and see if I have better luck. Will keep you posted, if I actually solve the problem.

Thank you very much!
0
 
AndyAinscowCommented:
Can you post the code where you replace the standard menu with your owner draw menu.
0
 
aquarius003Author Commented:
Unfortunately, I seem to have lost/deleted the test app that was the reason for this thread. :(

On a brighter note, I've managed to do what I need, mostly thanks to the details provided at the above mentioned site: http://www.codeguru.com/cpp/controls/menu/article.php/c3719/

You can download a sample application from http://ca.geocities.com/a_quarius@rogers.com/code/, if you would like to take a look. It's probably just another way of making menus owner-drawn .

Instead of

     CMenu::ModifyMenu( ..., MF_BYPOSITION | MF_OWNERDRAW, ... )

I'm doing

     ::AppendMenu(hMenu, MF_POPUP|MF_OWNERDRAW, ... );


Thanks for your help, as always! :)
Sandra
0

Featured Post

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

  • 7
  • 5
Tackle projects and never again get stuck behind a technical roadblock.
Join Now