I am trying to load a popup "right click" menu, and use the resource file to define the menu items. The picture shows what is happening when I right click, it displays room for 2 items, which is correct, but doesnt show any text.
In the .cpp:
POINT pt;
pt.x = LOWORD (lParam);
pt.y = HIWORD (lParam);
ClientToScreen (hwnd, &pt);
HMENU hMenu = LoadMenu(NULL, MAKEINTRESOURCE(IDR_POPUPMENU));
TrackPopupMenu (hMenu, TPM_RIGHTBUTTON, pt.x, pt.y, 0, hwnd, NULL);
and the resource:
IDR_POPUPMENU MENU DISCARDABLE
BEGIN
MENUITEM "test", IDM_TEST
MENUITEM "Close", IDM_CLOSE
END
any idea on what I am donig wrong?
Thanks.
EDIT: I just tested, and clicking in the "no text displayed" areas, and it sends the correct message. What could be causing it to not display the text?
Found the solution:
HMENU hMenu = LoadMenu(NULL, MAKEINTRESOURCE(IDR_POPUPMENU));
hMenu = GetSubMenu(hMenu, 0);
and resource:
IDR_POPUPMENU MENU DISCARDABLE
BEGIN
POPUP "TEST"
BEGIN
MENUITEM "Test", IDM_TEST
MENUITEM "Close", IDM_CLOSE
END
END
Just had to start the resource entry with a beginning sub menu, TEST does not display, only its menu items do.
Your menu resource is incorrect. It must be a popupmenu.
eg:
IDR_MENU_TRAY MENU
BEGIN
POPUP "ContextMenu"
BEGIN
MENUITEM "ShowWindow", ID_POPUP_SHOWWINDOW
MENUITEM "Exit", ID_POPUP_EXIT
END
END
TrackPopupMenu first parameter is a handle to a submenu associated with an existing menu item.
You can see the examples here: http://msdn.microsoft.com/EN-US/library/ms647558(v=VS.85,d=hv.2).aspx
Related
Here is a new View menu that I have added to my software:
My editor (a CDialog) has two modes. This View menu is only application to one of the modes.
At the moment I am simply disabling the menu items like this:
CMenu* pMenu = GetMenu();
if (pMenu != nullptr)
{
pMenu->EnableMenuItem(ID_VIEW_REFRESH, MF_BYCOMMAND | MF_GRAYED);
CMenu* pViewMenu = pMenu->GetSubMenu(3);
if (pViewMenu != nullptr)
pViewMenu->EnableMenuItem(1, MF_BYPOSITION | MF_GRAYED);
}
This works fine. But is there any way to either:
Disable the actual View menu item on the menu bar?
Remove / Add the menu as needed?
As the moment the menu is always there and I just disable the items dependant on the active editor mode. It is part of my editor menu in the resources:
POPUP "View"
BEGIN
MENUITEM "Refresh\tF5", ID_VIEW_REFRESH, INACTIVE
POPUP "Zoom", GRAYED
BEGIN
MENUITEM "Zoom In\tCTRL +", ID_ZOOMLEVEL_ZOOMIN
MENUITEM "Zoom Out\tCTRL -", ID_ZOOMLEVEL_ZOOMOUT
MENUITEM SEPARATOR
MENUITEM "400%", ID_ZOOMLEVEL_400
MENUITEM "300%", ID_ZOOMLEVEL_300
MENUITEM "250%", ID_ZOOMLEVEL_250
MENUITEM "200%", ID_ZOOMLEVEL_200
MENUITEM "175%", ID_ZOOMLEVEL_175
MENUITEM "150%", ID_ZOOMLEVEL_150
MENUITEM "125%", ID_ZOOMLEVEL_125
MENUITEM "100%\tCTRL + 0", ID_ZOOMLEVEL_100
MENUITEM "75%", ID_ZOOMLEVEL_75
MENUITEM "50%", ID_ZOOMLEVEL_50
MENUITEM SEPARATOR
MENUITEM "Custom...", ID_ZOOM_CUSTOM
END
END
Is this possible?
Let's suppose your menu is called IDR_MAINFRAME:
Create your mainFrame and add IDR_MAINFRAME menu:
CMainFrame* pFrame = new CMainFrame;
pFrame->LoadFrame(IDR_MAINFRAME, WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE, NULL, NULL);
You must get the main menu like this:
CMenu menu;
menu.LoadMenu(IDR_MAINFRAME);
Now, you can desable a specific item:
menu.EnableMenuItem (1, MF_BYPOSITION|MF_DISABLED|MF_GRAYED);
pFrame->SetMenu(&menu);
See result below :
Note that Edition is a main menu (similar to your View menu) for my application.
To enable your menu (View menu) dynamically, call EnableMenuItem a second time like this:
menu.EnableMenuItem (1, MF_BYPOSITION);
Hope it help you.
Update
I also had to use this code to get the menu bar to update visually:
DrawMenuBar();
With this code the menu did not visually update until the mouse was put over the menu text.
Sure, to disable the item retrieve the menu handle using GetMenu then use the EnableMenuItem API and specify MF_BYPOSITION rather than MF_BYCOMMAND.
Or you could use a MENUEX resource and assign an ID to the popup menu items (unfortunately th resource editor can not save MENUEX resources, it can read them but always saves as MENU). If you want to change to MENUEX put it in the .rc2 file of an MFC project.
I am trying to draw a custom popup menu on MFC single-document interface (SDI) project.
From here, I found The framework calls this member function for the owner of an owner-draw button control, combo-box control, list-box control, or menu when a visual aspect of the control or menu has changed.
So I added the handle OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct) and added some code inside this function, but I found that this callback didn't be called by the framework when I right click on the view, like this:
How to make a popup menu dynamically?
Here is how I get my pop up menu:
void Cdynamic_menu_sdiView::OnContextMenu(CWnd* /* pWnd */, CPoint point)
{
if (IDR_MY_MENU == 0)
return;
CMenu dynamicMenu, proxyMenu;
if (dynamicMenu.GetSafeHmenu())
dynamicMenu.DestroyMenu();
// Create a new popup menu.
if (dynamicMenu.CreatePopupMenu() == FALSE)
return;
if (proxyMenu.LoadMenu(IDR_MY_MENU) == FALSE)
return;
int nSubMenu = 1;
CMenu* pProxyMenu = proxyMenu.GetSubMenu(nSubMenu);
build_dynamic_menu(m_map_menu_element_2, pProxyMenu, dynamicMenu, CString(""));
//m_menu_on_draw = &dynamicMenu; // link up the dynamic menu to the on draw menu, so that we can print it on the screen
CPoint ptCurPos; // current cursor position
GetCursorPos(&ptCurPos);
dynamicMenu.TrackPopupMenu(TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON, ptCurPos.x, ptCurPos.y, AfxGetMainWnd(), NULL);
}
Inside the function build_dynamic_menu(), it is a depth first search function, I do InsertMenu(i, MF_BYPOSITION | MF_POPUP | MF_OWNERDRAW, uSubMenuID, strLabel); so that I can change the text of the popup menu dynamically.
Since it is too long to put the function here, I only state the idea.
I also want to change the text color and background color dynamically, so I am trying to find a way to draw the menu by code.
Where should I start? Is owner drawn menus approach good for me?
I currently am attempting to do something simple:
CMenu menu;
menu.LoadMenu(IDR_MENU_IMAGE);
CPoint pt;
GetCursorPos(&pt);
menu.TrackPopupMenu(TPM_RIGHTBUTTON, pt.x, pt.y, this);
When I right-click, I get the below image. However, the menu is loaded; as I move my cursor down the menu, you can see it populate sub-menus just fine. It does this with any menu I load dynamically like this. I attempted to create a pointer (CMenu*) and still continue having this problem.
The points don't matter (I input arbitrary points).
The "this" in question is a derived CView* class. I am clicking on a HWND object but I tried to also take the CWnd::FromHandle() of this particular object I am clicking on and having the object handle it, but I still have the same problem.
My top menu structure and all other menus work - it is only in this particular case.
I don't really want to derive a C++ CMenu class just to override the MeasureItem function when the original menus should actually be working, and do work fine in other versions..
Help?
Use GetSubMenu(0) to obtain a popup handle:
CMenu menu;
menu.LoadMenu(IDR_MENU_IMAGE);
CMenu *submenu = menu.GetSubMenu(0);
if (submenu)
submenu->TrackPopupMenu(TPM_RIGHTBUTTON, pt.x, pt.y, this);
Where IDR_MENU_IMAGE is created in resource editor similar to the following:
IDR_MENU_IMAGE MENU
BEGIN
POPUP "File"
BEGIN
MENUITEM "New", ID_FILE_NEW
MENUITEM "Open", ID_FILE_OPEN
MENUITEM "Save", ID_FILE_SAVE
MENUITEM "Save As ...", ID_FILE_SAVEAS
END
END
Result:
Note, this won't work if there is only a "menu bar", and no popup. The menu below cannot be created as popup:
IDR_MENU_IMAGE MENU //no popup menu!
BEGIN
MENUITEM "A", IDA
MENUITEM "B", IDB
MENUITEM "C", IDC
END
You can also create the popup menu as follows:
CMenu menu;
menu.CreatePopupMenu();
menu.AppendMenu(MF_STRING, ID_FILE_NEW, "New");
menu.TrackPopupMenu(TPM_RIGHTBUTTON, p.x, p.y, this);
I am working with a dialog window, which has three buttons: "Save...", "Decrypt" and "OK". According to Spy++, each button has class "XButton". I am trying to press "Decrypt" from another application, so this is what i do:
// "buffer" below contains dialog's caption
hProgramWindow = FindWindowEx(NULL, NULL, NULL, buffer);
// "caption" below contains string "Decrypt"
HWND hButton = FindWindowEx(hProgramWindow, NULL, TEXT("XButton"), caption);
SetFocus(hProgramWindow);
SetActiveWindow(hProgramWindow);
PostMessage(hProgramWindow, WM_COMMAND,
MAKEWORD(GetDlgCtrlID(hButton), BN_CLICKED), (LPARAM)hButton);
// After posting the message, GetLastError() returns "5" (Access denied),
// but the button is clicked
When caption variable has value "Save...", the "Save..." button is clicked (still GetLastError() = 5), the appropriate save dialog appears. But when caption variable has value "Decrypt", the "Decrypt" button is not clicked, no dialog appears. Any suggestions, why it can happen?
By the way, calling EnableWindow(hButton, FALSE); for "Decrypt" button (as well as for "Save..." button) works fine, the it becomes disabled, so that means that the handle is correct.
Here is what I'm doing. I'v created a combobox but I'm not using it for that. When I click it, it calls trackpopup and brings up a context menu. However after I'v clicked the context menu, I'd like it to close the combobox in the same way it would if you clicked anywhere (killing the focus) or selected an item from the combobox.
Here's the event for the combobox:
if(uMsg == WM_COMMAND)
{
HMENU m;
m = CreatePopupMenu();
MENUITEMINFO itm;
itm.cbSize = sizeof(MENUITEMINFO);
itm.fMask = MIIM_FTYPE | MIIM_STRING;
itm.fType = MIIM_STRING;
itm.dwTypeData = "Kill time";
itm.cch = 12;
POINT p;
GetCursorPos(&p);
InsertMenuItem(m,4,false,&itm);
if((int)HIWORD(wParam) == CBN_DROPDOWN)
{
SendMessage(engineGL.controls.TopSelHwnd,WM_KILLFOCUS,(WPARAM)engineGL.controls.TopSelHwnd,0);
SendMessage(engineGL.controls.TopSelHwnd,WM_IME_SETCONTEXT,(WPARAM)0,(LPARAM)ISC_SHOWUIALL);
TrackPopupMenu(m,0,p.x,p.y,NULL,hWnd,NULL);
SendMessage(hWnd,WM_KILLFOCUS,0,0);
SetFocus(HWND_DESKTOP);
}
return 1;
}
How can I make it so that after I click an item on the context menu, the combobox closes properly as if I'd actually chosen an item from it?
Thanks
I'm not sure. Need to try your code.
However I'm sure that one should not send the WM_KILLFOCUS message manually. Instead you need to set the focus to another window by calling SetFocus. The OS will automatically send messages to the window losing the focus and the new window that is gaining the focus.