In VB to display a popup menu when the user right clicked on some control this is what I had to do:
1) Create the menu in the menu editor
2) Hide this menu by setting its Visible property to False
3) Then call a single line function to display a popup in the appropriate control's event. (Like the button down or button up event of the desired control)
What's the procedure in FF/PB? I don't see any way to hide a menu so I don't think I create it in the menu editor first and then hide it. I also see no function in PB or FF to display a popup (context) menu.
Does this have to be handled via pure Win32 stuff? Does anyone have a handy code snippet or library that makes this easier?
TIA
Art
If you just want a popup, it would probably be easier to use the APIs. I usually create them in the WM_CREATE function and destroy them in WM_DESTROY. You just setup a MENUITEMINFO structure/type and use CreatePopupMenu and InsertMenuItem to create the menu. Might be easiest to make up some Global DWORDS or even an array to store the menu handles for each menu you want. Then use TrackPopupMenu on the click events to show the menu. Then on WM_DESTROY use DestroyMenu on all the menu handles.
You could also make them up on the fly which is better if you want dynamic options in the menu, but may show the menu a little slower. On Click do the whole process of Creating the menu, Inserting the items, Show the menu, then after the selection is made Destroy it.
%WM_MENURESTORE = %WM_USER + 501
%WM_MENUABOUT = %WM_USER + 502
%WM_MENUSEPLINE = %WM_USER + 503
%WM_MENUEXIT = %WM_USER + 504
'------------------------------------------------------------------------------------
Function FORM_WM_CREATE (hWndForm As Dword, ByVal UserData As Long) As Long
Local mi As MENUITEMINFO
Local tempsz As Asciiz * 10
' Setup Menu Structure
mi.cbSize=SizeOf(mi)
mi.fMask= %MIIM_TYPE Or %MIIM_STATE Or %MIIM_ID
mi.fType= %MF_STRING
mi.dwTypeData= VARPTR(tempsz)
' Create Menu
gMenu= CreatePopupMenu()
mi.wID= %WM_MENURESTORE
mi.fState= %MFS_DEFAULT
tempsz= "&Restore"
InsertMenuItem(gMenu, &HFFFFFFFF, %TRUE, mi)
mi.wID= %WM_MENUABOUT
mi.fState= %MF_ENABLED
tempsz= "&About"
InsertMenuItem(gMenu, &HFFFFFFFF, %TRUE, mi)
mi.fType= %MF_SEPARATOR
mi.wID= %WM_MENUSEPLINE
InsertMenuItem(gMenu, &HFFFFFFFF, %TRUE, mi)
mi.fType= %MF_STRING
mi.wID= %WM_MENUEXIT
tempsz= "E&xit"
InsertMenuItem(gMenu, &HFFFFFFFF, %TRUE, mi)
End Function
'------------------------------------------------------------------------------------
Function FORM_WM_DESTROY (hWndForm As Dword) As Long
DestroyMenu(gMenu) 'cleanup menu handle
End Function
Thanks Roger - again, you've been a big help to me. I am having a problem displaying the popup menu over the list control. I am using TrackPopupMenu in the WM_RBUTTONUP of the list control and am getting a popup menu but it is not positioned at the location of the cursor. Here is the code I am using. Perhaps you can point out my error?
FUNCTION FRMMAIN_LSTNAMES_WM_RBUTTONUP (parameters omitted for brevity) AS LONG
'display the context menu
TRACKPOPUPMENU gListPopupMenu, %TPM_LEFTALIGN OR %TPM_LEFTBUTTON, xPos, yPos, 0, hWndForm, BYVAL %NULL
END FUNCTION
TIA,
Art
OK, solved this myself. I thought that I could use the xPos and yPos values that are being passed in to WM_RBUTTONUP but apparently I can't. Maybe these are in client coordinates? But TrackPopupMenu requires screen coordinates. So I am now using GETCURSORPOS to get the coordinates. Here is the revised code that works properly.
FUNCTION FRMMAIN_LSTNAMES_WM_RBUTTONUP (parameters omitted for brevity) AS LONG
'display the context menu
LOCAL lngRetVal AS LONG
LOCAL ptScreenCursorPos AS POINTAPI
lngRetVal = GETCURSORPOS(ptScreenCursorPos)
IF lngRetVal <> 0 THEN
TRACKPOPUPMENU gListPopupMenu, %TPM_LEFTALIGN OR %TPM_LEFTBUTTON, ptScreenCursorPos.x, ptScreenCursorPos.y, 0, hWndForm, BYVAL %NULL
END IF
END FUNCTION
Art
Quote from: Art ArayaI thought that I could use the xPos and yPos values that are being passed in to WM_RBUTTONUP but apparently I can't. Maybe these are in client coordinates? But TrackPopupMenu requires screen coordinates. So I am now using GETCURSORPOS to get the coordinates. Here is the revised code that works properly.
Art, you are definately correct. All of the mouse button type messages use the client area coordinates rather than screen coordinates. This is just how Windows has designed those messages. You did the right thing by grabbing the mouse position via GetCursorPos and displaying the menu based on those values.
Oh, and one other thing, don't forget to use DestroyMenu to free the resources held by the menu handle, especially if you are dynamically creating the menu many times during the life of your program (via CreateMenu). Each time you create the menu you should first test to see if the gListPopupMenu variable is valid and destroy it.
If gListPopupMenu then DestroyMenu gListPopupMenu
' continue to create the new menu here....
You can also DestroyMenu at the end of the program as well just to ensure that the resources are released. i.e. via the WM_DESTROY message handler for the main form.
Thanks for the pointer Paul. I am creating the popup menu once during WM_CREATE. And am therefore destroying the popup menu once during WM_DESTROY. Is this correct?
Yes, that is correct. Even though Windows will normally release all memory held by your application when it terminates, it is considered good programming practice to explicitly destroy your used handles prior to the app ending.
From the code examples above:
Roger -
' Create Menu
gMenu= CreatePopupMenu()
Art -
'display the context menu
TRACKPOPUPMENU gListPopupMenu, ...
===
When I added Roger's pop up menu to the Calculator example in the Samples folder, I had to change Art's variable "gListPopupMenu" to Roger's variable "gMenu" to get the menu to display
===
Am I right in assuming that this is just two people using two different names for the menu handle, or is there really another variable involved but this is such a simple example that the second variable doesn't come into play?
Quote from: Larry BurfordAm I right in assuming that this is just two people using two different names for the menu handle, or is there really another variable involved but this is such a simple example that the second variable doesn't come into play?
You're right - it's just two people using two different names for the menu handle.