1

It it trivial to set up an NSArray containing strings and connect (via an NSArrayController) the content array to an NSPopUpButton (a nice answer for this standard problem is here, NSPopUpButton + Bindings + Show All Option).

I have a NSPopUpButton and want each item in the menu to draw using a view (it has been possible to add views to menu item since 10.5 using the -setView: method of NSMenuItem).

So far I have the following approach.

1) A model object which provides the views,

@interface MenuViewsModel : NSObject
// Array of views for the pop up button to display
@property NSArray *previewViews; 
@end

2) In IB I add an array controller to my XIB and set it's content array as the previewViews of model.

3) Next I bind the NSPopUpView to the array controller:

  • Content - > arrayController.arrangedObjects
  • Content Values -> arrayController.arrangedObjects

The pop-up menu displays the pointers of the views as strings rather than taking the views and setting the NSMenuItem's view property. For example the pop-up button displays items like,

< NSView: 0x61000014e910 >

< NSView: 0x61000014e9c0 >

Community
  • 1
  • 1
Daniel Farrell
  • 9,316
  • 8
  • 39
  • 62
  • The [Bindings Ref for Popup Buttons](https://developer.apple.com/library/mac/documentation/cocoa/reference/CocoaBindingsRef/BindingsText/NSPopUpButton.html) says the "Content Values" binding is for the array of strings that correspond to the objects in the "Content" binding. If bindings are going to work with view-based menus, I'd think the "Content Values" binding ought to point to an array of NSViews, while "Content" points to an array of objects that are represented by those views. That said, it could all just be impossible. – stevesliva Jul 06 '14 at 03:49

1 Answers1

0

You are soooooo close to being finished. What you need to do is arrayController.arrangedObjects.[insertModelDisplayProperty]

I don't have enough rep yet to post images...otherwise I would give you a screen shot - I am working on this exact problem at this minute and have made it work.

In the XIB designer, there will be a modelKeyPath property in the binding settings for ControlValues. Set the model key path value to the property you want to display for each item.

I had a simpler problem to solve, but one that required similar approach...I still use binding; however.

stevesliva's comment got me thinking. I needed a simple style change for each menu item; so I derived my own NSMenu, and replaced the one wrapped by the NSPopupButton. The important method for me to override was:

- (NSMenuItem *)insertItemWithTitle:(NSString *)aString
                         action:(SEL)aSelector
                  keyEquivalent:(NSString *)keyEquiv
                        atIndex:(NSInteger)index

if((aString != nil)  && ([aString length] > 0))
{
    NSMenuItem *result = [[NSMenuItem alloc] initWithTitle:aString action:aSelector keyEquivalent:keyEquiv];

    NSView *menuView =[[AppMenuItemView alloc] init];

    menuView.autoresizingMask = NSViewWidthSizable;

    [result setView: menuView];

    [self insertItem:result atIndex:index];

    return result;
}
else
{
    return [super insertItemWithTitle:aString action:aSelector keyEquivalent:keyEquiv atIndex:index];
}

}


If we expand on the string comparison I used, you could easily see how Steve's idea is plausible...in this logic, you could use the "title" as a key to a dictionary of views that then gets used here to assign each item's view property.

Note that this likely requires changes to how you do your modeling - these views probably have to be bound to singletons, or some other way of associating the object memory...not saying this part is trivial...but, it may be possible. In the end, it is probably a question of re-factor effort to make it worthwhile. Note that the addItemWithTitle method probably needs to be coded similarly to the insertItemWithTitle method.

Combine all of that together, and yeah...bindings are probably not worthwhile for this use case, your original post should be up voted (if I could actual up vote with my paltry reputation).

  • The objects I wanted to display (views) are the objects in the array so I'm unclear how setting the model property will help. – Daniel Farrell Feb 26 '15 at 22:57
  • So, do those objects have a property with some sort of display string? –  Feb 26 '15 at 22:58
  • No. Basically you can't bind to the view property of pop up buttons with a managed array of views. Binding are half baked. Glad swift has got rid of them. – Daniel Farrell Feb 26 '15 at 23:01
  • Ah, then it does not work I guess...if your model has a property like model.displayString, you set that value in modelKeyPath=displayString and it all goes. I have had good luck with Mac bindings, but would like more UI templating (I think this is the half backed part). It is a shame this does not work for you; works perfectly for me! Different use cases I guess. –  Feb 26 '15 at 23:03
  • Yeah, different use case. You want to bring a string to the menu titles, I want to bind views to the menu items. Thanks for posting anyway. – Daniel Farrell Feb 26 '15 at 23:05
  • Actually, in many ways you are trying to do what I really want to do! –  Feb 26 '15 at 23:13