Dynamic sub-menus

I have a program with dynamically created menus, but I want to change one of them to fixed menu items, some of which will have sub menus. Initially, the sub menus would be empty with items added (and occasionally deleted) dynamically. So…

  1. How do I add sub menu items dynamically?

  2. How do I delete a sub menu item dynamically?

  3. How do I handle menu selections in the menu handler?

Thanks,
Dan Paymar

MenuItem has an Append method.

MenuItem has a Remove method.

Use AddHandler or Delegates.

As I said, I’m already using dynamically created menus, so I know all of that, but I haven’t figured out how to do it with sub-menus.

MenuItem.Append

As Eli ott said, use append on the submenu, menuitem. They work exactly the same and submenus are really just menuitems (as are their parent menus).

It adds the new item in the main menu, not the sub menu, and it’s not enabled. Some example code would be greatly appreciated.

… needs qualification please. So that it may become possible for others to see that what is being done.

I don’t understand what Syed is asking for.

@Dan: you say “it adds…”. Syed is asking what the “it” stands for.

Instead of adding your menu items dynamically to menus you just need to add the to other menus. There shouldn’t be a difference. Can you post your code if it doesn’t work?

You will need to add a handler to the menuitem using addhandler (see xojo docs) for the (sub) menu item to have an action associated with it, if created dynamically. You can also enable and disable menuitems using

Menuitemname.enabled = true

Demos of both menuitem and addhandler are available in the docs

http://documentation.xojo.com/index.php/MenuItem
http://documentation.xojo.com/index.php/AddHandler

The menu items must be added dynamically because the things to be selected are created during runtime, and sometimes deleted during runtime. And what do you mean by the “other menus”?

There are two pages of code. I could post it here or send it privately.

P.S. to Beatrix: The “it” refers, of course, to the program, my code.

That still tells us nothing we might use to help you. Post some code.

OK, here it is.

This is for the Games menu in a video poker program. The Games menu is created in the editor as follows:
Text Index Name
Jacks or Better 0 GamesJB
All American 1 GamesAA
Bonus Poker 2 GamesBP
Double Bonus 3 GamesDB
etc.
Each has Submenu checked.

=================== Here’s my current code in the method BuildGamesMenu

’ Scan all the files in the Games folder, and build the Games menu

dim x, y, z, n as integer
dim Fname, Gname, Bname as string
dim f as FolderItem
dim m as MenuItem
dim Found as boolean

f = GetFolderItem( “Games” ) ’ Find the Games folder
if not f.directory then FolderError “Games”
n = f.count ’ Confirm that the Games folder is not empty
if n < 1 then FolderError “Games”

z = 0
for x = 1 to n ’ Accumulate game filenames, ignoring hidden Mac files
Fname = f.item( x ).name
if left( Fname, 1 ) = “.” or right( Fname, 4 ) = “.DAT” then continue
Gname = replaceAll( Fname, “-”, “/” )
redim GameNames( z )
GameNames( z ) = Gname
z = z + 1
next
GameNames.sort ’ Alphabetize the game names

DefaultGame = 0 ’ If JoB 9/6 doesn’t exist, the first JoB game will be the default

BuildGnamesArray ’ The Gnames array defines the Games sub-menus structure

’ ******* Everything up to here has been verified to be working properly ********

for x = 0 to z-1 ’ Loop to put the game names in the proper sub-menus
Gname = GameNames( x ) ’ Get a game name
Found = false ’ Flag to be set when a match has been found
for y = 0 to 7 ’ Scan the Gnames array to determine the game category
for z = 0 to 10 ’ Scan this game category for this game name
Bname = Gnames( y, z ) ’ One of the basic game names
if Bname = “” then exit ’ Check if done with this category
if Bname = left( Gname, len( Bname ) ) then ’ Is it a match?
select case Gnames( y, 0 ) ’ yes, append an item in this category
case “JB”
m = new GamesJB
case “AA”
m = new GamesAA
case “BP”
m = new GamesBP
case “DB”
m = new GamesDB
case “DD”
m = new GamesDD
case “TD”
m = new GamesTD
case “DW”
m = new GamesDW
case “JW”
m = new GamesJW
case else
m = new GamesOther
end
m.text = Gname
Found = true
if Gname = “Jacks or Better 9/6” then ’ Save position of default game
DefaultGame = x ’ It’s at this position in the GameNames array
end
exit
end
next z
if Found then exit
next y
next x
EnableMenuItems ’ May be redundant *****

CurrentGame = DefaultGame ’ Select the default game
GameName = GameNames( CurrentGame )
LoadGame( GameName )

exception err
if err isa EndException then
raise err ’ This will be handled in App.UnhandledException
end

=================== Here’s my current code in the method BuildGamesArray

’ This is used to built the Games menu
’ For example, any game name starting with JB, JoB, Jacks or Better, etc.
’ will be category JB, and will be put in the GamesJB sub-menu.

Gnames( 0,0 ) = “JB”
Gnames( 0,1 ) = “JoB”
Gnames( 0,2 ) = “Jacks or Better”
Gnames( 0,3 ) = “AF”
Gnames( 0,4 ) = “Aces”
Gnames( 0,5 ) = “”

