我正在尝试使用 ArrayController 和 Bindings 设置自定义单元格的 NSTableView 。为此,我在自定义单元格中添加了一个子视图。数据连接似乎有点奏效。虽然,似乎有一个我无法解决的重绘问题。当我加载应用程序时,只渲染一些单元格。当我滚动行或选择一个渲染更改时。
我创建了一个example project on github来说明问题所在。
可以找到单元格渲染的实际源代码here:
// CustomCell.m
- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
if (![m_view superview]) {
[controlView addSubview:m_view];
}
// The array controller only gets wrapped data items pack by the NSObjectTransformer.
// Therefore, objectValue returns a NSObjectWrapper.
// Unpack the wrapper to retreive the data item.
DataItem* dataItem = [(NSObjectWrapper*)[self objectValue] original];
[[m_view name] setStringValue:dataItem.name];
[[m_view occupation] setStringValue:dataItem.occupation];
[m_view setFrame:cellFrame];
}
似乎父controlView
没有重绘。我可以以某种方式强迫它吗?
答案 0 :(得分:3)
这几乎肯定不是这样做的最佳实践方式,我将在后面解释原因:但是,它似乎确实有效。用以下内容替换您的单元格类的drawInteriorWithFrame:inView:
方法:
- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
DataItem* dataItem = [(NSObjectWrapper*)[self objectValue] original];
[[m_view name] setStringValue:dataItem.name];
[[m_view occupation] setStringValue:dataItem.occupation];
[m_view setFrame:cellFrame];
NSData *d = [m_view dataWithPDFInsideRect:[m_view bounds]];
NSImage *i = [[NSImage alloc] initWithData:d];
[i setFlipped:YES];
[i drawInRect:cellFrame fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
}
问题是只为整个表创建了一个NSCell。这就是单元格的工作方式:表格视图创建一个单元格,并调用setObject ...然后反复绘制drawInterior ...以使单元格绘制整个表格。从效率的角度来看这很好(NSCell类是在25mhz是快速计算机时设计的,所以它的目的是最小化对象分配的数量),但这会引起问题。
在代码中,使用值填充视图,并设置其框架,并根据需要将其添加为表视图的子视图。但是,由于您只有一个NSCell实例,因此只能有一个视图:您使用了单个视图,只是将其移动到表格的行中。
要正确执行此操作,您需要一些数据结构来跟踪您添加为NSTableView子视图的所有视图,当单元格在drawInterior ...方法中更新时,您需要查找哪个正确一个是并更新。您还需要在代码中分配所有这些视图(或者至少将视图移动到可以加载多个副本的单独nib),因为因为它只是你的笔尖中有一个并且复制视图是痛苦。
我写的代码是一个kludge,因为它真的很低效。我所做的是每次视图需要绘制时,我将视图绘制到屏幕外图像缓冲区,然后将缓冲区绘制到表视图中的正确位置。在这样做的过程中,我避免了只有一个视图的问题,因为代码只需要它并在需要时绘制其内容的新副本。
答案 1 :(得分:0)
编辑:请参阅我的其他答案以获得解释
您是否已实施copyWithZone:
?您需要确保在该方法中复制或重新创建视图,否则不同的单元格最终将共享一个视图(因为NSTableView会复制其单元格)。