在具有两个相同NSOutlineView并排的macOS Cocoa应用程序中,有没有办法在两者之间同步扩展/折叠项目?

问题描述 投票:1回答:2

我正在Swift 5.1中开发macOS Cocoa应用程序。在主窗口中,我有两个完全相同的NSOutlineViews,它们具有完全相同的内容。我想启用一个同步模式,如果项目在两个NSOutlineViews之一中展开/折叠,则相应的项目在另一个NSOutlineViews中同时展开/折叠。我试图通过在委托中实现shouldExpandItem和shouldCollapseItem来做到这一点。这两个NSOutlineViews的委托是相同的对象,并且我有引用两个NSOutlineViews的插座来区分两者。问题是,如果我在shouldExpandItem中以编程方式调用expandItem,则会再次为另一个NSOutlineView调用该方法,从而导致无限循环和堆栈溢出。我发现了一个肮脏的解决方案,该解决方案可以通过将相关NSOutlineView的代表暂时设置为nil,展开/折叠该项目,然后再重新设置代表来工作。代码如下:

func outlineView(_ outlineView: NSOutlineView, shouldExpandItem item: Any) -> Bool {

    let filePath = (item as! FileSystemObject).fullPath

    let trueItem = item as! FileSystemObject

    trueItem.children = Array()

    do {
        let contents = try FileManager.default.contentsOfDirectory(atPath: filePath!)

        for (_, item) in contents.enumerated() {

            let entry = FileSystemObject.init()
            entry.fullPath = URL.init(fileURLWithPath: filePath!).appendingPathComponent(item).path
            if entry.exists {
                trueItem.children.append(entry)
            }
        }

    } catch {

    }

        if outlineView == self.leftOutlineView {
            self.rightOutlineView.delegate = nil;
            self.rightOutlineView.expandItem(item)
            self.rightOutlineView.delegate = self;
        } else {
            self.leftOutlineView.delegate = nil;
            self.leftOutlineView.expandItem(item)
            self.leftOutlineView.delegate = self;
    }

    return true

}

func outlineView(_ outlineView: NSOutlineView, shouldCollapseItem item: Any) -> Bool {

    if outlineView == self.leftOutlineView {
        self.rightOutlineView.delegate = nil;
        self.rightOutlineView.collapseItem(item)
        self.rightOutlineView.delegate = self;
    } else {
        self.leftOutlineView.delegate = nil;
        self.leftOutlineView.collapseItem(item)
        self.leftOutlineView.delegate = self;

    }

    return true
}

这似乎可行,但是我担心这种方法可能会出问题。是暂时设置委托人以取消可能的解决方案,还是我应该注意任何警告?您是否可以建议另一种模式来实现这一目标?谢谢

编辑:根据下面的评论和答案

由于收到了答复/评论,我找到了最简单的解决方案。代替在outlineViewShouldExpand / Collapse方法中实现同步逻辑,可以实现outlineViewDidExpand和outlineViewDidCollapse并将同步逻辑放在那里。以编程方式扩展/折叠项目时不会调用后一种方法,因此没有无限循环或堆栈溢出的风险。

代码如下:

func outlineViewItemDidExpand(_ notification: Notification) {

    let outlineView = notification.object as! NSOutlineView

    let userInfo = notification.userInfo as! Dictionary<String, Any>

    let item = userInfo["NSObject"]

    if outlineView == self.leftOutlineView {
              self.rightOutlineView.animator().expandItem(item)
        } else {
              self.leftOutlineView.animator().expandItem(item)

    }
}

func outlineViewItemDidCollapse(_ notification: Notification) {

      let outlineView = notification.object as! NSOutlineView

      let userInfo = notification.userInfo as! Dictionary<String, Any>

      let item = userInfo["NSObject"]

      if outlineView == self.leftOutlineView {
                self.rightOutlineView.animator().collapseItem(item)
          } else {
                self.leftOutlineView.animator().collapseItem(item)

      }
  }

此外,现在,我不明白为什么动画的展开/折叠是动画的,这与我的原始方法不兼容。我希望这对某人有帮助,对我很有帮助。非常感谢。

swift macos cocoa nsoutlineview
2个回答
1
投票

我的应用执行类似的操作。我需要在Windows中保持许多视图同步。这些视图之一是NSOutlineView。我对NSOutlineView遇到了一些怪癖,但我不认为它们与同步有关。

不过,我确实采用了其他方法。我没有操纵委托,而只是拥有抑制某些动作的标志。就我而言,标志更有意义,因为许多其他视图都受到影响。但是,效果与您正在执行的操作非常相似。

我认为唯一的风险是在同步期间会丢失委托调用。假设您的逻辑不依赖于此,我相信您的方法会很好用。


0
投票

outlineView(_:shouldExpandItem:)在扩展项目之前被调用,来回调用expandItem()会引起infite循环。扩展项目后,将调用outlineViewItemDidExpand(_:),而已扩展项目(已记录的行为)时,NSOutlineView.expandItem(_:)不执行任何操作。展开左轮廓视图时,右轮廓视图的expandItem()会调用outlineViewItemDidExpand(_:),但左轮廓视图的expandItem()不会再次调用outlineViewItemDidExpand(_:)

func outlineViewItemDidExpand(_ notification: Notification) {
    let outlineView = notification.object as! NSOutlineView
    let item = notification.userInfo!["NSObject"]
    if outlineView == self.leftOutlineView {
        self.rightOutlineView.animator().expandItem(item)
    } else {
        self.leftOutlineView.animator().expandItem(item)
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.