tableView:shouldEditTableColumn:row:用于基于视图的NSTableView

时间:2014-11-19 18:11:57

标签: objective-c cocoa nstableview

根据Apple's documentation on [NSTableViewDelegate tableView:shouldEditTableColumn:row:],“此方法仅对基于NSCell的表视图有效”。与基于视图的表视图相同的是什么?我想用自定义编辑体验替换默认的内联编辑。

3 个答案:

答案 0 :(得分:2)

这个委托方法实际上不需要基于视图的表视图。

在这种情况下,您需要创建一些NSView子类。也可能有nib文件。

让我们说,你有一个名为CustomCellView的类有一些插座。 CustomCellView.h档案

#define kCustomCellViewReusableIdentifier @"kCustomCellViewReusableIdentifier" // NSTableView reuses cell views

@interface CustomCellView : NSView

@property (weak) IBOutlet NSImageView *imageView;
@property (weak) IBOutlet NSTextField *textField;

- (void)setCellEditable:(BOOL)editable;

@end

这是您的CustomCellView.m文件

@implementation CustomCellView

- (void)awakeFromNib
{
  // paste your ui initializing code here
}

- (void)prepareForReuse
{
  // this method will call each time cell reuses
}

- (void)setCellEditable:(BOOL)editable
{
  [self.textField setEditable:editable];
  // some other code
}

@end

不要忘记创建nib文件并连接你的网点。您的NSTableView所有者类必须具有一些用于重用的初始化代码。 MyTableViewController.m

- (void)initUI
{
  NSString *nibName = NSStringFromClass([CustomCellView class]);
  [self.tableView registerNib:[[NSNib alloc] initWithNibNamed:nibName bundle:nil]
                 forIdentifier:kCustomCellViewReusableIdentifier];
}

#pragma mark - table view data source methods

- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
   CustomCellView *view=[tableView makeViewWithIdentifier:kCustomCellViewReusableIdentifier owner:nil];
   [view setCellEditable:someCondition]; // 
   return view;
}

#pragma mark - operations

- (void)setViewAtColumn:(NSTableColumn *)tableColumn row:(NSInteger)row editable:(BOOL)editable
{
  CustomCellView *view=[self.tableView viewAtColumn:tableColumn row:row makeIfNecessary:NO]; //no need to create it if it's not exists - we'll set the data in NSTableViewDataSource method
  if (view) // if it's exists
    [view setCellEditable:editable];
}

答案 1 :(得分:1)

评论Astoria的方法:

每当模型的可编辑性发生变化时,必须更改文本字段的可编辑性的“不足”问题是,您必须“主动”跟踪模型的可编辑性并更新文本字段的可编辑性。

相比之下,基于单元格的表格视图的委托方法延迟了对可编辑性的关注,直到用户尝试进行编辑的时刻为止,此时委托只返回是否可以编辑模型。设置更少,错误的可能性更小。 (例如,根据您在模型中监视/响应可编辑性的方式,您可能会错过更改,现在用户可能会错误地编辑或不编辑该字段。)

因此,另一种方法是在用户尝试编辑时重新创建确定可编辑性的委派。要做到这一点,你要继承NSTextField,覆盖“正确的位置”,询问代表,允许或禁止可编辑性。

“正确的位置”似乎会覆盖acceptsFirstResponder,并返回NO。

- (BOOL)acceptsFirstResponder
{
    BOOL accepts = [super acceptsFirstResponder];

    if (accepts) {
        if ([self.delegate respondsToSelector:@selector(textFieldShouldBecomeEditable:)]) {
            accepts = [self.delegate textFieldShouldBecomeEditable:self];
        }
    }

    return accepts;
}

使用上述内容,只要字段的editable为YES,就会调用委托进行最终确定。

根据您的应用程序,这可能是一种更理想的方法,因为监控模型可编辑性的变化并不是直截了当的。但是,通常,简单设置字段editable属性的标准方法是最佳的。

答案 2 :(得分:0)

根据seth的回答,我想到了这一点;需要对象(项目)上下文以及column和tableView信息。 HTH

//  We cannot alter a playitem once plays is non-zero; set to zero to alter
@objc func textFieldShouldBecomeEditable(_ textField: PlayTableTextField) -> Bool {
    let tableView = textField.superview?.superview?.superview as! PlayTableView
    let item = (textField.superview as! PlayTableCellView).objectValue
    let tableColumn = textField.tableColumn!

    if tableView == playlistTableView, let playlist : PlayList = item as? PlayList {
        guard playlist.name != UserSettings.HistoryName.value else { return false }
        return tableColumn.identifier == .name
    }
    else
    if tableView == playitemTableView, let playitem : PlayItem = item as? PlayItem {
        let virgin = playitem.plays == 0

        guard playitem.name != UserSettings.HistoryName.value else { return false }

        switch tableColumn.identifier {
        case .link:
            return !virgin && !appDelegate.isSandboxed

        case .plays:
            return true

        default:
            return virgin || ![.link,.plays].contains(tableColumn.identifier)
        }
    }
    else
    {
        return false
    }
}