【发布时间】:2009-07-25 10:23:21
【问题描述】:
如何使用搜索框过滤 NSOutlineView/NSTreeController?我知道这与绑定和谓词有关。但不具体如何。有人可以带我完成过滤 NSOutlineView/NSTreeController 的步骤吗?
【问题讨论】:
标签: objective-c cocoa nsoutlineview
如何使用搜索框过滤 NSOutlineView/NSTreeController?我知道这与绑定和谓词有关。但不具体如何。有人可以带我完成过滤 NSOutlineView/NSTreeController 的步骤吗?
【问题讨论】:
标签: objective-c cocoa nsoutlineview
我不认为你可以。 NSArrayController 允许你给它一个过滤谓词; NSTreeController 没有。我建议你file a bug。
【讨论】:
从 macOS 10.11 开始,NSTableView(因此是子类 NSOutlineView)具有新的 hideRows 和 unhideRows 方法,可简化过滤行的任务。仍然没有自动支持过滤掉NSTreeController 中的项目(它不是 NSArrayController 的子类,因此不继承其filter 谓词),但它至少做了很多允许您将整个模型保留在控制器中,同时只显示其中的一部分。
【讨论】:
在这个问题上我费了好大的劲儿,但实际上过滤NSTreeController 非常简单,你只需要调整你的实际节点对象。
在我的例子中,我放弃了在控制器上实现实际的过滤器,只是将一个谓词传递给我的树节点。当谓词在叶节点上不匹配时,我只需将其从子数组中删除。
class PredicateOutlineNode: NSObject {
typealias Element = PredicateOutlineNode
@objc dynamic var children: [Element] = [] {
didSet {
propagatePredicatesAndRefilterChildren()
}
}
@objc private(set) dynamic var filteredChildren: [Element] = [] {
didSet {
count = filteredChildren.count
isLeaf = filteredChildren.isEmpty
}
}
@objc private(set) dynamic var count: Int = 0
@objc private(set) dynamic var isLeaf: Bool = true
var predicate: NSPredicate? {
didSet {
propagatePredicatesAndRefilterChildren()
}
}
private func propagatePredicatesAndRefilterChildren() {
// Propagate the predicate down the child nodes in case either
// the predicate or the children array changed.
children.forEach { $0.predicate = predicate }
// Determine the matching leaf nodes.
let newChildren: [Element]
if let predicate = predicate {
newChildren = children.compactMap { child -> Element? in
if child.isLeaf, !predicate.evaluate(with: child) {
return nil
}
return child
}
} else {
newChildren = children
}
// Only actually update the children if the count varies.
if newChildren.count != filteredChildren.count {
filteredChildren = newChildren
}
}
}
现在您可以将NSTreeController 类名设置为PredicateOutlineNode,并将其关键路径设置为filteredChildren、count 和isLeaf。当然,您可以以不同的方式命名您的对象访问器。现在,当我想过滤树时,我在根节点上设置了一个NSPredicate,它将它向下传递。
也适用于 KVO,无需额外代码,NSOutlineView 将自动更新。
【讨论】: