Cocoa:关于 NSTableView Type Select

1,687 阅读3分钟

本文总结了 Table View 怎样处理键盘事件,以及如何通过 delegate 方法来定制其行为。

在处理某 View Controller 的键盘事件时, keyDown: 事件总是无法正确响应,因为 View Controller 中有 Table View ,每当与 Table View 交互后 Window 的 First Responder 就会变成 Table View ,而键盘事件在 Table View 中被处理并结束了。这就是 NSTableView 的 Type Selection 行为。

通过实现 Table View 的一些相关 delegate 方法就能简单轻松地定制化 Table View 的 Type Selection 行为。

Type Selection

为了简化表格的操作,NSTableView 通过支持 Type Selection 让用户可以使用键盘来查找或者选择 Table View 中对应的行。 在 Table View 的 keyDown: 事件中,默认会通过比较按键内容与每一行 View 的 stringValue 来查找并选择。

定制化的 Type Selection

首先可以通过设置 Table View 的 allowsTypeSelect 属性来启用或者禁用 Type Selection(默认是启用的)。

Type Selection 通过 delegate 方法 tableView(_:typeSelectStringFor:row:) 返回的 String? 和键盘事件中按键的值比较来判断相对应要查找或选择的行。

当 delegate 没有实现 tableView(_:typeSelectStringFor:row:) 方法时,Table View 将通过 preparedCell(atColumn:row:) 返回 Cell 的 stringValue 作为查找的值。

总之 Table View 中任一一项都有相对应的可查找的值。如果需要限制 Type Selection 在 Table View 中可进行有效查找的范围,可以通过在 tableView(_:typeSelectStringFor:row:) 方法中对特定的列或者行返回 nil 来实现。

通过实现 delegate 的 tableView(_:nextTypeSelectMatchFromRow:toRow:for:) 方法可以进一步的定制 Type Selection 的行为。如果已经选中多行,该方法将在选中的行中通过与当前的 string 比较合适的值选择某一行,如果没有合适的行则返回 -1

此外 delegate 可以通过实现 tableView(_:shouldTypeSelectFor:withCurrentSearch:) 方法决定 Type Selection 是否响应某些特定的键盘事件。需要注意的是,在这一方法中返回 NO 仅禁止了 Type Selection 的处理,并不会就此终止键盘事件继续传递,如果实现自定义的快捷键不能在这个函数中直接进行处理,而应该重载 keyDown: 方法。

总结

Table View 的 Type Selection 整个过程可以用伪代码描述如下:

// in NSTableView
keyDown(theEvent: NSEvent) {  
    // Pseudo-code 
    guard allowsTypeSelect else {
        super.keyDown(theEvent)
        return
    }
    var matchRow = nil
    let currentSearch = theEvent.characters
    for row in rows {
        if !shouldTypeSelectForRowAndCurrentSearch {
            // 'true' if delegate not implement this method.
            continue
        }
        if let typeSelectStringAtRow == currentSearch {
            // using 'preparedCell.stringValue' if delegate not implement this method.
            matchRow = row
            break
        }
    }
    select(matchRow)
}

NSTableView 及 NSTableViewDelegate 中相关的属性、方法如下:

讨论

在学习文档过程中,由于几个相关文档的版本及更新时间不一,尚有一些存在困惑的地方。上文提到:

当 delegate 没有实现 tableView(_:typeSelectStringFor:row:) 方法时,Table View 将通过 preparedCell(atColumn:row:) 返回 Cell 的 stringValue 作为查找的值。

令人不解的是此方法仅对基于 NSCell 的 Table View 有效,并且在 最新文档 中方法已标记为 Deprecated ,改为 view(atColumn:row:makeIfNecessary:) ,可无论 return 的 NSView 或 NSTableCellView 都没有 stringValue

在实际情况中似乎 View 和 subViews 中有 stringValue 的值都可以被 Type Selection 搜索。

因此在 delegate 没有实现 tableView(_:typeSelectStringFor:row:) 方法时 Table View 是如何获取每一行的 stringValue 并不清楚。

参考

🍃 That's all, Happy Coding 🍂

支持我们

SalesX 是给 Apple 开发者使用的菜单栏工具,第一时间把 app 销售情况推送给你,7 天免费试用

CurrencyX 是 Mac 上小而美的汇率 app

如果你觉得文章对你有帮助,可以买一个支持我们

关注我们公众号,获取最新文章推送