NSOutlineView - 获取给定项目的 NSTableCellView

NSOutlineView - Get NSTableCellView for a Given Item

我的基于视图的大纲视图为其行显示自定义上下文菜单(右键单击菜单)。

菜单上的一个菜单项是"Rename...",菜单项的representedObject属性设置为大纲视图行代表的对象:

    let menu = NSMenu()

    // ...other menu items...

    let renameItem = NSMenuItem(
            title: "Rename...",
            action: #selector(OutlineViewController.rename(_:)),
            keyEquivalent: "")
    renameItem.representedObject = object

    menu.addItem(renameItem)

在操作方面,我想以编程方式在 table 单元格 editable 中创建文本字段。问题是,我不确定如何单独从表示的对象中获取对 table 单元格 的引用。

这是我的操作方法:

@IBAction func rename(_ sender: Any) {
    guard let menuItem = sender as? NSMenuItem else { return }
    guard let item = menuItem.representedObject else { return }

我可以获得所表示对象 (Int) 的行:

    let row = outlineView.row(forItem: item)

...和行视图 (NSTableRowView):

    let rowView = outlineView.rowView(atRow: row, makeIfNecessary: false)

我可以得到列索引(Int)和列(NSTableColumn):

    let columnIndex = outlineView.column(withIdentifier: "TitleColumn")
    let column = outlineView.tableColumns[columnIndex]

...并尝试获取单元格视图 (NSTableCellView):

    guard let cell = outlineView(outlineView, viewFor: column, item: item) as? NSTableCellView else {
        return
    }

最后,我尝试将文本字段设置为 editable:

    guard let textField = cell.textField else {
        return
    }
    textField.becomeFirstResponder()

所有这些测试都通过了(我设置了断点),但没有任何反应:文本字段不会变成editable(与双击时不同)。

我做错了什么?


编辑 我已经意识到当我打电话时:

outlineView(outlineView, viewFor: column, item: item)

这基本上是我的视图控制器正在实现的 NSOutlineViewDelegate 方法,因此它没有给我屏幕上已经显示的单元格,而是根据需要创建一个新副本。有点像打电话

UITableViewController.tableView(_:,cellForRowAt:)
// Data source method, creates or dequeues a new cell to pass 
// back to the table for display 

...而不是调用:

UITableView.cellForRowAt(_:) // table view proper的方法; returns 现有单元格如果 // 已经在屏幕上,或遵从数据源(方法 // 以上)否则

因此,我应该查询大纲视图本身,而不是调用重新创建单元格视图的委托方法。但是,我能看到的唯一有意义的方法是:

func rowView(atRow row: Int, makeIfNecessary: Bool) -> NSTableRowView?

...其中 returns 一个 NSTableRowView...

解决了。只需要更深入地研究 API:

// Get row index
let row = outlineView.row(forItem: item)

// Get view for the whole row: 
guard let rowView = outlineView.rowView(atRow: row, makeIfNecessary: false) else {
    return
}

// THIS is the missing piece: Get row subview for the given column
// (= cell)  
guard let cell = rowView?.view(atColumn: 0) as? NSTableCellView else {
    return
}

现在我有了对屏幕上实际文本字段的引用,它变得可编辑了:

self.view.window?.makeFirstResponder(cell.textField)