可可 如何在基于视图的NSTableView中对特定行强制实施特定的编辑行为?



我有一个简单的基于NSTableView的视图,其中一列填充了核心数据实体,而该行的视图只包含一个NSTextField。我只需要第一行不可编辑,并以红色显示。我试图在应用程序中的某个地方完成启动:

NSView *myView = [myPlaylistsTableView viewAtColumn:0 row:0 makeIfNecessary:NO];
NSArray *mySubviews = [myView subviews];
NSTextField *myTextField = [mySubviews firstObject];
[myTextField setEditable:NO];
NSDictionary *myDictionary = [NSDictionary dictionaryWithObjectsAndKeys:[NSColor redColor],NSForegroundColorAttributeName, nil];
NSAttributedString *myRedAttributedString = [[NSAttributedString alloc] initWithString:@"All Songs" attributes:myDictionary];
[myTextField setAttributedStringValue:myRedAttributedString];

但是,一旦在表中添加新元素或执行拖动,第一行就会再次变得可编辑。我尝试编写一个值转换器,将 NSTextField 可编辑绑定绑定绑定到数组控制器 selectionIndex,如果 selectionIndex 为 0,则返回 NO,在所有其他情况下都是 yes。对于值绑定的条件设置的可编辑复选框的各种配置,这不起作用。我想NSTableView的一个子类也应该可以解决问题,但我在这方面有点迷茫。 任何帮助一如既往地非常感谢。谢谢。

正如@Joshua Nozzi所建议的,我正在为表视图实现此委托方法:

-(NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
NSView *myView = [tableView makeViewWithIdentifier:[tableColumn identifier] owner:self];
if (tableView == myPlaylistsTableView)
{
if (row == 0)
{
NSArray *mySubviews = [myView subviews];
NSTextField *myTextField = [mySubviews firstObject];
[myTextField setEditable:NO];
NSDictionary *myDictionary = [NSDictionary dictionaryWithObjectsAndKeys:[NSColor redColor],NSForegroundColorAttributeName, nil];
NSAttributedString *myBoldAllSongsString = [[NSAttributedString alloc] initWithString:@"All Songs" attributes:myDictionary];
[myTextField setAttributedStringValue:myBoldAllSongsString];
}
}
return myView;
}

但是我一定错过了一些东西,因为该方法是为正确的 NSTableView 调用的,行 = 0,代码被执行,但我仍然没有红色字符串并且文本字段是可编辑的。

再次感谢您的任何帮助。

您正在尝试定位单元格视图并将其设置为"永久"。NSTableView不是这样工作的。每次重新加载一行或整个表时,都会"刷新"受影响行的视图。

自定义它们的适当位置是NSTableViewDelegate协议方法-tableView:viewForTableColumn:row:(请记住将实现此方法的控制器设置为表视图的委托)。

基于 OP 更新的更新

几点:

  1. 使用表列的标识符作为单元格视图的标识符有点奇怪,因为两者可能不同。特别是如果同一列中有多个可能的单元格类型(常见情况)。最好进入为每个单元格视图使用唯一标识符的做法,如果有多个列,则仅使用列标识符来标识列。

  2. 您将视图置于if()条件之外,以检查哪个表正在询问。如果您只有一个表,请不要费心检查;如果可能有多个控制器使用该控制器,请确保与每个表相关的所有内容(包括 -makeViewWithIdentifier:)都在其相关条件内。返回myView也是如此 - 这应该进入您的条件,如果没有匹配的表,您的最后一次返回应该为零,以便最佳实践。

  3. 您似乎仅在以下情况下配置单元格视图row == 0但未能考虑已配置为第 0 行单元格但正在重用于行>0 的重用视图。您可能会在需要大量滚动的大型表中看到所有行>0 的"有趣"行为。

  4. 您确定单元格视图的第一个子视图是您的NSTextField吗?您是否在调试器控制台中看到任何消息(如"...does not respond to selector...")?或者,如果在[myTextField setEditable:NO]行上设置断点,则调试器在那里暂停时是否myTextFieldnil?这里的最佳实践是创建您自己的视图子类,IBOutlets 到您想要与之交互的任何子视图,然后以这种方式更新它们。依赖其子视图列表会导致您在编辑单元格视图时出现混乱和未来的错误,即使它一开始是有效的。

  5. 与 4 相关,如果您只需要一个文本字段作为单元格,为什么不使用库存的 NSTableCellView 类(它有自己的-textField出口),这样您就可以myView.textField.attributedStringValue = someAttributedString分辨它?

  6. NSTextField具有用于设置其字符串值的字体和颜色的单独方法。为什么不利用这些而不是创建和设置属性字符串呢?

  7. 添加:忘记你提到绑定。即使您正确获取了对文本字段的引用,在此处设置其属性也无济于事,因为绑定可能会覆盖它们。更容易放弃绑定并与NSTableViewDelegate一起实现NSTableDataSource协议,并在数据更改时自行刷新表视图。您将省去很多关于UI更新时间的头痛和困惑。

基于上述内容的重写示例:

-(NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
// Is it the right table view?
if (tableView == myPlaylistsTableView)
{
// Determine properties based on row
BOOL firstRow = (row == 0);
NSFont * font = (firstRow) ? [NSFont systemFontOfSize:[NSFont systemFontSize]] : [NSFont boldSystemFontOfSize:[NSFont systemFontSize]];
NSString * text = (firstRow) ? @"All Songs" : [self.songsList[ row ] songTitle]; // or whatever other row titles will be
NSColor * color = (firstRow) ? [NSColor redColor] : [NSColor labelColor];
// Make an configure a cell view
NSTableCellView * myView = [tableView makeViewWithIdentifier:@"TextCell" owner:nil];
NSTextField * textField = myView.textField;
textField.editable = !firstRow;
textField.stringValue = text;
textField.font = font;
textField.textColor = color;
return myView;
}
return nil;
}

最新更新