Selected menu item's index

I need help figuring out how to get the index of the selected menu item. When the menu is selected it calls a subroutine like this. I can get the title of the sender and that’s the menu item that was selected. But what if I wanted the index of the item?

on menuSelected_(sender)

end

I found a couple clues on Apple’s page but can’t find a good example of how to phrase that in ASObjC to get a non-error result.

indexOfItem(withTitle:)

I tried stuff like this: menuOutlet’s indexOfItem_withTitle:(“Menu Name”)

https://developer.apple.com/documentation/appkit/nsmenu/1518237-indexofitem

Can anyone nudge me in the right direction here?

You have to get a little circular with your code, here:

set itemIndex to sender's |menu|'s indexOfItem:sender

When you click a menu, it sends a reference to the menu item that was clicked into the ‘sender’ variable. You use the ‘menu’ property of that menu item to get the menu that sent it, and then you ask that menu for the index of the menu item it sent.

That works, sort of… I have some disabled items in the menu and it appears to be returning the index position of the enabled items only, so it’s throwing it off.

Maybe another direction at this is to ask is there a way to set a controllers selection by name…?

Right now I am doing this:

groupListController's setSelectionIndex:(5)

But, given something like this

set sidebarList to {{title:"TEST HEADER", isHeader:true}, {title:"TEST ITEM", isHeader:false}, etc.

Is there a way to do something like:

groupListController's  setSelection:("Test Item")

FYI correction to above… the code you provided is actually returning the correct index number. When I use that number in

groupListController's setSelectionIndex:(numItem)

It goes wonky.

Err… ‘wonky’ is a bit difficult to diagnose. Try going to your doctor and saying “I feel wonky”, and then make sure you do not take whatever she prescribes.

Two possibilities to consider here.

First, AppleScript uses a 1-based index for lists, while Objective-C uses a 0-based index for NSArrays. usually the system figures it out, but if ‘wonky’ means you’re always off by one (e.g. it should do 4 but it does 3), then you may have to account for it manually by adding or subtracting 1 from the index.

Second, one of the functions of NSArrayController is to allow you to sort/filter items in the GUI without sorting them in the model. When you first dump an array into an array controller, the sequence of the model and the GUI should be the same, but if you’ve somehow re-sorted or filtered the controller, then you can’t refer to the model directly using indexes. Best practice is to avoid invoking the model object (in this case, ‘sidebarList’) and always refer to the array controller’s ‘arrangedObjects’ property. That way you’re assured to get the model objects ordered as they are presented in the GUI.

Now it’s “super wonky” and… working. Weird. It’s hard to describe the setup in text…

Menu and Sidebar/Controller

Header (non-selectable in menu and sidebar)
Item 1
Item 2
Header (non-selectable in menu and sidebar)
Item 3
Item 4
etc.

At first the menu would work, selecting item 1, item 2 correctly, based on the index of 1 and 2 (with the header being 0). But once I started selecting item 3, 4, etc. it was off by one or two or varied. In one case, it even selected a non-selectable header in the table when I selected a menu item an index below it.

It DOES seem to work now, so either:

  1. I was delirious this morning.
  2. Rebuild fixed it.
  3. It is a problem that will reappear later due to some other issue.

I’m not explicitly sorting or changing the sidebar once established… but maybe something is affecting it somewhere. I will keep an eye on it for now.

No, still a problem. Derp. I had the test code being override by later code I forgot to comment out. So, there is a selection drift the further I go down the line but its not making a pattern that makes sense to me.

After the first non-selectable heading, it selects item at index 1 and 2 correctly.

Then after the second non-selectable heading, with the item at index 4, 5, 6, it is shifted one lower than it should be.

But then, after the third non-selectable heading, when I select menu item 8 (index) it selects the heading record at index 7 in the table. So, it goes back one.

Then I pick the item at index 9, it thinks I picked 11 and selects that.

So, I’m not sure what to think about that.

Seems wonky is the best description! :slight_smile:

I switched it to this which works:

set listItems to groupListController's arrangedObjects
repeat with a from 1 to count items of listItems
if (title of (item a of listItems)) as string = nameItem then
groupListController's setSelectionIndex:(a-1)
exit repeat
end
end

But that’s a lot more code than I hoped, but it works.

How are constructing/populating the menu? Are you building it manually or hooking it up by bindings in the xib?

Manual menu added to the main menu and wired to the code, calling a subroutine.

Almost certainly the problem is there, in the way you’ve wired it, but without seeing the code… If you can’t debug it, I’ll suggest a left-field solution (which I haven’t tested, but which ought to work in theory). First, when you create each menu item, set its representedObject to the appropriate data source object you want it to invoke:

menuItem's setRepresentedObject:(arrayController's arrangedObjects's objectAtIndex:idx)

Then in your callback handler you can recover the represented object and use it to perform the selection:

on menuSelected_(sender)
    set theObj to sender's representedObject
    arrayController's setSelectedObjects:(NSArray's arrayWithObject:theObj)
end

That shouldn’t be able to ‘wonk’.