Get Text() & Tag() arrays from a MenuItem

Say we have a MenuItem with three selectable options in it, constructed like so:

Category: Option 1 Option 2: SubOption 1 SubOption 2

and we want a string array representation of this that looks like so:

item(0) Category: Option 1
item(1) Category: Option 2: SubOption 1
item(2) Category: Option 2: SubOption 2

and we want to get a corresponding array of tags from the menu also, like so:

tag(0) … the tag for the MenuItem corresponding to item(0) above
tag(1) … the tag for the MenuItem corresponding to item(1) above
tag(2) … the tag for the MenuItem corresponding to item(2) above

For some reason I can’t figure out how to do this. I’ve done similar things for file hierarchies, but folderitems are quite different to work with. It seems trying to write a recursive algorithm fails here. I’ve written a couple of methods a few times and I’m getting nowhere. It needs to be generalised to be able to return strings and tags for any menu. Any ideas?

EDIT: said another way, what I’m after for the string part is the equivalent of a file path, but for a MenuItem … a “MenuPath” if you will.

Actually I’ve got the tags part working. The following 2 methods work:

Public Function TagArrayFromMenuItem(m as MenuItem) as variant()
  // return an array of tags (variants) from the menuitem
  ' get only the tags of the terminal menu items 
  ' (those that can be selected by the user)
  dim v() as variant
  dim i() as MenuItem = GetTerminalMenuitemsFromMenu( m )
  for j as integer = 0 to i.Ubound
    v.append i(j).Tag
  next
  
  return v()
End Function

Public Function GetTerminalMenuitemsFromMenu(m as MenuItem) as MenuItem()
  // return only those menuitems from a menu that the user can actually select
  dim j, k as integer
  dim t() as MenuItem
  if m.Count = 0 then
    ' terminal menu item
    t.append m
  else
    ' has submenu
    for j = 0 to m.Count-1
      dim item as MenuItem = m.item(j)
      if item.count = 0 then
        ' terminal menu item
        t.append item
      else
        ' has submenu
        dim ss() as menuItem = GetTerminalMenuitemsFromMenu( item )
        for k = 0 to ss.Ubound
          t.append ss(k)
        next
      end if
    next
  end if
  
  return t()
End Function

As you can see, GetTerminalMenuitemsFromMenu() is recursive. I would use this same approach for the strings, but the problem is that with MenuItems I don’t seem to have access to the item’s parent (the way we do with FolderItems). So I can’t reconstruct the string as a “path” to the terminal MenuItem.

Pass the “path built so far” into the recursive call

I did try that, and the problem is that I can’t figure out how to build the path. It seems like a simple thing, but as far as I can tell it isn’t simple to do. I’m obviously missing something.

The following does not give correct results:

[code]Public Function MenuPathsFromMenu(m as MenuItem, pathParts() as string, delimiter as string = ", ") as string()
// return an array of string paths using the given delimiter
’ only to those menuitems that the user can actually select

dim j, k as integer
dim paths() as string
pathParts.append m.text
if m.Count = 0 then
’ terminal menu item
paths.append join( pathParts, delimiter )
redim pathParts(-1)
else
’ has submenu
for j = 0 to m.Count-1
dim item as MenuItem = m.item(j)
pathParts.append item.text
if item.count = 0 then
’ terminal menu item
paths.append join( pathParts, delimiter )
redim pathParts(-1)
else
’ has submenu
dim ss() as string = MenuPathsFromMenu( item, pathParts(), delimiter )
for k = 0 to ss.Ubound
paths.append join( pathParts, delimiter ) + delimiter + ss(k)
next
redim pathParts(-1)
end if
next
end if

return paths()
End Function[/code]

HUGE grain of salt this is written entirely in the forum editor so …

Public Function TagArrayFromMenuItem(m as MenuItem) as variant()
  // return an array of tags (variants) from the menuitem
  ' get only the tags of the terminal menu items 
  ' (those that can be selected by the user)
  dim v() as variant
  dim i() as Pair = GetTerminalMenuitemsFromMenu( m, m.name )
  for j as integer = 0 to i.Ubound
    v.append i(j).Left.Tag
  next
  
  return v()
End Function

Public Function GetTerminalMenuitemsFromMenu(m as MenuItem, pathsofar as string) as Pair()
  // return only those menuitem/path pairs from a menu that the user can actually select
  dim j, k as integer
  dim t() as Pair
  if m.Count = 0 then
    ' terminal menu item
    t.append new Pair(m, pathsofar + "." + m.name)
  else
    ' has submenu
    for j = 0 to m.Count-1
      dim item as MenuItem = m.item(j)
      if item.count = 0 then
        ' terminal menu item
        t.append new Pair(item, pathsofar + "." + m.name)
      else
        ' has submenu
        dim ss() as pair = GetTerminalMenuitemsFromMenu( item, pathsofar + "." + item.name )
        for k = 0 to ss.Ubound
          t.append ss(k)
        next
      end if
    next
  end if
  
  return t()
End Function


Public Function TextArrayFromMenuItem(m as MenuItem) as String()
  // return an array of paths 
  ' get only the paths to the terminal menu items 
  ' (those that can be selected by the user)
  dim v() as string
  dim i() as Pair = GetTerminalMenuitemsFromMenu( m, m.name )
  for j as integer = 0 to i.Ubound
    v.append i(j).Right
  next
  
  return v()
