B4J Code Snippet MenuBar Create Dynamically FontAwesome Icon

Example creating dynamically FontAwesome icons for a MenuBar.

This solution, see Sub TextToImage, uses a label which font is set to FontAwesome, add to a pane, followed by a screenshot which creates the image and then make the label invisible.
The image is added to the menu items via a list.

Their might be other ways to create an image from text, but this solution is working fine.


upload_2018-4-9_11-24-21.png


MenuBar1 Menu JSON string defined in the Visual Designer
B4X:
[
  {Text: "_Navigation", Children:
    [
     {Text: "Menu_Navigation_First", Tag: "File_Navigation_First", EventName: "Menu_Navigation_First"},
     {Text: "Menu_Navigation_Next", Tag: "File_Navigation_Next", EventName: "Menu_Navigation_Next"},
     {Text: "Menu_Navigation_Prev", Tag: "File_Navigation_Prev", EventName: "Menu_Navigation_Prev"},
     {Text: "Menu_Navigation_Last", Tag: "File_Navigation_Last", EventName: "Menu_Navigation_Last"}
    ]
  }
]

B4X:
Sub Process_Globals
   Private fx As JFX
   Private MainForm As Form
   Private Menu_Items As Map
   Private MenuBar1 As MenuBar
End Sub

Sub AppStart (Form1 As Form, Args() As String)
   MainForm = Form1
   ' The layout contains a menubar with JSON string as shared previous
   MainForm.RootPane.LoadLayout("Main")
   MainForm.Show
   AppInit
End Sub

Sub AppInit
   Menu_Items.Initialize
   Menu_Items = MenuBar_Items(MenuBar1)
   MenuBar_MenuItem_SetImage(Menu_Items , "File_Navigation_First", TextToImage(MainForm.RootPane, Chr(0xF0AA), 16))
   MenuBar_MenuItem_SetImage(Menu_Items , "File_Navigation_Next", TextToImage(MainForm.RootPane, Chr(0xF063), 16))
   MenuBar_MenuItem_SetImage(Menu_Items , "File_Navigation_Prev", TextToImage(MainForm.RootPane, Chr(0xF062), 16))
   MenuBar_MenuItem_SetImage(Menu_Items , "File_Navigation_Last", TextToImage(MainForm.RootPane, Chr(0xF0AB), 16))
End Sub

' Build the menubar items as map
Public Sub MenuBar_Items(MnuBar As MenuBar) As Map
   Dim menus As Map
   menus.Initialize
   CollectMenuItems(menus, MnuBar.Menus)
   Return menus
End Sub

' Collate the menu items as a list - used by MenuBar_Items
Private Sub CollectMenuItems(Menus As Map, Items As List)
   For Each mi As MenuItem In Items
       If mi.Tag <> Null And mi.Tag <> "" Then Menus.Put(mi.Tag, mi)
       If mi Is Menu Then
           Dim mn As Menu = mi
           CollectMenuItems(Menus, mn.MenuItems)
       End If
   Next
End Sub

' Set an image for a menuitem
Public Sub MenuBar_MenuItem_SetImage(MenuItems As Map, Item As String, Img As Image)
   Dim mi As MenuItem = MenuItems.Get(Item)
   If mi.IsInitialized Then
       mi.Image = Img
   End If
End Sub

' Convert text string to an image using a hidden label.
' Example with FontAwesome:
' Dim img As Image = TextToImage(MainForm.RootPane, Chr(0xF0AA), 16)
' This can be used to add f.e. a fontawesome icon dynamically to a menu item:
' Dim mi As MenuItem ... mi.Image = img
Sub TextToImage(p As Pane, s As String, FontSize As Double) As Image
   Dim img As Image
   Dim lbl As Label
   lbl.Initialize("lbl")
   lbl.Font = fx.CreateFontAwesome(FontSize)
   lbl.Text = s
   p.AddNode(lbl, -1, -1, -1, -1)
   img = lbl.Snapshot
   lbl.Visible = False
   Return img
End Sub

EDIT: 2018-04-09
Another solution is to define a global label and use it for the snapshot.
B4X:
' Convert fontawesome string to an image using a label created with the visual designer.
' Private Label1 As Label
' Dim img As Image = FontAwesomeToImage(Chr(0xF0AA), 16)
' This can be used to add f.e. a fontawesome icon dynamically to a menu item:
' Dim mi As MenuItem ... mi.Image = img
Sub FontAwesomeToImage(s As String, FontSize As Double) As Image
   Dim img As Image
   Label1.Text = s
   Label1.TextSize = FontSize
   Label1.Visible = True
   img = Label1.Snapshot
   Label1.Visible = False
   Return img
End Sub

EDIT: 2018-04-10
With
B4X:
    img = Label1.Snapshot2(fx.Colors.Transparent)
the image has a transparent background when selecting the menu item.
 
Last edited:
Top