B4J Question Question about context menus ...

MuuSer

Member
Licensed User
Longtime User
Hello!

How is possible to avoid text field native context menu (copy, paste, etc.) and invoke custom menu? So far I had them both in same time, but this is not good enough. :)

Or - another solution will be, if somehow is possible to invoke custom context menu programmatically, then there is no need to avoid native context menu of text field as I can invoke it with double-click.

Any ideas?

Thanks ahead. :)
 

Daestrum

Expert
Licensed User
Longtime User
Maybe not the easiest - but it works - example loads an image and a slider into a context menu for the textfield.
Click on image and it disappears, click on slider and it will stay there so you can interact with it.
( I use Java 8_20 sdk, so may not work on earlier java's)
B4X:
Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    'MainForm.RootPane.LoadLayout("Layout1") 'Load the layout file.
    MainForm.Show
    '===== make up some controls =====
    '===== and initialize them
    Dim t As TextField
    Dim im As Image
    Dim iv As ImageView
    Dim sl As Slider
    sl.Initialize("")
    im.Initialize("c:/temp/","arr_right.png")' any old picture not too big, remember its in a menu
    iv.Initialize("iv")
    iv.SetImage(im)
    t.Initialize("")
    Dim jo,jo1 As JavaObject ' dont forget to add javaobject library
    Dim cm As ContextMenu
    cm.Initialize("") ' init contextmenu dont want handler
    ' ===== initialize the 'Custom menu items"
    jo.InitializeNewInstance("javafx.scene.control.CustomMenuItem",Array(iv))
    jo.RunMethod("setHideOnClick",Array(True)) ' disappear when clicked
    jo1.InitializeNewInstance("javafx.scene.control.CustomMenuItem",Array(sl))
    jo1.RunMethod("setHideOnClick",Array(False)) ' dont disappear when clicked
    cm.MenuItems.AddAll(Array(jo,jo1)) ' add to context menu
    t.ContextMenu = cm ' bind menu to textfield
    MainForm.RootPane.AddNode(t,50,50,-1,-1) ' add textfield to form
End Sub
Sub iv_MouseClicked(eventdata As MouseEvent) ' called when image in menu clicked
    Log("clicked " & Sender)
End Sub
 
Upvote 0

MuuSer

Member
Licensed User
Longtime User
Thanks, Daestrum.

I have no problems for creating context menus. Anyway nice tip for adding programmatically image or slider objects and working with slider in menu, but as you see from my attachment - native textfield menu is still there.

two_menus.jpg
 
Upvote 0

MuuSer

Member
Licensed User
Longtime User
My knowledge about Java is near zero, but Google told me that in Java is simple method contextmenu.show for displaying context menus. Is it possible and if is, then how to use javaobject library to achieve that?
 
Upvote 0

Daestrum

Expert
Licensed User
Longtime User
That's really odd as I do not get the text version only what I add.

Is your textfield added with the designer or code ?
 

Attachments

  • context menu.jpg
    context menu.jpg
    43.2 KB · Views: 334
Upvote 0

MuuSer

Member
Licensed User
Longtime User
My screenshot is from your posted code - so it added with code, which is a way I need. But if I add contextmenu items in designer - the same happens. And for clarification - my system is Win7 x64.
 
Upvote 0

Daestrum

Expert
Licensed User
Longtime User
The only way I can see the 'text' version of the contextmenu is to right click a textfield I added to the contextmenu, so I see a contextmenu whilst in a contextmenu.

Are you using Java 7 or 8 ?
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
Here is a small example:
B4X:
Sub Process_Globals
   Private fx As JFX
   Private MainForm As Form
   Dim cm As ContextMenu
   Dim b As Button
End Sub

Sub AppStart (Form1 As Form, Args() As String)
   MainForm = Form1
   MainForm.Show
   cm.Initialize("cm")
   Dim mi As MenuItem
   mi.Initialize("item 1", "item1")
   cm.MenuItems.Add(mi)
   b.Initialize("b")
   MainForm.RootPane.AddNode(b, 100, 100, 100, 100)
End Sub

Sub MainForm_MouseClicked (EventData As MouseEvent)
   Dim jo As JavaObject = cm
   jo.RunMethod("show", Array(b, MainForm.WindowLeft + b.Left + 20, _
     MainForm.WindowTop + b.Top + 50))
End Sub

Sub item1_Action
   Log("click")
End Sub
 
Upvote 0

Saverio

Member
Licensed User
Longtime User
This don't work for me

B4X:
  jo.RunMethod("show", Array(b, MainForm.WindowLeft + b.Left + 20, _
    MainForm.WindowTop + b.Top + 50))

Should be ... and work for me
B4X:
  jo.RunMethod("show", Array as Object(b, MainForm.WindowLeft + b.Left + 20, _
    MainForm.WindowTop + b.Top + 50))
 
Upvote 0

Daestrum

Expert
Licensed User
Longtime User
@Saverio
The 'Array As Object' is needed if you are not running the latest version of B4J.
The latest version (2.2) allows you to omit the 'As Object' on an array in most cases.
 
Upvote 0

Saverio

Member
Licensed User
Longtime User
How to add a Separator in a ContextMenu?
I have tried with "-" but got just the that sign.

Thanks
 
Upvote 0

MuuSer

Member
Licensed User
Longtime User
Maybe this helps:
B4X:
Dim SMI As JavaObject
SMI.InitializeNewInstance("javafx.scene.control.SeparatorMenuItem",Null)
YourContextMenuName.MenuItems.InsertAt(YourContextMenuName.MenuItems.Size,SMI) 'Append separator to the end of menu
;)
 
