2012-11-17 18 views
0

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

绑定弹出单元的content values到的NSAttributedString阵列产生在UI乱码,因为它只能理解平原NSString对象。

弹出按钮的菜单不是绑定(即,不能够通过绑定动态分配)。

弹出按钮菜单的内容不能被动态地或者约束。

任何人都可以建议一种方式(至少与表格内容的其余部分保持绑定),以便动态地使用NSAttributedString对象填充NSPopUpButtonCell菜单吗?

回答

2

对菜单中显示归属字符串时,它的突然出现,我建议包含弹出电池有它的Content绑定指向表列设置为本身必然的NSAttributedStringsNSArray包含所有选项的NSArrayController ,然后将通过弹出电池包含在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,通常用于渲染,调用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上所有相关的绑定在厦门国际银行: Example Project

希望有所帮助。

+0

感谢您的解决方案!我遇到了同样的问题,即'NSPopUpButtonCell'无法正确更新自己,所以在花费了几个小时并尝试各种方法之后,我继续通过tableView:dataCellForTableColumn:row:从表视图委托中填充弹出式按钮,然后只是绑定弹出窗口的选定索引属性.. – Jay