NSPopupButton中的分隔项与绑定

ATV*_*ATV 10 cocoa objective-c appkit cocoa-bindings nspopupbutton

a的内容NSPopupButton绑定到一个NSArray字符串.

我们如何通过绑定插入分隔项?

" -"字符串(如旧版/经典日)不起作用,即字面上显示为" -"菜单项.

有没有标准的Cocoa类和绑定的开箱即用的解决方案?

这应该是一个很重要的问题,但我找不到任何解决办法,不涉及傻黑客就像子类的问题NSMenu,NSPopupButton或者其他非直观的变通.

n.D*_*ake 6

在使用绑定时,我找不到一种干净的方法来动态地将分隔符添加到菜单中.我发现的最简单(也是最可重用)的方法是使用NSMenuDelegate动态地将NSMenuItems替换为特定标题,例如委托方法@"---"中的分隔符项menuNeedsUpdate:.

步骤1:创建符合NSMenuDelegate协议的NSObject

#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
Run Code Online (Sandbox Code Playgroud)

第2步:在Interface Builder中链接.

将Object拖出到包含NSPopupButton实例的场景中. 拖出一个对象

将对象的类设置为 SeparatorMenuDelegate

设置对象的类

旋转打开文档大纲中的NSPopupButton控件,然后选择其中的菜单.然后将菜单的委托设置为SeparatorMenuDelegate您之前拖动的对象.

设置菜单的委托

在此之后,菜单中标题为""---"的所有项目都将转换为分隔项目.

如果在同一场景中有多个NSPopupButton实例,则可以将其Menu的委托设置为同一对象(SeparatorMenuDelegate每个场景只需要一个).


小智 5

恕我直言,最干净的解决方案仍然是子类化NSMenu - 这种自定义正是子类化的目的。以下解决方案基于@matt 多年前在Cocoabuilder写的内容,并更新为更普遍适用,包括在 High Sierra 上。

首先,定义一个“魔法字符串”来表示代码中的分隔符项;在所有受影响的类将导入的头文件中执行此操作。在这个例子中,我选择了“---”,当然,这可以是你喜欢的任何字符串:

#define MY_MENU_SEPARATOR @"---"
Run Code Online (Sandbox Code Playgroud)

其次继承 NSMenu并覆盖添加菜单项的两个方法,以处理特殊分隔符情况:

@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
Run Code Online (Sandbox Code Playgroud)

就是这样。在Interface BuilderIdentity检查中将受影响的菜单设置为MyMenu类,它们将在需要的地方插入分隔项。适用于菜单栏菜单以及弹出窗口。