Normally when you hover over a sub-menu (with the little arrow) on a CMenu menu item it delays briefly then shows the sub-menu items. Also, if you click the item before the delay timeout, it shows the sub menu items. I want the delay behavior, but I want a different behavior for the click. That is, I want the sub-menu itself (the one with the arrow) to be a clickable entity too, i.e. it has an ID and results in a WM_COMMAND and menu dismissal.
The idea is, the main sub-menu menu item is a "default", and the sub-menu items are modified versions, e.g. "print->" (defaulting to default printer), and sub-menu items like "print preview" "print to file" etc. Thanks for thoughts/suggestions.
edit:
IDR_MY_MENU MENUEX
BEGIN
POPUP "menu"
BEGIN
MENUITEM "&Something Else", ID_MENU_SOMETHING_ELSE
POPUP "&Print", ID_MENU_PRINT
BEGIN
MENUITEM "Print Pre&view", ID_MENU_PRINT_PREVIEW
MENUITEM "Print to &File", ID_MENU_PRINT_TO_FILE
END
MENUITEM "", -1, MFT_SEPARATOR
MENUITEM "&Bottom", ID_MENU_BOTTOM
MENUITEM "&Done", ID_MENU_DONE
END
END
I dont know if theres a better way as I last did this 2 years ago, but the way I solved the problem had one constraint: that you own the whole menu. If you do own the whole menu what you can do is create two columns (two columns in the menu/submenu that is, not a new submenu) and use the right column as a submenu and the left column as the default.
For future StackOverflowers, here's what I did...
OnInitMenuPopup
and correspondingON_WM_INITMENUPOPUP()
, although doing this messed up myUPDATE_COMMAND_UI
handler but I was able to resolve that by moving that code into theOnInitMenuPopup
handler.OnInitMenuPopup
handler, set a hook for the mouseSetWindowsHookEx(WH_MOUSE,...)
(checking if one isn't already set because sub-menus can cause multiple calls)... and for each menu that initializes during the hook, push theHMENU
onto a linked list.HMENU
is still and active menu viaIsMenu
and remove it if it isn't. If there are no menus left,UnhookWindowsHook
.WM_LBUTTONUP
orWM_RBUTTONUP
and see if happened over one of your menu items (because of coordinate mapping of screen versus sub-menu that I couldn't figure out I ended up simply cycling through the menu items viaGetMenuItemRect
and checkingPtInRect
to determine this).GetMenuItemInfo
on the item, and if there's ahSubMenu
for that item and it has anwID
(and thewID
doesn't match the sub-menu handle), simply post the id as aWM_COMMAND
, post aWM_CANCELMODE
to dismiss the menu, and disable the hook... Bingo!So, seems to work fine and everything else functions like normal. The only issue at this point is a keyboard handler for selecting the item instead opening the sub-menu but I suspect the same idea works there as well.
Also, I added the main sub-menu text as the first item in the sub-menu list with a separator which added some clarity to what the menu was doing.