End Function

Thank you. I like your version using Pair which I have never used. At first the results were wrong due to one small error: the second m . name needs to be item . name. Then it works! :slight_smile:

Here is my edited version:

Public Function GetTagsAndPathsFromMenu(m as MenuItem, pathsofar as string = "", delimiter as string = ", ") as Pair()
  // return only those menuitem/path pairs from a menu that the user can actually select
  ' 24. May 2017 solved with help from Norman Palardy
  ' https://forum.xojo.com/40821-get-text-tag-arrays-from-a-menuitem
  dim j, k as integer
  dim t() as Pair
  if m.Count = 0 then
    ' terminal menu item
    t.append new Pair( m.tag, pathsofar + delimiter + m.text )
  else
    ' has submenu
    for j = 0 to m.Count-1
      dim item as MenuItem = m.item(j)
      if item.count = 0 then
        ' terminal menu item
        t.append new Pair( item.tag, pathsofar + delimiter + item.text )
      else
        ' has submenu
        dim ss() as pair = GetTagsAndPathsFromMenu( item, pathsofar + delimiter + item.text )
        for k = 0 to ss.Ubound
          t.append ss(k)
        next
      end if
    next
  end if
  
  return t()
End Function

Thank you very much, Norman Palardy. This turned out to be a good example of when to use the Pair object, which I had forgotten even existed in Xojo.

Hence why I said

I can see now the forum needs Xojo code autocompletion etc :stuck_out_tongue:

[quote=332503:@Aaron Hunt]Thank you. I like your version using Pair which I have never used. At first the results were wrong due to one small error: the second m . name needs to be item . name. Then it works! :slight_smile:

Here is my edited version:

[code]
Public Function GetTagsAndPathsFromMenu(m as MenuItem, pathsofar as string = “”, delimiter as string = ", ") as Pair()
// return only those menuitem/path pairs from a menu that the user can actually select
’ 24. May 2017 solved with help from Norman Palardy
https://forum.xojo.com/40821-get-text-tag-arrays-from-a-menuitem
dim j, k as integer
dim t() as Pair
if m.Count = 0 then
’ terminal menu item
t.append new Pair( m.tag, pathsofar + delimiter + m.text )
else
’ has submenu
for j = 0 to m.Count-1
dim item as MenuItem = m.item(j)
if item.count = 0 then
’ terminal menu item
t.append new Pair( item.tag, pathsofar + delimiter + item.text )
else
’ has submenu
dim ss() as pair = GetTagsAndPathsFromMenu( item, pathsofar + delimiter + item.text )
for k = 0 to ss.Ubound
t.append ss(k)
next
end if
next
end if

return t()
End Function
[/code][/quote]

Ok I got it, Its very good! In fact. It gets the Path of the MenuItem

I dunno if I’m doing it correctly:

 if menuchoice<>nil then
    Dim nuu() As Pair
    nuu = GetTagsAndPathsFromMenu(MenuContribuyentes)
    
    For i as integer = 0 to nuu.Ubound
      Msgbox Str(nuu(i).Left.StringValue + ", " + nuu(i).Right.StringValue).Replace(", , ","")
    Next
    
  end if

So at This way I Test the method.

But How can I apply it to get the path of selected Menu.

Example:

As you can see Thats how it looks my menu, and I’m Selecting this: Invoices / 2014 / Nov
Main Menu
Invoices
2016
Jan
Feb
Mar
Apr
2015
Jul
Dec
2014
Aug
Mar
Nov
2013
Oct
Dic
Credit Notes
2017
Nov
Dic
2014
Jul
Sep
2011
Jan
Dic
Payroll Receipt
2001
Jan
Mar
Apr
2000
Jul
Sep
1999
Nov
Dic
Employees
2011
2008
2002

So how can I Use the method to get the path of my selected item, in order to Process it.
Regards

[quote=362654:@Gerardo García]Ok I got it, Its very good! In fact. It gets the Path of the MenuItem

I dunno if I’m doing it correctly:

 if menuchoice<>nil then
    Dim nuu() As Pair
    nuu = GetTagsAndPathsFromMenu(MenuContribuyentes)
    
    For i as integer = 0 to nuu.Ubound
      Msgbox Str(nuu(i).Left.StringValue + ", " + nuu(i).Right.StringValue).Replace(", , ","")
    Next
    
  end if

So at This way I Test the method.

But How can I apply it to get the path of selected Menu.

Example:

As you can see Thats how it looks my menu, and I’m Selecting this: Invoices / 2014 / Nov
Main Menu
Invoices
2016
Jan
Feb
Mar
Apr
2015
Jul
Dec
2014
Aug
Mar
Nov
2013
Oct
Dic
Credit Notes
2017
Nov
Dic
2014
Jul
Sep
2011
Jan
Dic
Payroll Receipt
2001
Jan
Mar
Apr
2000
Jul
Sep
1999
Nov
Dic
Employees
2011
2008
2002

So how can I Use the method to get the path of my selected item, in order to Process it.
Regards[/quote]
Sorry for my Stubbornness, I discovered that MenuItem also have TAG property, just like Listbox.Cell
That its only accessible via code, and not displayed

So then I analyze the TAG of selected MenuItem ignorer to know what to do.

Thanks :D. :smiley: