I ported my MFC application to Feature pack.When i try to insert a new sub menu/popup menu to CMFCMenuBar, the menu items in "Window" menu gets duplicated. Kindly help me. I used the below code to insert submenu.
CMenu* pMenu;
HMENU hMenu = m_wndMenuBar.GetHMenu();
ASSERT(::IsMenu(hMenu));
pMenu = CMenu::FromHandle(hMenu);
pMenu = pMenu->GetSubMenu(2);
pMenu->InsertMenu(2, MF_BYPOSITION ,
(UINT)ID_SORTING_SORTBYACCESS, _T("My Menu"));
m_wndMenuBar.CreateFromMenu(hMenu, false, true);
Related
I would like to have dynamic menu in my application. This dynamic menu should contain popupmenus which will be added and removed on the fly. For the first approach I made dynamic menu created with single menu items.
AppendMenu(menu, MF_STRING, item_id, "TEST");
I have created algorithm which generate item_id and store them in array, so I could remove them by
DeleteMenu(menu, id_to_be_deleted, MF_BYCOMMAND);
I do not see any pitfalls of this implementation and I am happy with it. But then stuck with final implementation. I would like my menus would be popup menus.
new_popup_menu = CreatePopupMenu();
AppendMenu(new_popup_menu, MF_STRING, 1, "TEST1");
AppendMenu(new_popup_menu, MF_STRING, 2, "TEST2");
AppendMenu(new_popup_menu, MF_STRING, 3, "TEST3");
AppendMenu(menu, MF_STRING|MF_POPUP,
(UINT_PTR)new_popup_menu, "dynamic menu");
This code works as expected, but I have no idea how to remove "new_popup_menu" from "menu" since the "UINT_PTR uIDNewItem" parameter of AppendMenu now is used as handle to submenu, not ID and cannot be used with DeleteMenu+MF_BYCOMMAND.
Is there any way to remove this submenu item other then DeleteMenu+MF_BYPOSITION?
Is there a way to get menu item position by handle which is returned by CreatePopupMenu())?
I feel implementation algorithm of tracking which menu is on which position is pain in the ass. Since Windows has API to insert the menu after other specific menu, recreating whole menu tree is a waste of CPU time.
If you want to create a menu item that opens a submenu and has an ID then create it with InsertMenuItem(...) rather than AppendMenu(...). InsertMenuItem(...) lets you fill in a struct that specifies all of the properties you want to be set on the menu item you are creating, including ID and submenu. A lot of Win32 works this way: AppendMenu(...) is like a shorthand version for the more verbose version of the same function. When you run into situations in which you can't do something reasonable with a certain Win32 call, look for a synonymous call that takes a *INFO structure.
Code below:
...
HMENU menu_bar = GetMenu(hWnd);
HMENU new_menu = CreateMenu();
AppendMenu(menu_bar, MF_POPUP, (UINT_PTR)new_menu, "foobar");
AppendMenu(new_menu, MF_ENABLED | MF_STRING, 1002, "item1");
AppendMenu(new_menu, MF_ENABLED | MF_STRING, 1003, "item2");
HMENU dynamic_popup = CreatePopupMenu();
AppendMenu(dynamic_popup, MF_ENABLED | MF_STRING, 1004, "mumble");
AppendMenu(dynamic_popup, MF_ENABLED | MF_STRING, 1005, "quux");
// Below will add an item named "dynamic menu" to the end of new_menu
// that has an ID of 1006.
MENUITEMINFO mii = { 0 };
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_SUBMENU | MIIM_STRING | MIIM_ID;
mii.dwTypeData = (LPSTR)"dynamic menu";
mii.hSubMenu = dynamic_popup;
mii.wID = 1006;
InsertMenuItem(new_menu, 0, FALSE, &mii);
//DeleteMenu(new_menu, 1006, MF_BYCOMMAND);
...
In my project, there is a menu that need to be appended an item dynamically.
In original code, items in the menu are stationary. So the menu is defined in the resource file:
IDM_SERVER_OPTIONS MENU DISCARDABLE
BEGIN
POPUP ""
BEGIN
MENUITEM "&Connect", IDC_LAUNCHITEM_CONNECT
MENUITEM "&Delete", IDC_REMOVE_SERVER
END
END
and is loaded in the code:
CMenu menu;
menu.LoadMenu(IDM_SERVER_OPTIONS);
Now, there is a new requirement that need to append a dynamic menu item after load the resource menu. I referred this aricle:
Dynamic menu using mfc
Followed it, I wrote these code:
CMenu menu;
menu.LoadMenu(IDM_SERVER_OPTIONS);
CMenu *autoConnectMenu = new CMenu;
autoConnectMenu->CreatePopupMenu();
autoConnectMenu->AppendMenu(MF_STRING | MF_ENABLED,
IDC_MENU_AUTO_CONNECT_SERVER,
utils::LoadString(IDS_MENU_AUTO_CONNECT_SERVER));
menu.AppendMenu(MF_POPUP,
(UINT)autoConnectMenu->m_hMenu,
L"auto connect server");
Unfortunately, it doesn't work. The new menu item "auto connect server" can't be displayed.
Then, I tried the HMENU function:
CMenu menu;
menu.LoadMenu(IDM_SERVER_OPTIONS);
AppendMenu((HMENU)menu.GetSubMenu(0),
MF_STRING | MF_ENABLED,
IDC_AUTO_CONNECT_SERVER,
utils::LoadString(IDS_MENU_AUTO_CONNECT_SERVER));
It works fine!
I want to know what problem in my former code? Appreciate!
I think that I have found the issue. I should have called
menu.GetSubMenu(0)->AppendMenu(...);
instead of
menu.AppendMenu(...);
I'm using the CMFCPopupMenu to create a right click popup menu. The problem is that the first time the menu is shown only the menu frame with shades is shown but the contents is white. The second time the menu is shown there are no problems. The code looks like this:
CPoint point;
::GetCursorPos (&point);
CMFCPopupMenu* pop = new CMFCPopupMenu();
pop->InsertItem(CMFCToolBarMenuButton(ID_COMMAND_1,NULL,-1,_T("Command 1")));
pop->InsertItem(CMFCToolBarMenuButton(ID_COMMAND_2,NULL,-1,_T("Command 2")));
pop->InsertItem(CMFCToolBarMenuButton(ID_COMMAND_3,NULL,-1,_T("Command 3")));
pop->InsertItem(CMFCToolBarMenuButton(ID_COMMAND_4,NULL,-1,_T("Command 4")));
pop->Create(this,point.x,point.y,NULL,0,true);
The parent class is based on CDialogEx.
Thanks.
I don't understand why my approach doesn't work but I found a way around it by defining the menu in the ressource and do like this:
CMenu menu;
menu.LoadMenu(IDR_SESSION_MENU);
HMENU hMenu = menu.GetSubMenu (0)->Detach ();
CMFCPopupMenu* pMenu = theApp.GetContextMenuManager()->ShowPopupMenu(hMenu, point.x, point.y, this, TRUE);
That Works and the only problem is that it's a bit more complicated to have a menu with dynamic entries depending on state and selection.
CMFCPopupMenu* pPopupMenu = new CMFCPopupMenu;
if (pPopupMenu->Create(pWndOwner, point.x, point.y, NULL, FALSE, TRUE))
{
pPopupMenu->InsertItem(CMFCToolBarMenuButton(57645, NULL, -1, _T("Command 1")), -1);
pPopupMenu->InsertItem(CMFCToolBarMenuButton(57646, NULL, -1, _T("Command 2")), -1);
pPopupMenu->RecalcLayout();
}
Need call RecalcLayout() after insert
How to create a menu dynamically?
In detail I want to:
Create a new ribbon page (tab, I think it's called ribbon page)
Next create a title for the page
Next add 2 ribbon groups and add titles to them
Next add 3 bar button items to the first ribbon group
How to accomplish this?
Dim menu As New RibbonControl
Dim aPage As New RibbonPage("Nicks Page")
'groups
Dim aGroup1 As New RibbonPageGroup("1st Group")
'ADD BUTTONS TO RIBBON GROUP HERE
Dim i As New DevExpress.XtraBars.BarButtonItem()
i.Caption = "Nicks Button"
aGroup1.ItemLinks.Add(i)
Dim i2 As New DevExpress.XtraBars.BarButtonItem()
i2.Caption = "Nicks Other Button"
aGroup1.ItemLinks.Add(i2)
aPage.Groups.Add(aGroup1)
menu.Pages.Add(aPage)
Me.Controls.Add(menu)
I writing a MFC which has a listview control. When the user right clicks any item , I am generating a dynamic menu item with that text that is selected in listview. Everything is displaying properly, but I do not know how to add a message map to that dynamic menu item.
Any help?
void CMyListDlg::OnRclickList(NMHDR* pNMHDR, LRESULT* pResult)
{
// TODO: Add your control notification handler code here
int nIndex = m_List.GetSelectionMark();
CString pString = m_List.GetItemText(nIndex,1);
CMenu menu, * pSubMenu;
int pos=0;
menu.LoadMenu(IDR_MENU1);
pSubMenu = menu.GetSubMenu (0);
pSubMenu->DeleteMenu(0,MF_BYPOSITION);
pSubMenu->InsertMenu(pos,MF_BYPOSITION,NULL,pString);
CPoint oPoint;
GetCursorPos (& oPoint);
pSubMenu-> TrackPopupMenu (TPM_LEFTALIGN, oPoint.x, oPoint.y, this);
*pResult = 0;
}
At the moment you are inserting the menu item with ID = 0 (NULL). That way you can't figure out which command was pressed. You have to assign an ID to the item, the simplest one is to
#define WM_MYMESSAGE WM_USER + 1
then you insert it like this:
pSubMenu->InsertMenu(pos,MF_BYPOSITION,WM_MYMESSAGE,pString);
If you override OnCommand for your window, you get your ID as wParam.
To actually figure out what happened, store some additional information in another class member, like m_nLastItemClicked or ... you get the idea?!
Check the MFCIE sample, it generates a favorite menu from the user's favorite folder and navigates to the favorite url when a favorite menu item is clicked.
Just add ON_COMMAND (and ON_UPDATE_COMMAND_UI if necessary) handlers for the menu items' IDs on your class.