【问题标题】:Xcode9 Swift4.2 NSOutlineView NSTreeController dataXcode9 Swift4.2 NSOutlineView NSTreeController 数据
【发布时间】:2019-04-20 15:46:03
【问题描述】:

我正在尝试在具有多个级别的 MacOS 应用程序中创建大纲视图,这些级别是 SQLite3 中保存的一组数据的摘要。我有一个大纲视图,它使用一个基于模型类的非常简单的 NSMutuableDictionary 的树控制器。

import Cocoa
class Summary: NSObject {
    @objc dynamic var name: String
    @objc dynamic var trades: Int
    @objc dynamic var avgPL: Double
    @objc dynamic var pandl: Double
    @objc dynamic var parent: String
    @objc dynamic var isLeaf: Bool
    @objc dynamic var childCount: Int
    @objc dynamic var children: [Summary] = []
    init(name: String, trades: Int, avgPL: Double, pandl: Double, parent: String, isLeaf: Bool,childCount: Int) {
        self.name = name
        self.trades = trades
        self.avgPL = avgPL
        self.pandl = pandl
        self.parent = parent
        self.isLeaf = isLeaf
        self.childCount = childCount
    }
    @objc func add(child: Summary) {
        children.append(child)
    }
}

我的简单示例数据是:

    let root: [String : Any] = ["name": "Overall","trades":5,"avgPL":200,"pandl":500,"parent":"","isLeaf": false,"childCount": 2 ]
    let dict: NSMutableDictionary = NSMutableDictionary(dictionary: root)
    let l2a = Summary(name: "L2a", trades: 3, avgPL: 100, pandl: 300, parent: "L1",isLeaf: true,childCount: 0)
    let l2b = Summary(name: "L2b", trades: 2, avgPL: 100, pandl: 200, parent: "L1",isLeaf: true,childCount: 0)
    dict.setObject([l2a,l2b], forKey: "children" as NSCopying)

我将字典传递给treeController:

treeController.addObject(dict)

这很好地给了我一个可折叠的轮廓:

但我不知道如何为孩子添加更多关卡或孩子。我想在大纲中有多达四个级别。我有所有的 SQL 摘要工作,我尝试了很多填充数组的变体,并试图用数据创建一个字典,但无济于事。我有 children 和 childCount 并且 isLeaf 设置在所有东西上,但是 treecontroller 不喜欢数组抱怨 isLeaf 不符合 KVO。我的数组中的数据看起来是这样的(不是所有的数据但足以看到我在做什么)主级别和所有后续子级都基于上面的Summary模型类。我可以简单地将这个数组转换为字典吗?或者,我可以通过向模型类或其他东西添加键来使其符合 KVO 吗?如果有用的话,我将所有 4 个级别都放在用于构建结果数组的单独数组中:

我应该补充一点,我有一个定义为 NSMutableArray 的 NSObject,它的内容与 treeController 相关联。我的 treeController 绑定到模型类中的每个变量,并且在顶层有:

如果我将构建的数组传递给 treeController,我会收到以下错误:

Failed to set (contentViewController) user defined inspected property on (NSWindow): [<_TtGCs23_ContiguousArrayStorageC11outlinetest7Summary_ 0x604000445160> addObserver:forKeyPath:options:context:] is not supported. Key path: isLeaf

【问题讨论】:

  • Summary KVO 是否符合密钥 childrenchildCountisLeaf
  • @Willeke 在这方面我唯一知道要做的就是制作 vars @objc dynamic
  • 我认为我的 KVO 问题与 Interface Builder 相关,我可能在其中输入了不正确的内容。我能够完全剥离树控制器并完全删除绑定并使其以老式方式工作。我仍然希望 KVO 能够正常工作,所以我会继续努力。

标签: xcode9 nsoutlineview swift4.2 nstreecontroller


【解决方案1】:

在构建没有 NSTreeController 的 NSOutlineView 并让一切正常工作之后,我仍然想回到这个并实现 treeController 以利用它提供的排序机制。根据我的最后一条评论,我确实发现我在 InterfaceBuilder 中确实有问题,导致它抱怨 KVO 合规性。除了 treeController 上的 Content Array 绑定外,我的所有东西都正确连接。这里我将它绑定到我的 ViewController 并将我的数据数组 reportSummary 添加到模型键路径。

我也不再需要使用treeController.addObject(reportSummary) 手动将我的数据数组添加到treeController。一旦这个工作正常,我就能够实现排序并且一切运行良好。我应该指出两点。

  1. TreeController 上的排序设置与绑定到 TableView 的 ArrayController 上的设置略有不同。使用 tableview 就足以指定哪些列在 IB 的身份检查器中是可排序的。但在outlineView 场景中,我还需要在IB 中设置绑定到treeController,并将Controller Key 从arrangedObjects 更改为sortDescriptors

  2. 在测试我的树形控制大纲视图时,我在双击摘要行时遇到了问题。我在 IB 中的 outlineView 上实现了 Double Action,以控制摘要部分的展开和折叠。请注意,我在这里的一个线程中读到了有关执行此操作的信息,有人提到您需要维护多个数组和跟踪索引,因为一旦折叠或展开一行,就会更改所有后续行的行号。但我发现解决方案只是以相反的顺序遍历行,然后展开或折叠它们,从outlineView.numberOfRows-1 开始沿着树备份。这很好用,与 Double Action (clicking) 一起展开和折叠我还添加了一个 NSSlider,它跟踪展开级别并让我折叠所有最低级别并向上移动到树上,而不是单击每行上的所有小箭头.当我实现 treeController 时,这打破了。我收到一个错误

无法转换“NSKVONotifying_NSTreeControllerTreeNode”类型的值

这行代码就是问题所在

let summary = reportOutline.item(atRow: x) as! Summary

我不得不把它改成

let node = reportOutline.item(atRow: x) as! NSTreeNode
let summary = node.representedObject as! Summary

就是这样。现在工作得很好。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-16
    • 1970-01-01
    • 2015-10-04
    相关资源
    最近更新 更多