Objective c 带绑定的NSPopupButton中的分隔符项

Objective c 带绑定的NSPopupButton中的分隔符项,objective-c,cocoa,cocoa-bindings,appkit,nspopupbutton,Objective C,Cocoa,Cocoa Bindings,Appkit,Nspopupbutton,nspoupbutton的内容绑定到字符串的NSArray 如何通过绑定插入分隔符项? “-”字符串(就像在古代/经典年代一样)不起作用,即字面上显示为“-”菜单项 是否有标准Cocoa类和绑定的现成解决方案? 这应该是一个很小的问题,但我找不到任何解决方案,除了像子类化NSMenu、nspoupbutton或其他非直观的解决方法这样愚蠢的黑客之外 查看Mac OS X 10.5中添加的NSContentPlacementTagBindingOption的文档。在Interface Builde

nspoupbutton
的内容绑定到字符串的
NSArray

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

-
”字符串(就像在古代/经典年代一样)不起作用,即字面上显示为“
-
”菜单项

是否有标准Cocoa类和绑定的现成解决方案?


这应该是一个很小的问题,但我找不到任何解决方案,除了像子类化
NSMenu
nspoupbutton
或其他非直观的解决方法这样愚蠢的黑客之外

查看Mac OS X 10.5中添加的
NSContentPlacementTagBindingOption
的文档。在Interface Builder的绑定检查器中,这可用于弹出菜单按钮等元素;转到“值选择”部分,在任何内容类别(内容、内容对象、内容值)中查找“内容放置标签”。字段值应该是与某个菜单项的标记号匹配的数字


绑定数组的内容将插入到菜单中,以代替具有指示标记值的任何项目。在这种情况下,静态菜单将包含分隔符项和至少一个其他项来指定数组值的位置。

在使用绑定时,我找不到一种干净的方法来动态地将分隔符添加到菜单中。我发现的最简单(也是最可重用)的方法是使用NSMenuDelegate动态交换具有特定标题的NSMenuItems,如
@--“
”,并在
menuedsupdate:
delegate方法中使用分隔符项

步骤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
#导入
@接口分隔符NuDelegate:NSObject
@结束
@实现分隔符NuDelegate
-(无效)菜单取消日期:(NSMenu*)菜单{
NSArray*fakeSeparators=[[menu itemArray]filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@“title=='--'''];
用于(NSMenuItem*fakeSeparators中的fakeSep){
[menu insertItem:[NSMenuItem separatorItem]atIndex:[menu indexOfItem:fakeSep]];
[菜单删除项:fakeSep];
}
}
@结束
步骤2:在Interface Builder中链接内容。

将对象拖出到包含NSPopupButton实例的场景中。

将对象的类设置为
separatorNuDelegate

旋转打开文档大纲中的NSPopupButton控件,然后选择其中的菜单。然后将菜单的委托设置为先前拖动的
分隔符numdelegate
对象

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


如果在同一场景中有多个NSpoupButton实例,则可以将其菜单的委托设置为同一对象(每个场景只需要一个
separatorNuDelegate

以下是n.Drake在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)
            }
        }
    }
}

依我看,最干净的解决方案仍然是子类化NSMenu——这种定制正是子类化的目的。以下解决方案基于@matt多年前在上所写的内容,并经过更新以更普遍适用,包括在High Sierra上

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

#define MY_MENU_SEPARATOR @"---"
Second,子类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

就这样。将受影响的菜单设置为Interface Builder的标识检查器中的MyMenu类,它们将在需要时插入分隔符项。适用于菜单栏菜单和弹出窗口。

您找到解决方案了吗?没有-返回到跛脚插座+手动构建菜单方法。不过我还是很感兴趣。如果最后期限不是个问题,我会尝试一些涉及价值变换器的东西。嗯,我知道这个选项。但是,如果您有一个包含多个分隔符的通用列表,如项目a、分隔符、项目B、分隔符、项目C……的效果非常好(并且解释得非常好),那么这并没有帮助。这应该是可以接受的答案。非常有用,因为我15年的解决方案,子类化NSMenu并重写
addItemWithTitle
,不再有效。。。我想这是我们用当前的MacOSAPI所能做的最好的了。干杯@马特,为什么你认为你的“15年解决方案”不再有效?子类化NSMenu在High Sierra上仍然可以很好地工作,从我的观点来看,这不是一个“愚蠢的hack”,而是子类化的真正目的,因此是最干净的解决方案。记住不仅要覆盖
addItemWithTitle
,还要覆盖
insertItemWithTitle
。@UliZappe我从来没有说过这是一个愚蠢的黑客行为。我可以建议你,如果你有一个使用它的解决方案,你就给出这个答案吗?@matt“傻瓜黑客”是线程启动者在他的问题中使用的一个表达;对不起,我应该明确地指出这一点。至于解决方案,这是您的解决方案,如所述。当然我可以重复一遍,但这真的有意义吗?@ATV这是制作NSMenu的一个支持分隔符的子类的代码。因此,它很小——你一生中只做一次。然后,添加分隔符的代码-这是不同的-只是在需要的地方添加
MY\u MENU\u separator
。这一点都不容易。答案似乎在你编辑最初的帖子之前已经被修改过;)