Gnames( 1,0 ) = “AA”
Gnames( 1,1 ) = “All American”
Gnames( 1,2 ) = “Gator”
Gnames( 1,3 ) = “”

Gnames( 2,0 ) = “BP”
Gnames( 2,1 ) = “Bonus Poker”
Gnames( 2,2 ) = “”

Gnames( 3,0 ) = “DB”
Gnames( 3,1 ) = “Double Bonus”
Gnames( 3,2 ) = “DJ”
Gnames( 3,3 ) = “Double Jackpot”
Gnames( 3,4 ) = “DF”
Gnames( 3,5 ) = “Double Faces”
Gnames( 3,6 ) = “”

Gnames( 4,0 ) = “DD”
Gnames( 4,1 ) = “Double Double”
Gnames( 4,2 ) = “Dbl Dbl”
Gnames( 4,3 ) = “DblDbl”
Gnames( 4,4 ) = “”

Gnames( 5,0 ) = “TD”
Gnames( 5,1 ) = “Triple Double”
Gnames( 5,2 ) = “”

Gnames( 6,0 ) = “DW”
Gnames( 6,1 ) = “Deuces Wild”
Gnames( 6,2 ) = “FPDW”
Gnames( 6,3 ) = “NSUD”
Gnames( 6,4 ) = “Not So Ugly”
Gnames( 6,5 ) = “BD”
Gnames( 6,6 ) = “Bonus Deuces”
Gnames( 6,7 ) = “DWB”
Gnames( 6,8 ) = “LD”
Gnames( 6,9 ) = “Loose Deuces”
Gnames( 6,10 ) = “”

Gnames( 7,0 ) = “JW”
Gnames( 7,1 ) = “Joker Wild”
Gnames( 7,2 ) = “DJ”
Gnames( 7,3 ) = “Double Joker”
Gnames( 7,4 ) = “”

’ Any game name that doesn’t start with one of the above strings
’ will be put in the “Others” sub-menu

Does that even compile? I would expect

m = new MenuItem
GamesJB.Append m

Yes, it compiles with no error indication, but it doesn’t work.
I changed
m = new GamesJB
to
m = new MenuItem
GamesJB.Append m

and I get a compile error “This method or property does not exist” with the word “Append” highlighted.

Here is the sample code from LR with extra lines for enabling the MenuItem “TestOne” under the “Fonts” menu. This code complies and executes without any error. The code below was added to the “Open” event of Window1 in a new Desktop project in Xojo 2013r2.

  dim m,mNew as MenuItem
  m=self.menubar
  mNew=New MenuItem
  
  mNew.text="Fonts"
  mNew.name="Fonts"
  
  mNew.Append(new menuitem("TestOne"))
  mNew.Append(new menuitem("Testtwo"))
  mNew.Append(new menuitem("Testthree"))
  mNew.Append( new MenuItem( "-" ) )
  
  dim submenu as New Menuitem("MySub")
  
  submenu.Append(new menuitem("submenu One"))
  submenu.Append(new menuitem("submenu Two"))
  submenu.Append(new menuitem("submenu three"))
  
  m.Append mnew
  mNew.Append submenu
  
  //
  // Extra code below if for adding the "Action" event handler and enabling the "Fonts - TestOne" Menuitem
  //
  Dim subMenuItem As MenuItem
  subMenuItem = mNew.Child("TestOne")
  If subMenuItem <> Nil Then
    AddHandler subMenuItem.Action, AddressOf mnuFontsTestOne
    subMenuItem.Enabled = True
  End If

  //
  // Add handlers for other MenuItems here
  //

  //
  // Add a Method with following code to handle the "Fonts - TestOne" "Action" event
  //
  Function mnuFontsTestOne( mnuFT1 As MenuItem) As Boolean
     //
     // Add the required code here
     //
  End Function

Thanks for the sample code, but I’m afraid I don’t understand how to adapt it to my code.

I changed the central loop to:

for x = 0 to z-1 ’ Loop to put the game names in the proper sub-menus
Gname = GameNames( x ) ’ Get a game name
Found = false ’ Flag to be set when a match has been found
for y = 0 to 7 ’ Scan the Gnames array to determine the game category
for z = 0 to 10 ’ Scan this game category for this game name
Bname = Gnames( y, z ) ’ One of the basic game names
if Bname = “” then exit ’ Check if done with this category
if Bname = left( Gname, len( Bname ) ) then ’ Is it a match?
Found = true ’ yes
m = new MenuItem
m.text = Gname
m.name = “Games” + Gnames( y, 0 )
m.append( new MenuItem( Gname ) )
if Gname = “Jacks or Better 9/6” then ’ Save position of default game
DefaultGame = x ’ It’s at this position in the GameNames array
end
exit
end
next z
if Found then exit
next y
next x

and put a breakpoint on the line
m.append( new MenuItem( Gname ) )

When it hits the breakpoint, the menuitem m seems to be correct. In the properties, text is “Aces and Faces” (the first game name in the file), and name is “GamesJB” which is the name of the correct menu item where this should become a submenu item, and enabled is true.

I don’t think the append statement is correct.

Just a detail : when you enter code, click the code icon to make it more readable, and to prevent the forum software for making links out of lines such as m.name = “Games” + Gnames( y, 0 )

m.name  = "Games" + Gnames( y, 0 )