B4J Code Snippet Get ContextMenus working on Nodes/Controls which do not support it

moster67

Expert
Licensed User
I though I would post this sample before I forget it and loose the code :)

EDIT: Posted correct sample because last night I posted the wrong code.

There are some Nodes/Controls which do not support setting a ContextMenu such as Pane, ImageView and some others.
There are a lot of code/snippets here in the forum for ContextMenu but I couldn't find any code (unless I missed it) which could help me with nodes that do not support ContextMenu. There is a work-around posted where a button was used to get a ContextMenu over an ImageView but I couldn't get it to work that well.
By googling, I noted that it can actually be done in a regular and proper way. Below code-sample is based on my findings.

B4X:
#Region Project Attributes
    #MainFormWidth: 600
    #MainFormHeight: 600
#End Region

Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    Private ContextMenu,ContextMenu1 As ContextMenu
    Private pane1 As Pane
    Private img As ImageView
   
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    'MainForm.RootPane.LoadLayout("Layout1") 'Load the layout file.
   
    ContextMenu.Initialize("ContextMenu")
    ContextMenu1.Initialize("ContextMenu1")
    pane1.Initialize("pane1")
    img.Initialize("img")
    Private bpm As Image
    bpm.Initialize(File.DirAssets,"Image1.jpg") 'add your own image in the asset folder
    img.SetImage(bpm)
    MainForm.RootPane.AddNode(pane1, 200,100,100,100)
    MainForm.RootPane.AddNode(img,200,300,200,200)
    pane1.Style="-fx-background-color: #FA7073"
   
    'add menuitems to the contextmenu
    Private MenuText() As String = Array As String("Open","Save as PNG","Save as JPEG")
    For i = 0 To MenuText.Length - 1
        Private TheMenuItem As MenuItem
        TheMenuItem.Initialize(MenuText(i),"cxm")
        ContextMenu.MenuItems.Add(TheMenuItem)
    Next
   
    Private MenuText1() As String = Array As String("A1","B2","C3")
    For i = 0 To MenuText1.Length - 1
        Private TheMenuItem As MenuItem
        TheMenuItem.Initialize(MenuText1(i),"cxm1")
        ContextMenu1.MenuItems.Add(TheMenuItem)
    Next
   
    'call the AddEventHandler sub for the nodes
    AddEventHandler(pane1,"pane1")
    AddEventHandler(img,"img")
    MainForm.Show
End Sub


Sub AddEventHandler(n As Node, EventName As String)
    'add an event handler and a ContextMenuEvent to the node which was passed
    Private joNode As JavaObject = n
    Private ev As Object = joNode.CreateEventFromUI("javafx.event.EventHandler",EventName,False)
    joNode.RunMethod("setOnContextMenuRequested",Array(ev))
End Sub

Sub Pane1_MouseClicked(EventData As MouseEvent)
    'trap the mouseclicked event, get the necessary data and show the ContextMenu
    Private joCM As JavaObject = ContextMenu1
    Private joED As JavaObject = EventData
    Private ScreenX As Double = joED.RunMethod("getScreenX", Null)
    Private ScreenY As Double = joED.RunMethod("getScreenY", Null)
    joCM.RunMethod("show",Array(pane1,ScreenX,ScreenY))
   
End Sub

Sub img_MouseClicked (EventData As MouseEvent)
    'trap the mouseclicked event, get the necessary data and show the ContextMenu
    Private joCM As JavaObject = ContextMenu
    Private joED As JavaObject = EventData
    Private ScreenX As Double = joED.RunMethod("getScreenX", Null)
    Private ScreenY As Double = joED.RunMethod("getScreenY", Null)
    joCM.RunMethod("show",Array(img,ScreenX,ScreenY))
End Sub

Sub cxm_Action
    'get the sender, menuitem clicked and do something with it
    Private meit As MenuItem = Sender
    If meit.Text = "Open" Then
        Log("Open") 'do something
    else if meit.Text = "Save as PNG" Then
        Log("Save as PNG") 'do something
    else if meit.Text = "Save as JPEG" Then
        Log("Save as JPEG") 'do something
    End If
End Sub

Sub cxm1_Action
    'get the sender, menuitem clicked and do something with it
    Private meit As MenuItem = Sender
    If meit.Text = "A1" Then
        Log("A1") 'do something
    else if meit.Text = "B2" Then
        Log("B2") 'do something
    else if meit.Text = "C3" Then
        Log("C3") 'do something
    End If
End Sub


'Return true to allow the default exceptions handler to handle the uncaught exception.
Sub Application_Error (Error As Exception, StackTrace As String) As Boolean
    Return True
End Sub
upload_2019-2-14_23-53-22.png


I guess you can improve the look and feel of the ContextMenu by using CSS but I didn't try that.

Hope this turns useful for someone.
 
Last edited:

moster67

Expert
Licensed User
Updated first post with the correct sample because last night I posted the wrong code. Apparently I was too tired....
 
Top