如何在NSTableViewRow中创建一个按钮来响应所表示的对象

时间:2015-04-16 19:11:05

标签: cocoa nstableview cocoa-bindings nstablecellview

我已经在这个问题上奋斗了很长一段时间。我正在处理文件复制管理器模块,到目前为止,除了取消按钮之外,我已经能够完美地完成所有工作。出于某种原因,当我单击特定行的取消按钮时,按钮操作会同时定位多个行。

File Copy Manager

经过几天的研究,我能够使对象成功取消行所代表的操作:

-(IBAction)btnCancelOperationClick:(id)sender {
    NSInteger row = [_tableView rowForView:sender];
    if (row != -1) {
        FileCopyOperation *opr = [_fileCopyOperations objectAtIndex:row];
        [opr cancel];
        [_fileCopyOperations removeObjectAtIndex:row];
        [_tableView removeRowsAtIndexes:[NSIndexSet indexSetWithIndex:row] withAnimation:NSTableViewAnimationEffectFade];
    }
}

这很好用,我可以取消操作并相应地更新我的表。其他一切都按预期工作,但我的代码或绑定必须有问题。我从笔尖加载这个单元格,然后使用:

注册这个笔尖
[_tableView registerNib:[[NSNib alloc]initWithNibNamed:@"FileCopyCell" bundle:nil] forIdentifier:@"FileCopyCell"];

我将QueueController作为文件的所有者并挂钩了这样的一切:

Bindings

如果有人能指出我正确的方向让这件事情正常运转,我将不胜感激。提前谢谢!

编辑以添加更多代码示例。

-(NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
    FileCopyCell *cell = [tableView makeViewWithIdentifier:@"FileCopyCell" owner:self];
    FileCopyOperation *opr = [_fileCopyOperations objectAtIndex:row];

    [cell.fileName setStringValue:[NSString stringWithFormat:@"Copying \"%@\"",opr.fName]];
    [cell.progressBar setDoubleValue:((opr.bWritten.doubleValue / opr.fSize.doubleValue) * 100)];
    [cell.totalBytes setStringValue:[NSString stringWithFormat:@"of %@",[NSByteCountFormatter stringFromByteCount:opr.fSize.longLongValue countStyle:NSByteCountFormatterCountStyleFile]]];
    [cell.status setStringValue:[NSString stringWithFormat:@"%@",[NSByteCountFormatter stringFromByteCount:opr.bWritten.longLongValue countStyle:NSByteCountFormatterCountStyleFile]]];
    [cell.icon setImage:[[NSWorkspace sharedWorkspace]iconForFile:opr.srcURL.path]];
    [cell.cancelButton setTarget:self];
    return cell;
}

-(void)windowDidLoad {
    [super windowDidLoad];
    _fileCopyOperations = [NSMutableArray new];
    windowFrame = [self.window frame];
    rows = 0;

    [_tableView registerNib:[[NSNib alloc]initWithNibNamed:@"FileCopyCell" bundle:nil] forIdentifier:@"FileCopyCell"];

    if (!fileCopyManager) {
        fileCopyManager = [FileCopyManager sharedFileCopyManager];
        [fileCopyManager.fileCopyQueue addObserver:self forKeyPath:@"operationCount" options:NSKeyValueObservingOptionNew context:(void*)fileCopyManager];
    }

    [_scrollView setHasHorizontalScroller:NO];
    [_scrollView setHasVerticalScroller:NO];
}

2 个答案:

答案 0 :(得分:2)

最好的方法是继承NSTableCellView并让 it 处理自己的操作并表示对象。例如,表示Foo实例的单元格可能包含两个属性:foofooController。调用(nonatomicfoo setter时,单元格可以更新自己的UI以表示传递的Foo。当Foo控制器创建表格单元格时,它可以实例化FooCell实例,将其自身设置为fooController并分配Foo实例并让单元格处理自己。取消按钮的目标可以是它自己的单元格,当调用-cancel:动作时,它可以告诉其fooController要做什么(因为Foo控制器负责更新队列和表视图)并且由于它具有对其foo的引用,它可以通过某种-cancelFoo:(Foo *)theFoo方法将其传递给控制器​​,而无需依赖控制器来查找其索引(可能如果您正在为行显示和消失动画或者用户正在快速取消一堆但是它们的删除被延迟并异步更新,则不准确。)

干净整洁。整洁有序的遏制/责任分离。单元格处理自己的UI更新和操作,并知道自己的foo; foo控制器处理它的foo集合,它的表视图,以及为foo单元分配foos。

答案 1 :(得分:1)

感谢Joshua Nozzi,按照他的建议,我将按钮动作从控制器移动到了细胞类。在单元类中,我使用下面的方法来访问所表示的对象并发送[operation cancel]消息。

-(IBAction)cancelOpr:(id)sender {
    NSButton *button = (NSButton*)sender;
    FileCopyOperation *opr = [(NSTableCellView*)[button superview]objectValue];
    [opr cancel];
    // This code calls the controller [removeObject:] method that takes care of cleaning everything out and updates the GUI accordingly.
    AppDelegate *ad = (AppDelegate*)[[NSApplication sharedApplication]delegate];
    QueueWindowController *qc = [ad getQueueController];
    [qc.fileCopyOperations performSelectorOnMainThread:@selector(removeObject:) withObject:opr waitUntilDone:YES];
}

您可以获得完整的项目here

enter image description here