Contents - Index - Top


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

<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