Separator Element in NSPopupButton with Links

The content of NSPopupButton bound to NSArray strings.

How can we insert a separator element through bindings?

The lines " - " (for example, in the old days / classical days) do not work, that is, they are literally displayed as a menu item " - ".

Is there a turnkey solution with standard Cocoa classes and bindings?

This should be a trivial problem, but I cannot find a solution to the problem that does not include silly hacks such as subclasses of NSMenu , NSPopupButton or other non-intuitive working methods.

+8
objective-c cocoa appkit cocoa-bindings nspopupbutton
source share
5 answers

I could not find a clean way to add separators to the menu dynamically when using bindings. The easiest (and most reusable) way I've found is to use NSMenuDelegate to dynamically replace NSMenuItems with a specific header like @"---" with separator elements in the delegate method menuNeedsUpdate:

Step 1: Create an NSObject that Complies with the NSMenuDelegate Protocol

 #import <Cocoa/Cocoa.h> @interface SeparatorMenuDelegate : NSObject <NSMenuDelegate> @end @implementation SeparatorMenuDelegate -(void)menuNeedsUpdate:(NSMenu *)menu { NSArray* fakeSeparators = [[menu itemArray] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"title == '---'"]]; for (NSMenuItem* fakeSep in fakeSeparators) { [menu insertItem:[NSMenuItem separatorItem] atIndex:[menu indexOfItem:fakeSep]]; [menu removeItem:fakeSep]; } } @end 

Step 2: Link things in Interface Builder.

Drag the object into the scene containing the NSPopupButton instance. Drag out an object

Define SeparatorMenuDelegate Object Class

Set the object's class

Twirl open the NSPopupButton control in the outline of the document and select Menu from it. Then set the menu delegate to the SeparatorMenuDelegate object that you migrated earlier.

Set the menu's delegate

After that, all items in the menu with the heading @ "---" will be converted to separator items.

If you have multiple instances of NSPopupButton in the same scene, you can set the delegate of your menu to the same object (you only need one SeparatorMenuDelegate for each scene).

+4
source share

Here's the n.Drake answer in Swift 3.1:

 class MySeparatorMenuDelegate : NSObject, NSMenuDelegate { func menuNeedsUpdate(_ menu: NSMenu) { for (ix,mi) in menu.items.enumerated() { if mi.title == "---" { menu.removeItem(at: ix) menu.insertItem(NSMenuItem.separator(), at: ix) } } } } 
+1
source share

IMHO, the cleanest solution is still a subclass of NSMenu - this kind of customization is exactly what the subclass is for. The following solution is based on what @matt wrote many years ago on Cocoabuilder and is being updated to be more universal, including High Sierra.

First , define a "magic string" to represent the separator element in your code; do this in the header file, which imports all the affected classes. In this example, Ive selected β€œ---,” but of course it could be any line you like:

 #define MY_MENU_SEPARATOR @"---" 

Second , subclass NSMenu and rewrite the two methods that add menu items to handle the special case of the delimiter:

 @implementation MyMenu - (NSMenuItem*)addItemWithTitle:(NSString*)aString action:(SEL)aSelector keyEquivalent:(NSString*)keyEquiv { if ([aString isEqualToString:MY_MENU_SEPARATOR]) { NSMenuItem *separator = [NSMenuItem separatorItem]; [self addItem:separator]; return separator; } return [super addItemWithTitle:aString action:aSelector keyEquivalent:keyEquiv]; } - (NSMenuItem*)insertItemWithTitle:(NSString*)aString action:(SEL)aSelector keyEquivalent:(NSString*)keyEquiv atIndex:(NSInteger)index { if ([aString isEqualToString:MY_MENU_SEPARATOR]) { NSMenuItem *separator = [NSMenuItem separatorItem]; [self insertItem:separator atIndex:index]; return separator; } return [super insertItemWithTitle:aString action:aSelector keyEquivalent:keyEquiv atIndex:index]; } @end 

And here it is. Configure vulnerable menus on the MyMenu class in the Identity Interface Builder inspector, and they will insert separator elements as desired. Works for menu menus as well as pop-ups.

+1
source share

[[popupButton menu] addItem: [NSMenuItem separatorItem]];

0
source share

Take a look at the documentation for NSContentPlacementTagBindingOption , added in Mac OS X 10.5. In the Builder interface binding inspector, it is available for items such as pop-up menu buttons; go to the "Select value" section and look in any content category (content, content objects, content values) for the "Content placement tag". The field value must be a number that matches the tag number of the menu item.

The contents of the linked array will be inserted into the menu instead of the element having the specified tag value. In this case, the static menu will contain a separator element and at least one other element to indicate where the array values ​​go.

0
source share

All Articles