Confued as to how to add handler to MenuItem

Hello, trying to populate a menu with devices which I have done, but how do I then assign the method to run for each one in my code (which is in the EnableMenuItems event)? I would want the m.tag to be passed to the method. Or am I approaching this wrong?
There’s an example for this in the Documentation for the DesktopMenuItem but I am just using MenuItem and I cannot seem to get ‘MenuBarSelected’ to work.

dim i,c as integer
dim info as PortMidiDeviceInfoMBS

do until OpenOutputMenu.LastRowIndex = -1 //delete all current menu's
  OpenOutputMenu.RemoveMenuAt(0)
loop

// Show the device list
c=p.CountDevices-1

for i=0 to c
  info=p.DeviceInfo(i)
  
  if info<>Nil then
    if info.HasOutput then //only show outputdevices
      
      Var m As New MenuItem(info.Name)
      m.Name = info.Name
      m.Text = info.Name
      m.Tag = i
      // code here for action??
      OpenOutputMenu.AddMenu(m)
      
    end if
  end if
  
next

Thanks

Right-click on the app icon of your app in the navigation pane and select Add Menu Handler. Then in the Inspector you choose which menu item you want to add the handler for. Then put the code in there, for that menu item. You won’t be using MenuBarSelected for this.

Assignment of the Text and Tag properties is taken care of by the Constructor:

Var m As New MenuItem(info.Name,i)
m.Name = info.Name // (If you actually need to name it)

The code to be executed when the user selects the menu item goes in a MenuHandler, as TIm said.

1 Like

Thanks Tim, Yes I have done that previously for lots of other static menus. And I’ve finally got a message box to show up on selecting one of the dynamic menues by setting the m.name to “OpenOutputMenu” and then putting the code in the Menu Handler. But I’m still confused as to how you independently identify the specific menu that was selected say by a variable (can you do it by the ‘tag’?). The no of menu that could be populated isn’t always going to be the same.
There is ‘select case hitItem’ but I think that only works ContextualMenuAction, I am not sure if I should be using that or how?

Another solution would be to subclass DesktopMenuItem. Then you could implement the events directly.

Thanks so I have the (OpenOutputMenu) menu handler firing now when I select one of the menus using the code below. I seem to need to have the m.name for work so the event handler. The problem is the device names and the tag is always going to be different so I cannot just add a handler in the xojo because these are variables. Can the OpenOutputMenu check/retrieve for i so that it know what menu was pressed or can i be called so it can in the used handler code? or do I need to use AddHandler in the code below and then reference a method or something?

in other words I want a put a script in when the user presses the menu option that it will open that midi device and I need to know i / tag for that within the script.


Var m As New MenuItem(info.Name,i)
m.Name = "OpenOutputMenu"

OpenOutputMenu.AddMenu(m)

I tried this, and it wanted me to convert all the windows to DeskopWindows too, and so I did… Then 214 compile errors because I already have a lot of code using a standard listbox… surely there is another way?

You’re adding a bunch of MenuItems to the OpenOutputMenu, so I don’t think you want to name any of those items “OpenOutputMenu”.

You probably want to subclass MenuItem. Scroll way down on this page

https://documentation.xojo.com/api/deprecated/menuitem.html#menuitem

to the section on dynamic menus.

" In certain cases you cannot specify the menu items that belong in a menu in advance. They may change depending on the context in which the application is used or on the operating system on which the application is running.

A common example of this is the Font menu that is normally included in any application that supports styled text. The programmer has no way of knowing in advance which fonts happen to be installed on the user’s computer. The Font menu’s menuitems have to be built dynamically when the application is launched.

The recommended technique is to create a subclass of MenuItem in the Project Window. To create the menuitems, you use the MenuItem’s constructor to instantiate an instance of the class for each MenuItem you need. You handle the MenuItem in the Action event."

For example, I made a MenuItem subclass for making a “Recent Files” menu:

Screen Shot 2023-05-25 at 9.18.43 AM

Once you have a subclass, you can add properties, customize the Constructor, etc. Add the Action event handler in the IDE and put whatever code you want in there. You can tell which item was selected by checking Name or Text or Tag.

Yes, this is how I do it. Subclass DesktopMenuItem, and build your menus using new instances of the subclass. That subclass will then have the MenuItemSelected event directly available to it.

Is this an old app? If it’s a new one, why were you not already using DesktopWindows?

OK so went to the effort of converting the code to work with the desktop thingy ma bob (almost - just a few lines I commented out that I need to figure out). And I’ve used this code with a method:

Var m As New DesktopMenuItem(info.Name,i)
m.Name = info.Name
AddHandler m.MenuBarSelected, AddressOf ActionMethod // We assign the Delegate Method as the Action to execute
OpenOutputMenu.AddMenu(m)

And ugh now I’m getting this

Type mismatch error. Expected delegate Delegate( DesktopMenuItem ), but got delegate Delegate( DesktopMenuItem ) as Boolean
AddHandler m.MenuBarSelected, AddressOf ActionMethod // We assign the Delegate Method as the Action to execute

If I remove the boolean from the ActionEvent method and the ‘return true’, then it compiles but goes on a loop with the messgebox, so I assume this boolean is needed. I’ve just done the same thing as in the documentation for DestopMenuItems basically, but I probably need to have a break and come back to it. It’s like I get so close and then it doesn’t want me to be able to do this.

I doubt you want to handle this event - it fires when the user clicks on anything in the MenuBar. You probably intended m.MenuItemSelected.

As to your Type mismatch, your ActionMethod method would need to have as its first parameter a variable of type MenuItem, e.g.

ActionMethod(sender as MenuItem)

Subclassing MenuItem obviates the need for AddHandler, since the Action event can be implemented in the IDE.

2 Likes

Thanks alot Julia, Think I’ve got it now, changing it to MenuItemSelected worked and got rid of the type mismatch. I realised now because with this project I have been learning from the ground up and I copied a couple things from a example project to get me started early on hence why I was still using alot of the old non ‘Desktop’ code (the example must have been using old type list boxes or something).

1 Like

Doesn’t seem to work with Menuitem and the .Action event, sadly.

AddHandler and MenuItem.Action is working fine for me. I converted Norman’s example from the other forum into API 1.0 / Pre-Desktop controls: https://xojo.dev/IXm6YXv2

1 Like

Odd. I did exactly the same, nothing.
I’ll try your project. Maybe I made a booboo

Edit:
No, I didn’t. My code ended up the same as yours, but when placed into my actual project, it didnt work.
The menu I have in mind for this is specific to a Window
When I put the code into the Window’s open event, it doesn’t work FOR ME because the Open event of the window never fires. (A problem I have had to work around for 15 years)
But putting it inside a ‘run once’ section of code that I have in activate() event, works fine. Hurrah.

How can that be? Don’t think I’ve ever encountered that one.

How can that be?

No idea.
But I promise you, code in the Open() event of that window in that project does not run, and no breakpoint is ever hit. I’ve tried all kinds of tests for corruption, file formats…

I gave up scratching my head over it years ago (although sometimes it catches me out again like this) , and like most things, once I had a workaround, I just kept going.

Can you make a small example project demonstrating the iss… just kidding!!! :joy:

1 Like

Jeff, does this window have a constructor?
Norman has a theory (and example project).
NoOpenEvent.xojo_binary_project

Personally, I don’t do any window setup in constructors or open. I always use a window setup function (usually called Display) that fills all the fields and lastly shows the window. This has always worked for me, I don’t end up with race conditions or non-existent controls.

2 Likes