0

我有一个NSArrayController用一堆列动态填充的表格,其中一个有一个弹出按钮。弹出按钮单元格的内容需要使用NSAttributedString,因为我需要显示一个带下标的科学变量(例如,X1 降低 1)。

将弹出单元格绑定content values到 UI 中会产生乱码数组,NSAttributedString因为它只能理解普通NSString对象。

弹出按钮的菜单不可绑定(即无法通过绑定动态分配)。

弹出按钮菜单的内容也不能动态绑定。

任何人都可以提出一种方法(至少对表格内容的其余部分坚持绑定)用对象动态填充NSPopUpButtonCell菜单吗?NSAttributedString

4

1 回答 1

2

为了在弹出菜单时在菜单中显示属性字符串,我建议设置包含弹出单元格的表列,使其Content绑定指向NSArrayController本身绑定到包含所有选项的一个NSArrayNSAttributedStrings然后在NSMenu由弹出单元格包含,然后在委托中执行以下操作:

- (void)menuNeedsUpdate:(NSMenu*)menu
{
    for (NSMenuItem* item in menu.itemArray)
        if ([item.representedObject isKindOfClass: [NSAttributedString class]])
        {
            item.attributedTitle = item.representedObject;
        }
}

绑定会将​​未骚扰的人NSAttributedString放入. 您可以在那里找到它并将其放入属性中,这将使其在菜单中显示属性字符串。总而言之,在菜单中绘制的菜单项及其属性设置得当,将绘制样式化的文本。representedObjectNSMenuItemattributedTitleattributedTitle

更复杂的是,当菜单弹出时,在弹出单元格中按预期绘制属性字符串。NSPopUpButtonCell似乎通过NSMenuItem为它绘制一个来呈现。不幸的是,该特定的创建NSMenuItem似乎并不包括将未受到干扰的价值推入其中。相反,标题似乎是作为一个普通的、非归属的字符串发送的。我无法为此设计一个优雅的解决方案,但我确实想出了一个不优雅的解决方法:

首先添加一NSTextFieldNSTableView正确绘制当前选定的属性字符串(即带有属性)。使该列隐藏。子类化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: 示例项目

希望有帮助。

于 2012-12-04T12:40:21.910 回答