在NSTableView上迭代单元格

时间:2015-08-27 16:57:54

标签: objective-c macos nstableview nsview

我正在构建一个NSTableView来显示一组文件路径(directoriesArray)。我在main.storyboard上构建了NSTableView,我使用了这段代码:

- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
    return _directoriesArray.count;
}

- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
    return [_directoriesArray objectAtIndex:row];
}

- (void)tableViewSelectionDidChange:(NSNotification *)notification {

    NSTableView *tableView = notification.object;
    NSLog(@"User has selected row %ld", (long)tableView.selectedRow);

    NSLog(@"%@",[_directoriesArray objectAtIndex:tableView.selectedRow]);

}

//changes font of everything
- (NSCell *)tableView:(NSTableView *)tableView dataCellForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
    NSTextFieldCell *cell = [tableColumn dataCell];
    [cell setFont:[self quicksand:15.0f]];
    return cell;
}

这很有效。

我现在想要遍历NSTableView上的每个单元格并使用if语句编辑它们。

我尝试过更换

- (NSCell *)tableView:(NSTableView *)tableView dataCellForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {

阻止,用:

-(NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row{
    NSTableCellView *view = [tableView makeViewWithIdentifier:[tableColumn identifier] owner:self];
    if(view == nil){
        NSTableCellView *view = [[NSTableCellView alloc]initWithFrame:[tableView frame]];
        view.identifier = [tableColumn identifier];
    }
    NSTextField *textfield = [[NSTextField alloc]initWithFrame:NSMakeRect(0, 0, 100, 30)];
    [textfield setStringValue:[_directoriesArray objectAtIndex:tableView.selectedRow]];
    [textfield setBackgroundColor:[NSColor redColor]];
    [view addSubview:textfield];
    [view setNeedsDisplay:YES];
    return view;
}

但这显示空行!我做错了什么?!

奇怪的是 - 当我修改代码运行时点击一个单元格tableViewSelectionDidChange被调用,我仍然可以完美地获取日志....?!

修改

我已经更新了代码(尽我所能 - 这很糟糕):

-(NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row{
    NSTableCellView *view = [tableView makeViewWithIdentifier:[tableColumn identifier] owner:self];
    if(view == nil){
        NSTableCellView *view = [[NSTableCellView alloc]initWithFrame:[tableView frame]];
        view.identifier = [tableColumn identifier];
        view.translatesAutoresizingMaskIntoConstraints = false; //turned this off
        NSTextField *textfield;
        textfield.autoresizingMask = NSViewMaxXMargin | NSViewMinYMargin; //changed to autoresizing
        [textfield setStringValue:[_directoriesArray objectAtIndex:row]]; //changed to row
        [textfield setBackgroundColor:[NSColor redColor]];
        [view addSubview:textfield];
        [view setNeedsDisplay:YES];
    }
    return view;
}

enter image description here

1 个答案:

答案 0 :(得分:3)

这个问题似乎很困惑。主题说它是关于遍历表格视图的单元格,但其中似乎没有任何内容,因此。

您说您使用-tableView:dataCellForTableColumn:row:方法替换了-tableView:viewForTableColumn:row:方法。第一个适用于基于单元格的表格视图。第二个是基于视图的表视图。通过更改您的委托方法,您可以将表格从基于单元格更改为基于视图。

对于以编程方式创建的表视图,我认为委托方法是唯一决定它是基于单元格还是基于视图的方法。但是,对于在故事板中创建的表视图,也会在故事板中指定。两者不匹配肯定会造成麻烦。

因此,如果您想从基于单元格切换到基于视图,请确保在故事板中更改它。在这种情况下,您也可以在故事板中设置原型单元格视图。

您可以在代码中创建单元格视图。由于您没有关闭translatesAutoresizingMaskIntoConstraints(默认情况下已启用),因此您的单元格视图及其文本字段实际上是使用spring-and-struts模型进行布局。表视图将设置单元视图的框架。但是,您最初将其设置为巨大 - 与整个表视图一样大。此外,文本字段最初位于(0,0,100,30)。您需要设置其autoresizingMask以确定在单元格视图的大小更改时其大小应如何更改。并且,如果将其设置为在其superview调整大小时调整大小,那么您希望superview具有更合理的大小(或者文本字段几乎不合理)。

您要避免的场景是单元格视图开始很大,文本字段相对较小,文本字段配置为大致与单元格视图的大小成比例,因此当表格视图将单元格视图的大小调整为单元格的大小,将文本字段缩小到极小的大小。

在创建单元视图之前,请求表视图从其重用队列中获取一个。这很好。但是,如果它从其重用队列中获取一个,那么那个已经有一个文本字段。您不应每次都创建和添加新的文本字段。文本字段的创建应该在if(view == nil)语句中。

当您设置文本字段stringValue时,您正使用_directoriesArraytableView.selectedRow编入索引。这是错的。首先,表格视图可能没有selectedRow。事实上,它不可能在它首次建立时。我很惊讶你因为使用错误的索引(-1)索引到数组而没有得到异常。其次,为所有不同的行调用您正在实现的方法。你不想给他们所有相同的价值。该方法传递一个row参数,该参数指示视图已被请求的行。

为了更好地衡量,我会将单元格视图的textField插座连接到您创建的文本字段。 NSTableCellView有时根据其textField出口连接做特殊事情。 (例如,它使用文本字段的内容作为单元格的辅助功能文本。)

在您编辑的新代码中,存在新问题。

您正在关闭translatesAutoresizingMaskIntoConstraints以查看单元格视图。我并不是说你把它关掉了。我只是在解释它的存在以及它的后果是什么。对于单元格视图,您应该将其保持打开状态,并让表视图决定是否要将其关闭。通常,将视图插入视图层次结构的控制器代码决定是否关闭该视图。但是,还有那些仍然没有意识到自动布局或属性的控制器代码,因此默认情况下它应保持打开状态。这样,自动布局感知控制器代码可以根据需要设置它,而自动布局 - 初始控制器代码获取它所依赖的旧行为。 (从技术上讲,我们不能假设NSTableView的内部是否在这个意义上是自动布局感知的。)

您根本不再创建文本字段。您声明了变量,但是您没有创建实例。该变量只保留nil(假设您正在使用ARC)。您仍应分配并初始化文本字段。但是,您应该使用框架矩形作为单元格视图和文本字段,它们具有您希望它们具有的空间关系。弹簧和支柱只保持关系。所以,你需要从一个合理的关系开始,然后使用autoresizingMask来维护它。

如果您决定使用自动布局将文本字段与其超级视图(单元格视图)相关联,则可以在文本字段上关闭关闭。但是,您需要建立约束以将文本字段与单元格视图相关联。在这种情况下,单元格视图和文本字段的初始帧无关紧要。

在新代码中,您只需在创建文本字段时设置translatesAutoresizingMaskIntoConstraints。但是,如果从重用队列中获取它,则需要设置它。如果在创建两者时设置单元格视图的stringValue属性,则执行此操作会更容易。

以下是您的代码的修订版本:

textField