NSTableView中的自定义单元格

时间:2012-01-12 20:46:15

标签: cocoa nstableview cocoa-bindings nstableviewcell

使用自定义单元格填充NSTableView的最佳方法是什么?

当我填充标准数据时,我总是使用Cocoa Bindings,并且在使用自定义单元格填充表时,我总是使用数据源。我想知道的是,如果有一种方法可以将这两个概念混合在一起进行优化设计。

遗憾的是,使用Xcode 3(因此,IBPlugins)不是一种选择。

1 个答案:

答案 0 :(得分:3)

我个人不会混合绑定数据和数据源。我只是痛苦地试图做到这一点。我确实有几种方法可以帮助你。

我能做的一件事是在IB中设置一个自定义单元格类,它是IB知道的一个单元格的子类,然后覆盖你需要的任何东西,以便让它做你想做的。但首先是一些背景,有些错过了尝试:

绑定基于单元格的NSTableView时,通常会在列本身而不是列中的单元格上设置绑定。如果在表列中使用自定义NSCell子类,您会注意到列上不再提供value等绑定,这与单元格是NSTextFieldCell时不同。我试图通过将value绑定设置为NSTextFieldCell来设置IB,然后切换出单元格 - 绑定仍然出现在绑定检查器中,但它总是在运行时因此错误而崩溃:[<NSTableColumn 0x10252e910> valueForUndefinedKey:]: this class is not key value coding-compliant for the key value.

这让我想到了IB知道如何绑定的一个单元的子类化方法。我创建了NSTextFieldCell的子类,向下钻取到表列中的“文本字段单元格 - 文本单元格”,然后在Identity Inspector中设置我的自定义子类。我能够确认绑定仍然有效,IB仍然像对待NSTextFieldCell一样对待它。从那里,我可以覆盖我想要的自定义单元格类中的任何方法,并获得自定义行为。我没有理由相信你也不能用图像细胞做到这一点。当然,这是一种虚假的方法,但取决于你的自定义单元格的“自定义”方式,它可能会编写一堆自定义代码来连接数据源。

我在进一步实验时发现,这是一个“IB问题”,而不是真正的NSTableView /绑定问题。还有另外一个很好的方法。

假设您要使用自定义单元格,并且希望将其绑定到某个任意模型对象。你有NSTableColumn Value绑定绑定到一个NSArrayController,它出售一个自定义模型对象列表,每个对象都有一个属性,称之为dataForCustomCell,返回自定义单元需要做的事情。您将设置TextFieldCell列(如IB中的默认值),然后将NSTableColumn的value绑定绑定到Array Controller&gt; arrangedObjects并输入模型关键路径dataForCustomCell。此时,假设dataForCustomCell返回的对象实现了NSCopying(如果你的应用程序不会崩溃,但这不是真正相关的话,那么你运行你的应用程序时会看到的是NSTextFieldCell会在- (NSString*)description返回的对象上调用dataForCustomCell并将该文本放入单元格中。

现在有趣的部分:在-awakeFromNib时间你自己的对象(NSView,NSViewController等等),替换dataCell(和headerCell,如果你喜欢),如下所示:

- (void)awakeFromNib
{
    [super awakeFromNib];
    // Assuming you've got your NSTableView plugged into an IBOutlet property called table
    NSTableColumn* col = [[self.table tableColumns] objectAtIndex:0];
    col.dataCell = [[[MYCustomCell alloc] init] autorelease];
}

由于绑定位于NSTableColumn而不是单元本身,因此您可以更换单元格而无需担心重新挂接任何绑定。在您的自定义单元格类中,覆盖-(void)setObjectValue:,您将在运行时从绑定机制调用,推送来自与当前对应的模型对象上的dataForCustomCell属性的对象绘制表格的行。 (对于每个单元格,你也会得到一个以零传递的调用,但忽略它或者只是把它传递给super就好了。)

这种方法的一个缺点是您只能获得NSTextFieldCell具有的一个“Value”绑定。解决方法是将Value绑定绑定到模型中更大/更高的“粒度”,然后在需要时向下钻取并展示-setObjectValue:实现中的多个值。

这不是完美的,但它是“几行代码”修复,而不是“gazillions of code of code”修复。

或者,假设您的目标是最新版本的MacOS,您还可以使用基于视图的NSTableViews。它们非常好,并且以比基于NSCell的表更合理的方式处理绑定。这是一种完全不同的做事方式,因此很难说出你的任务将如何映射到它。有一个great video on the Apple developer site可以让您快速了解基于NSView的NSTableView。