NSOutlineView:仅展开特定类别的所有对象

5

如何最有效地展开NSOutlineView中特定类别的所有对象?(我的轮廓视图的数据源是NSTreeController。)

假设我有:

classA
classA
    - classA
        - classC
        - classC
    - classB
        - classC
        - classC
classB
   - classC

我想仅展开classA对象。我需要遍历整个树来检查每个对象属于哪个类吗? 更新:抱歉,我需要更正一下。outlineView对象是NSTreeController数据源中的NSTreeNode。只有“representedObject”是我的自定义类。
所以这些类的结构是正确的,但它们不能直接作为轮廓视图的节点进行访问。
3个回答

3

说句实话,我在评论中提到的重要的"粘合"部分,更或多或少地来自这篇优秀博客文章:Saving the expand state of a NSOutlineView

我将树中的所有类都作为抽象类的子类,并增加了一个expanded属性,因此每个NSTreeNode中的representedObject都有expanded属性。

但是如果您不在意在数据模型中保留expanded,则可能不需要这样做。

直接做的方法就是迭代行:

    for (NSUInteger row = 0; row < [outlineView numberOfRows]; row++)
    {
        // Expand item if it's an classA
        NSTreeNode* treeNode = [outlineView itemAtRow:row];
        if ([treeNode.representedObject isKindOfClass:[ClassA class]])
            [sender.animator expandItem:treeNode];
    }

如果仔细阅读参考博客文章的话,您会发现 for 循环从中引用了很多结构。

因此,我的回答是懒惰的,“是的,迭代整个树形结构。” 至少要迭代显示的树形结构。

编辑: 对于那些过分热衷于 MVC 的人,我现在觉得有必要指定上述代码应该位于您用作 NSOutlineView 控制器的类中,该类通常会实现 <NSOutlineViewDelegate>


1
抱歉,我必须进行更正。outlineView 对象来自 NSTreeController 数据源的 NSTreeNode。只有 "representedObject" 是我的自定义类。因此,我无法向这些对象添加任何属性,因为我没有对节点进行子类化。 - aneuryzm
1
@Patrick - 只是迭代行是简单的事情,因此您应该指定O(rows)不够。我仍然认为NSTreeNode包装器对于上述问题并不是很困难,但我必须去查看我的旧代码以获取粘合剂。 - stevesliva
@stevesliva 很不幸,链接现在已经失效了。 - koen

0

听起来像是 NSOutlineViewDelegate 的工作:

- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
{
    if ([[item representedObject] isMemberOfClass:[ClassA class]]) {
        [outlineView expandItem:item];
    }
}

-1
我需要遍历整个树来检查每个对象属于哪个类吗?
是的,因为这就是你想要做的。
但这并不像stevesliva中的A那么简单:
A. 你不应该遍历大纲视图的项目。它只是一个视图,与数据无关。也就是说,如果一个节点关闭了,它的后代不在行列表中。这是因为没有为它们创建行。
B. 相反,遍历树控制器的内容。控制器是用于访问数据的,所以访问数据的正确位置是在这里。-arrangedObjects(NSTreeController)可以让你访问内容。

1
这很容易,就像stevesilva的回答一样,因为没有迹象表明OP想要展开包含classA对象的节点,只是展开那些 classA对象的节点。如果一个classA对象在被折叠的classB对象内部,那么无论该classA对象是“展开”还是“折叠”,都没有特定的意义。因此,足以遍历行并展开您遇到的classA行。 - Ken Thomases
1
有一个提示:“展开特定类的所有对象”。除此之外,按照所提到的方式向视图请求数据是一种方法上的错误。 - Amin Negm-Awad
1
@AminNegm-Awad - 我认为你没有必要给自己戴上手铐,如果你认为在试图有效地修改视图而不是模型时无法查询视图。这就好像声明您无法使用视图层次结构代码仅删除所有视图的子视图一样荒谬。控制器对其视图出口具有弱引用,显然是因为视图拥有视图层次结构,并且在更改显示内容时肯定可以遍历视图层次结构。 - stevesliva
1
视图的更改取决于模型中的数据,例如数据类型。因此,您必须向模型提出请求。您可以通过控制器来实现这一点。这是相当简单的MVC。在视图中删除子视图不取决于模型中的数据。您可以在视图层中执行此操作。因此,您可以遍历任何您想要的地方,但如果您需要 [underlyingData somewhat],则必须向控制器提出请求。(您可以使用Cocoa绑定从视图中执行此操作,但几乎没有用处。)如上所述,如果您必须检查实际未显示的数据,则您的方法至少会失败。 - Amin Negm-Awad
1
@AminNegm-Awad - 这段代码将会在控制器中,至少是实现了outlineview委托方法的类中。你可以同时拥有treeController和这个。我并不建议将提供的代码片段包含在outlineview的子类中,因为使用isKindOfClass来检查子类是丑陋的...但是对于实现NSOutlineViewDelegate的类来说,查询视图状态和询问模型对象是标准的做法。 - stevesliva
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接