VFP - Custom Context Menu example
File(s): extra\customcontextmenu.scx, extra\antviewcontextmenuitemevents.prg, html\customContextMenu.html
We have a form called customcontextForm

You are being asked to right click on the html page and it will show you the details depending on where you click and what you do. For example if you first select some text in the page and then right click, you'll see this:

This shows our simple custom context menu. A menu with three options, "Reload", "Back" (in disabled form) and "Help" (with an icon).
At the bottom of the view we see that it shows the text we selected before right clicking on it and the target kind of the menu is currently in "Selected text" mode.
You can get different results, depending on clicking with or without selected text, by right clicking on the image and by right clicking on the link. If you then click on the link and navigate to the antview website, the "Back" option in the menu becomes enabled and you can use it to navigate back.
If you select an option from the menu, the selected option is displayed at the bottom of the form in the info area.
In order to do all this we have the following code.
First we need to generate the package for being able to access events for our context menu item, so that we can act on the user selecting the menu item.
This is the AntViewContextMenuItemEvents.prg file.
The AntViewContextMenuItemEvents.prg looks like this:
*
* AntViewContextMenuItemEvents.prg - VFP wrapper for Menu Item Events
*
* We're using a callBack method, called contextmenucallback that should exist in the form to be
* able to use it.
*
DEFINE CLASS AntViewContextMenuItemEvents AS session && OLEPUBLIC
menuItemID = 0 && We're setting this menuItemID to figure out which menu item object was clicked
IMPLEMENTS IAntViewContextMenuItemEvents IN "AntViewAx2.AntViewContextMenuItem"
PROCEDURE IAntViewContextMenuItemEvents_OnDestroy() AS VOID;
HELPSTRING "Called when the ContexMenuItem object goes out of scope"
* add user code here
ENDPROC
PROCEDURE IAntViewContextMenuItemEvents_OnCustomItemSelected() AS VOID;
HELPSTRING "This event triggers when the user selects this menu item."
* test if the method contextmenucallback exists on the current form and if so, call it
IF PEMSTATUS(_SCREEN.ACTIVEFORM, "contextmenucallback", 5) THEN
_SCREEN.ACTIVEFORM.contextmenucallback(this.menuItemID)
ELSE
WAIT WINDOW ("Programmer Error: the callBack method is undefined!")
ENDIF
ENDPROC
ENDDEFINE
The OnCustomItemSelected event has been extended here a bit with code that calls a user defined method "contextmenucallback" in the form along with a menu ID so we can identify which menu item was selected.
thisform.Init:
* *** CREATE THE MENU ITEM OBJECTS ***
thisform.oBackMenuItem = CREATEOBJECT('AntViewAx2.AntViewContextMenuItem') && Create the "back" menu item
thisform.oBackMenuItemEvents = NEWOBJECT('AntViewContextMenuItemEvents','AntViewContextMenuItemEvents.prg')
*EVENTHANDLER(thisform.oBackMenuItem,thisform.oBackMenuItemEvents) && connect the events (won't work here, we do it at assignment)
thisform.oHelpMenuItem = CREATEOBJECT('AntViewAx2.AntViewContextMenuItem')
thisform.oHelpMenuItemEvents = NEWOBJECT('AntViewContextMenuItemEvents','AntViewContextMenuItemEvents.prg')
thisform.oReloadMenuItem = CREATEOBJECT('AntViewAx2.AntViewContextMenuItem')
thisform.oReloadMenuItemEvents = NEWOBJECT('AntViewContextMenuItemEvents','AntViewContextMenuItemEvents.prg')
* create our icons used in the menu items
thisform.oNoMenuIcon = CREATEOBJECT('AntViewAx2.AntViewContextMenuIcon') && an empty icon object for the items without an icon
thisform.oHelpMenuIcon = CREATEOBJECT('AntViewAx2.AntViewContextMenuIcon')
thisform.oHelpMenuIcon.LoadFromFile(pchtmlpath+"StatusAnnotations_Information_32xLG_color.png")
*-------------------Page 1
thisform.oAntview.Init()
thisform.oAntview.UnlockControl("ExampleCompany","WI5PO2-2KSU3Q-HWFXFU-IUMU2V-QF8P2F")
lnStatus = thisform.oAntview.UnlockStatus
Thisform.oAntView.CreateWebView
*-------------------Resize
this.Resize
Thisform.refresh
In the init code of the form we create a bunch of objects, two for each menu item, one for the item itself and one for the events object. We don't link those two yet as there's no actual menu item attached just yet.
We also create two icon objects, one as an empty icon (this could also be a null dispatch object) and one for the help icon.
After that we initialize the AntView control.
Once the AntView control is done initializing it calls the following event:
oAntView.OnCreateWebViewCompleted:
*** ActiveX Control Event ***
LPARAMETERS hresult
thisform.loadstring
thisform.oInfoEdit.Value = "This info area will show the context menu interaction details."
In there we call the User Defined method loadstring.
thisform.loadstring:
LOCAL filePath, fileContents
LOCAL lcNotFoundHtml
lcNotFoundHtml = ''
TEXT TO lcNotFoundHtml NOSHOW PRETEXT 7
<html>
<body>
<p>File to show the contextmenu demo was not found.</p>
</body>
</html>
ENDTEXT
filePath = pchtmlpath+'customContextMenu.html'
IF FILE(filePath) THEN
fileContents = FILETOSTR(filePath)
ELSE
fileContents = lcNotFoundHtml
ENDIF
thisform.oAntView.navigateToString(fileContents)
The loadstring method reads the html file from disk and puts the result in a string.
As a result the page is loaded as a data URL. Which is a identifying feature that we will use later on.
The OnContextMenuRequested event is what gets called when the user right clicks anywhere in the AntView control.
oAntView.OnContextMenuRequested:
*** ActiveX Control Event ***
LPARAMETERS args
LOCAL lMenuItems As AntViewAx2.AntViewContextMenuItemCollection
LOCAL lTarget As AntViewAx2.AntViewContextMenuTarget
LOCAL lMenuKind As TxContextMenuItemKind
LOCAL lcKind As String
Thisform.oInfoEdit.Value = "OnContextMenuRequested event"
lMenuItems = args.menuitems
lTarget = args.ContextMenuTarget
lMenuItems.RemoveAllMenuItems
lMenuKind = 0 && cmikCommand = 0
thisform.oReloadMenuItem = Thisform.oAntView.CreateContextMenuItem('Reload',thisform.oNoMenuIcon, lMenuKind)
lMenuItems.AppendMenuItem(thisform.oReloadMenuItem)
EVENTHANDLER(thisform.oReloadMenuItem,thisform.oReloadMenuItemEvents)
thisform.oReloadmenuitemevents.MenuItemID = 1
thisform.oBackMenuItem = Thisform.oAntView.CreateContextMenuItem('Back',thisform.oNoMenuIcon, lMenuKind)
lMenuItems.AppendMenuItem(thisform.oBackMenuItem)
IF LEFT(lTarget.PageUri,15) = "data:text/html;" THEN
thisform.oBackmenuitem.Enabled = .F.
ELSE
thisform.oBackmenuitem.Enabled = .T.
ENDIF
EVENTHANDLER(thisform.oBackMenuItem,thisform.oBackMenuItemEvents) && connect the events
thisform.oBackmenuitemevents.MenuItemID = 2
thisform.oHelpMenuItem = Thisform.oAntView.CreateContextMenuItem('Help',thisform.oHelpMenuIcon, lMenuKind)
lMenuItems.AppendMenuItem(thisform.oHelpMenuItem)
EVENTHANDLER(thisform.oHelpMenuItem,thisform.oHelpMenuItemEvents)
thisform.oHelpmenuitemevents.MenuItemID = 3
IF lTarget.HasLinkUri THEN
Thisform.oInfoEdit.Value = "That hyperlink goes to " + lTarget.LinkUri
ENDIF
IF lTarget.HasSelection THEN
Thisform.oInfoEdit.Value = "Selected Text = " + lTarget.SelectionText
ENDIF
lcKind = ''
DO CASE
CASE lTarget.Kind= 0 && cmtkPage
lcKind = "Page"
CASE lTarget.Kind= 1 && cmtkImage
lcKind = "Image"
CASE lTarget.Kind= 2 && cmtkSelectedText
lcKind = "Selected Text"
CASE lTarget.Kind= 3 && cmtkAudio
lcKind = "Audio"
CASE lTarget.Kind= 4 && cmtkVideo
lcKind = "Video"
ENDCASE
Thisform.oInfoEdit.Value = Thisform.oInfoEdit.Value + CHR(13) + CHR(10) + "Kind: " + lcKind
Our first step is removing all menu items with RemoveAllMenuItems, followed by creating the first menu item.
thisform.oReloadMenuItem = Thisform.oAntView.CreateContextMenuItem('Reload',thisform.oNoMenuIcon, lMenuKind)
lMenuItems.AppendMenuItem(thisform.oReloadMenuItem)
EVENTHANDLER(thisform.oReloadMenuItem,thisform.oReloadMenuItemEvents)
thisform.oReloadmenuitemevents.MenuItemID = 1
As you can see we are here using the oReloadMenuItem object that was created earlier for creating our "Reload" menu item.
With AppendMenuItem we then add the new menu item into the menu and then we connect the event handler that we created in the init method of the form with the menu item.
We assign the value 1 to this menu item, which we use again in the callback function.
This is then repeated for the "Back" menu item.
thisform.oBackMenuItem = Thisform.oAntView.CreateContextMenuItem('Back',thisform.oNoMenuIcon, lMenuKind)
lMenuItems.AppendMenuItem(thisform.oBackMenuItem)
IF LEFT(lTarget.PageUri,15) = "data:text/html;" THEN
thisform.oBackmenuitem.Enabled = .F.
ELSE
thisform.oBackmenuitem.Enabled = .T.
ENDIF
EVENTHANDLER(thisform.oBackMenuItem,thisform.oBackMenuItemEvents) && connect the events
thisform.oBackmenuitemevents.MenuItemID = 2
One extra thing that we do here is to check the URL of the page in the browser. If it starts with "data:text/html;" html, it is a data URL and we'll disable the back menu item as that means we're on the opening page.
The "Back" menu item gets a menuItemID of 2 assigned.
The last menu item that we create here is the "Help" menu item.
thisform.oHelpMenuItem = Thisform.oAntView.CreateContextMenuItem('Help',thisform.oHelpMenuIcon, lMenuKind)
lMenuItems.AppendMenuItem(thisform.oHelpMenuItem)
EVENTHANDLER(thisform.oHelpMenuItem,thisform.oHelpMenuItemEvents)
thisform.oHelpmenuitemevents.MenuItemID = 3
This is almost like the ones before, except that we now assign the Help Menu Icon object.
The "Help" menu item gets a menuItemID of 3 assigned.
The User Defined function contextmenucallback is the method that gets called by our event.
We act in there depending on the value of the menuItemID that was set.
function thisform.contextmenucallback:
LPARAMETERS menuItemID
LOCAL lcInfo As String
lcInfo = ''
DO CASE
CASE menuItemID= 1
thisform.loadstring
lcInfo = "The Reload menu item was selected."
CASE menuItemID= 2
thisform.oAntView.goBack
lcInfo = "The Back menu item was selected."
CASE menuItemID= 3
lcInfo = "The Help menu item was selected."
OTHERWISE
WAIT WINDOW "Unknown item was selected!"
ENDCASE
thisform.oInfoEdit.value = lcInfo
AntView - The MS Edge WebView2 ActiveX control Date last changed: 11/05/2025