How to populate a popup button with NSArrayController and bindings

This is my very first attempt at using an NSArrayController, so please bear with some very basic questions.

I would like to display to the user a popup button whose menu items have the names “Name1”, “Name2”, . Each name is associated with a value, “Value1”, “Value2”, . When the user selects a name, I would like to do things in my controller script (MainScript) with the corresponding value. Based on some examples I found through searching, I’ve tried the following:

(1) In MainScript, I’ve created a list of NSDictionary items as follows:

property recordList : {}
set nameList to {"Name1", "Name2", "Name3"}
set valueList to {"Value1", "Value2", "Value3"}
repeat with i from 1 to nameList's length
	set end of my recordList to current application's NSDictionary's dictionaryWithObject_forKey_(valueList's item i, nameList's item i)
end repeat

(2) In the interface window, I’ve brought an NSArrayController object into the window and bound its Controller Content to MainScript with Model Key Path set to recordList.

(3) In the interface window, I’ve brought an NSPopUpButton into the window and made the following bindings:
NSPopUpButton’s Content bound to the NSArrayController with Controller Key set to arrangedObjects
NSPopUpButton’s Content Objects bound to the NSArrayController with Controller key set to arrangedObjects, and Model Key Path set to value
NSPopUpButton’s Content Values bound to the NSArrayController with Controller key set to arrangedObjects, and Model Key Path set to name

I build and run, and the popup button has no content. Also, if I create an outlet called arrayControllerOutlet in MainScript to the NSArrayController object and send it the message:

tell my arrayControllerOutlet to its content()

it returns an empty list.

Where am I going wrong? Why is the popup button not getting populated?

Hi,

just to populate NSPopupButton once the simple method to add the items programmatically might be more reasonable.
You can assign a representedObject “ the value in your example “ to NSMenuItem.
In the IBAction you get the value with sender’s selectedItem()'s representedObject()

How can that work? You don’t have a key called value. In fact, you’re records don’t have a key in common, and I suspect that’s where your problem is (or at least starts).

I picked up on that major mistake after submitting the post. Those Model Key Path values came from the example I had tried to copy from. I have since tried setting up properties and using the property names as the Model Key Path. Also tried using the NSDictionary key values without success.

Besides what to enter for Model Key Path, another big stumbling block is what to enter for the NSArrayController’s Object Controller attribute. I’ve set “Mode” to Class but am at a loss what to set “Class Name” and “Keys” to. The various discussions I’ve read all seem to indicate that these fields must be filled in, but with what?

I’m fumbling around in the dark. Wish there were a cookbook example just to get off the ground. :slight_smile:

I wonder whether you’re over-complicating things. Why not skip the array controller, use a simple list of values in a property, and bind directly to that?

That’s right; Entity is only for Core Data users.

You can ignore Keys. Class Name means the class of the objects in the list your are binding to. Unless you are planning to use a custom class, leave it at NSMutableDictionary – that means you are binding to a list of mutable dictionaries.

Well I know a book that has samples of binding tables via array controllers, and binding popup menus directly…

I bound a list of titles directly to the popup button as you suggested, and it populated perfectly.

What I can’t get to work is binding with an NSArrayController. “Well I know a book.” Yes, your book is outstanding, the sine qua non of ASObjC programming. But I haven’t had success adapting the table example in your book to my popup button. I left the NSArrayController’s Object Controller’s Class Name at NSMutableDictionary and did not enter any Keys. In MainScript, I created an array of NSMutableDictionary’s as follows:

property recordList : {}
set nameList to {"Name1", "Name2", "Name3"}
set valueList to {"Value1", "Value2", "Value3"}
repeat with i from 1 to nameList's length
	set end of my recordList to current application's NSDictionary's dictionaryWithObjects_forKeys_({nameList's item i, valueList's item i}, {"nameKey", "valueKey"})
end repeat

I then bound the NSArrayController’s content array to MainScript with a Model Key Path of recordList. I turned on "“Handles Content As Compound Value” as you suggested in your book. I then bound the popup button to the NSArrayController as follows:
NSPopUpButton’s Content bound to the NSArrayController with Controller Key set to arrangedObjects
NSPopUpButton’s Content Objects bound to the NSArrayController with Controller key set to arrangedObjects, and Model Key Path set to valueKey
NSPopUpButton’s Content Values bound to the NSArrayController with Controller key set to arrangedObjects, and Model Key Path set to nameKey

But it’s still not working. The popup button remains unpopulated.

Is it time to give up and go without an NSArrayController as you and Stefan have suggested? I’m partly driven simply by the desire to learn how to use the NSArrayController.

Understood. But it sounds like you’re trying too hard. So here’s a property:

	property recordList : {{nameKey:"Name1", valueKey:"Value1"}, {nameKey:"Name2", valueKey:"Value2"}, {nameKey:"Name3", valueKey:"Value3"}}

Add an array controller, bind its Content array to the script object containing recordList with a Model Key Path of nameKey.

Add a popup button. Bind its Content Values to the array controller with Controller Key arrangedObjects and Model Key Path nameKey.

Run.

I did as you suggested and get the following error message:


I tried a lot of little tweaks to the settings, all to no avail.

Ooops – the array controller should use an Model Key path of recordList. Sorry…

That was one of the tweaks I tried. Still not working. No error messages, but the button remains unpopulated.

Well I’m not making this up :slight_smile: Drop me an email and I’ll send you the project I just did it in…

I have emailed the project, but your email seems to be having problems collecting it…

Shane, your project worked perfectly here (Boston, USA, so geographic factors are not involved!) Furthermore, I created a new mini-project with everything identical to your project, and it too worked perfectly.

I then went back to my original project, which is much larger with many checkboxes, textfields, and other elements, and much more MainScript code, and once again it didn’t work. The popup button doesn’t populate. So something seems to be interfering with the NSArrayController in my larger project. I haven’t a clue what that something might be, but I won’t belabor this discussion trying to find the cause. But at least I now have seen with my own eyes that the NSArrayController-NSPopUpButton-bindings combination works, thanks to your invaluable help.

You might want to check that you haven’t accidentally set up some conflicting binding to a subview of the popup.

I didn’t find any conflicting bindings. I have the feeling that the problem is lurking in some unexpected place and that it would go away if I were to start over with a fresh reproduction of my program.

Hi - I second Stefan’s post in getting to do NSPopUpButton programatically. I worked on a project and found it very enjoyable and rewarding as well. There are delegation and notification methods. You can also implement NSUserDefaults too which is something I have put off but will get to it eventually. There are advantages to using bindings no doubts especially in tableViews.

Good luck.
t.

Hello.

I came by this command line argumen to your app, (which you set in the scheme editor -run arguments) a while a go for logging bindings. It has helped me some when I have been stuck. It is more informative than stack traces, and quells at least some thrown exceptions due to binding errors.

Thank you for the tip about NSBindingDebugLogLevel. Didn’t know about it but I’ll certainly start using it.