为了在弹出菜单时在菜单中显示属性字符串,我建议设置包含弹出单元格的表列,使其Content
绑定指向NSArrayController
本身绑定到包含所有选项的一个NSArray
,NSAttributedStrings
然后在NSMenu
由弹出单元格包含,然后在委托中执行以下操作:
- (void)menuNeedsUpdate:(NSMenu*)menu
{
for (NSMenuItem* item in menu.itemArray)
if ([item.representedObject isKindOfClass: [NSAttributedString class]])
{
item.attributedTitle = item.representedObject;
}
}
绑定会将未骚扰的人NSAttributedString
放入. 您可以在那里找到它并将其放入属性中,这将使其在菜单中显示属性字符串。总而言之,在菜单中绘制的菜单项及其属性设置得当,将绘制样式化的文本。representedObject
NSMenuItem
attributedTitle
attributedTitle
更复杂的是,当菜单未弹出时,在弹出单元格中按预期绘制属性字符串。NSPopUpButtonCell
似乎通过NSMenuItem
为它绘制一个来呈现。不幸的是,该特定的创建NSMenuItem
似乎并不包括将未受到干扰的价值推入其中。相反,标题似乎是作为一个普通的、非归属的字符串发送的。我无法为此设计一个优雅的解决方案,但我确实想出了一个不优雅的解决方法:
首先添加一NSTextField
列NSTableView
正确绘制当前选定的属性字符串(即带有属性)。使该列隐藏。子类化NSPopUpButtonCell
或使用类别和关联存储将新的私有属性添加到NSPopUpButtonCell
. 此属性将包含一个块,您可以在绘制时使用它从隐藏列中获取相应的单元格。添加NSTableViewDelegate
, 并实现-tableView:dataCellForTableColumn:row:
. 当弹出列调用它时,创建块以从隐藏列中获取单元格并将其推入子类的属性中。title
然后在绘制时,如果您有一个单元格提取器块,请清除menuItem
它通常用于渲染,调用 super (获取弹出窗口的小箭头),然后获取代理单元格,并让它也绘制。代码如下所示:
@interface AppDelegate : NSObject <NSApplicationDelegate, NSMenuDelegate, NSTableViewDelegate>
@property (assign) IBOutlet NSTableColumn *popUpColumn;
@property (assign) IBOutlet NSTableColumn *surrogateColumn;
// ...snip...
@end
@interface SOPopUpButtonCell : NSPopUpButtonCell
typedef NSTextFieldCell* (^CellFetcher)();
@property (nonatomic, copy, readwrite) CellFetcher cellFetcherBlock;
@end
@implementation AppDelegate
// ...snip...
- (NSCell *)tableView:(NSTableView *)tableView dataCellForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
if (nil == tableColumn || self.popUpColumn != tableColumn)
return nil;
SOPopUpButtonCell* defaultCell = (SOPopUpButtonCell*)[tableColumn dataCellForRow: row];
const NSUInteger columnIndex = [[tableView tableColumns] indexOfObject: self.surrogateColumn];
CellFetcher f = ^{
return (NSTextFieldCell*)[tableView preparedCellAtColumn: columnIndex row: row];
};
defaultCell.cellFetcherBlock = f;
return defaultCell;
}
@end
@implementation SOPopUpButtonCell
- (void)setCellFetcherBlock:(CellFetcher)cellFetcherBlock
{
if (_cellFetcherBlock != cellFetcherBlock)
{
if (_cellFetcherBlock)
Block_release(_cellFetcherBlock);
_cellFetcherBlock = cellFetcherBlock ? Block_copy(cellFetcherBlock) : nil;
}
}
- (void)dealloc
{
if (_cellFetcherBlock)
Block_release(_cellFetcherBlock);
[super dealloc];
}
- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
{
CellFetcher f = self.cellFetcherBlock;
if (f)
self.menuItem.title = @"";
[super drawWithFrame:cellFrame inView:controlView];
if (f)
NSTextFieldCell* surrogateCell = f();
[surrogateCell drawWithFrame: cellFrame inView: controlView];
}
@end
我必须承认这让我觉得有点脏,但它似乎完成了工作。我已经在 github 上发布了所有代码,包括带有所有关联绑定的 xib:
示例项目
希望有帮助。