Upvote 0

Saverio

Member
Licensed User
Longtime User
@MuuSer,
Thank you anyway, but I'm already working on it...
B4X:
Sub Process_Globals
  Private fx As JFX
  Private MainForm As Form
  Dim cm As ContextMenu
  Dim mi As MenuItem
  Dim jBeep As JavaObject
  jBeep.InitializeStatic("java.awt.Toolkit")
  jBeep = jBeep.RunMethod("getDefaultToolkit", Null)
  Dim lb1 As Label
  Dim jo As JavaObject
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
'  MainForm.Resizable = False
'  MainForm.SetFormStyle("UTILITY")
      lb1.Initialize("")
      MainForm.RootPane.AddNode(lb1, 100,300,300,100)
      MainForm.Show

    Dim smiClass As String = "javafx.scene.control.SeparatorMenuItem"
    Dim smi() As Object = Array(jo.InitializeNewInstance(smiClass,Null), _
                                jo.InitializeNewInstance(smiClass,Null))

    cm.Initialize("")
    mi.Initialize("MenuItem1","MenuItem1")
    cm.MenuItems.Add(mi)
    cm.MenuItems.Add(smi(0))
    mi.Initialize("MenuItem2","MenuItem2")
    cm.MenuItems.Add(mi)
    cm.MenuItems.Add(smi(1))
    mi.Initialize("MenuItem3","MenuItem3")
    cm.MenuItems.Add(mi)
    

End Sub
Sub MainForm_MouseReleased(mData As MouseEvent)

    jo = cm
    If mData.SecondaryButtonPressed  Then
     jo.RunMethod("show", Array(MainForm.RootPane, _
      MainForm.WindowLeft + MainForm.WindowWidth - MainForm.Width - 8 + mData.x, _
      MainForm.WindowTop + MainForm.WindowHeight - MainForm.Height - 8 + mData.y))
    Else
     jo.RunMethod("hide",Null)
    End If
End Sub

Sub MenuItem1_Action
    lb1.Text = "MenuItem1 was fired"
    Beep
End Sub
Sub MenuItem2_Action
    lb1.Text = "MenuItem2 was fired"
    Beep
End Sub
Sub MenuItem3_Action
    lb1.Text = "MenuItem3 was fired"
    Beep
End Sub
Sub Beep
  jBeep.RunMethod("beep", Null)
End Sub

Now what I'm trying to do is collect al MenuItems event processor in just one and then
try to get which MenuItem has fired the event. Something that get MenuItem Name or Tag.
May it be already done by reflection. I have to discover it. Or installing some Handler....
I'm working on it
 
Upvote 0

MuuSer

Member
Licensed User
Longtime User
Instead of:
B4X:
cm.Initialize("")
mi.Initialize("MenuItem1","MenuItem1")
cm.MenuItems.Add(mi)
cm.MenuItems.Add(smi(0))
mi.Initialize("MenuItem2","MenuItem2")
cm.MenuItems.Add(mi)
cm.MenuItems.Add(smi(1))
mi.Initialize("MenuItem3","MenuItem3")
cm.MenuItems.Add(mi)

use:
B4X:
cm.Initialize("")
mi.Initialize("MenuItem1","MenuItem")
cm.MenuItems.Add(mi)
cm.MenuItems.Add(smi(0))
mi.Initialize("MenuItem2","MenuItem")
cm.MenuItems.Add(mi)
cm.MenuItems.Add(smi(1))
mi.Initialize("MenuItem3","MenuItem")
cm.MenuItems.Add(mi)
...
Sub MenuItem_Action
     Dim Mitem as MenuItem = Sender
     lb1.Text = Mitem.Text & " was fired"
     Beep
End Sub
 
Upvote 0

Saverio

Member
Licensed User
Longtime User
Arrgh! I knew, it was easy Thank you.

But, as is, is not working.
I think <mi> must be an array, otherwise sender will get last mi.Initialize...
I'll try
 
Upvote 0
Top