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
。这一点都不容易。答案似乎在你编辑最初的帖子之前已经被修改过;)