过滤NSOutlineView / NSTreeController

时间:2009-07-25 10:23:21

标签: objective-c cocoa nsoutlineview

如何使用搜索框过滤NSOutlineView / NSTreeController?我知道它会与绑定和谓词有关。但不具体如何。有人可以带我完成过滤NSOutlineView / NSTreeController的步骤吗?

3 个答案:

答案 0 :(得分:2)

我认为你不能。 NSArrayController允许你给它一个过滤谓词; NSTreeController没有。我建议你file a bug

答案 1 :(得分:0)

从macOS 10.11开始,NSTableView(因此子类NSOutlineView)有了新的hideRows& unhideRows方法简化了过滤行的任务。仍然没有自动支持过滤掉NSTreeController中的项目(不是 NSArrayController的子类,因此不会继承其filter谓词),但它至少做了很多繁重的工作,允许你将整个模型保留在控制器中,同时只显示它的一部分。

答案 2 :(得分:0)

我在这个问题上花了很多心思,但实时过滤 NSTreeController 实际上非常简单,您只需要调整您的实际节点对象即可。

在我的例子中,我放弃了在控制器上实现实际的过滤器,只是在我的树节点上传递了一个谓词。当谓词在叶节点上不匹配时,我只需将其从 children 数组中删除。

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,并将其键路径设置为 filteredChildrencountisLeaf。当然,您可以以不同的方式命名对象访问器。现在,当我想过滤树时,我在根节点上设置了一个 NSPredicate,将其向下传递。

也适用于 KVO,无需额外代码,NSOutlineView 将自动更新。