AppKit "setMenu:forSegment:"

Hi,

I try to connect a DesktopSegmentedButton with a DesktopMenuItem via AppKit Declare setMenu:forSegment:. Sadly the App crashes using this code. Where’s the error?

Var menu As New DesktopMenuItem

menu.AddMenu(New DesktopMenuItem("Import"))
menu.AddMenu(New DesktopMenuItem("Export"))
menu.AddMenu(New DesktopMenuItem(DesktopMenuItem.TextSeparator))

menu.AddMenu(New DesktopMenuItem("Cut"))
menu.AddMenu(New DesktopMenuItem("Copy"))
menu.AddMenu(New DesktopMenuItem("Paste"))

' https://developer.apple.com/documentation/appkit/nssegmentedcontrol/1528853-setmenu?language=objc
Declare Sub setMenuForSegment Lib "AppKit" Selector "setMenu:forSegment:" (id As Ptr, menu As Ptr, segment As Int64)
setMenuForSegment(SegmentedButton1.Handle, menu.Handle, 1)

What does the crash log say? If you post that someone can probably help figure that out.

*** Terminating app due to uncaught exception ‘NSInvalidArgumentException’, reason: ‘+[NSMenuItem _recursivelyUnregisterMenuForKeyEquivalentUniquing:]: unrecognized selector sent to class 0x7ff85c83c080’
abort() called
terminating with uncaught exception of type NSException

Because you need to create a NSMenu and attach the items to that, then add the NSMenu to the Segmented control.

Do a NSObject_desription on the Xojo menu.handle and it should report as a NSMenuItem.

Thanks @Sam_Rowlands, can you please show me how? How can I bind DesktopMenuItem to NSMenu?

You can remedy this by just using an array and making your own NSMenu

Var items() As DesktopMenuItem

items.Add(New DesktopMenuItem("Import"))
items.Add(New DesktopMenuItem("Export"))
items.Add(New DesktopMenuItem(DesktopMenuItem.TextSeparator))

items.Add(New DesktopMenuItem("Cut"))
items.Add(New DesktopMenuItem("Copy"))
items.Add(New DesktopMenuItem("Paste"))


// make an NSMenu
Declare Function alloc Lib "Foundation" selector "alloc" (cls as ptr) as ptr
Declare Function init Lib "Foundation" selector "init" (cls as ptr) as ptr
Declare Function NSClassFromString Lib "Foundation" (name as cfstringref) as ptr
// - (void)addItem:(NSMenuItem *)newItem;
Declare Sub addItem Lib "AppKit" Selector "addItem:" ( obj as ptr , newItem as Ptr )

var NSMenu as ptr = init(alloc(NSClassFromString("NSMenu")))
for i as integer = 0 to UBound(items)
  addItem(NSMenu, items(i).Handle)
next i

' https://developer.apple.com/documentation/appkit/nssegmentedcontrol/1528853-setmenu?language=objc
Declare Sub setMenuForSegment Lib "AppKit" Selector "setMenu:forSegment:" (id As Ptr, menu As Ptr, segment As Int64)
setMenuForSegment(SegmentedButton1.Handle, NSMenu, 1)

Keep in mind that according to the Apple docs, if the segment has an action on it (which in Xojo they do), the user will have to press and hold for the menu to appear.

1 Like

Looks like Greg beat me to it.

IIRC it can be removed by setting a nill action on the control, but I’ve never actually tried this.

Don’t forget to release the NSMenu once you’ve attached it to segmented control (as it was created with alloc).

1 Like

Thanks @Greg_O for the explanations and the code example. The next question is how to activate the menu entries? Currently all are disabled and how to catch the click event and react to it?

Use AddHandler to map the events of DesktopMenuItem to a method.