NSPopupButton中的分隔项与绑定

时间:2014-10-05 11:55:37

标签: objective-c cocoa cocoa-bindings appkit nspopupbutton

NSPopupButton的内容绑定到NSArray个字符串。

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

" -"字符串(如旧时/经典日)不起作用,即字面意思显示为" -"菜单项。

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

这应该是一个微不足道的问题,但我找不到任何解决问题的方法,这些问题并不涉及像子类NSMenuNSPopupButton或其他非直观工作那样的愚蠢黑客攻击变通。

5 个答案:

答案 0 :(得分:6)

在使用绑定时,我无法找到一种干净的方法来动态地将分隔符添加到菜单中。我发现的最简单(也是最可重用)的方法是使用NSMenuDelegate动态地将具有@"---"的特定标题的NSMenuItem替换为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

第2步:在Interface Builder中进行链接。

将Object拖出到包含NSPopupButton实例的场景中。 Drag out an object

将对象的类设置为SeparatorMenuDelegate

Set the object's class

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

Set the menu's delegate

此后,菜单中的所有项目标题为@&#34; ---&#34;将被转换为分隔项。

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

答案 1 :(得分:4)

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

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

#define MY_MENU_SEPARATOR @"---"

第二次,子类 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 Identity 检查器中的 MyMenu 类,并在需要的位置插入分隔符项。适用于菜单栏菜单和弹出窗口。

答案 2 :(得分:1)

这是斯莱夫特在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)
            }
        }
    }
}

答案 3 :(得分:0)

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

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

答案 4 :(得分:-1)

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