NSOutlineView只显示NSTreeController层次结构的前两个级别。

4
我正在使用NSTreeController来填充一个NSOutlineViewNSTreeController是一个三级层次结构的控制器(CBMovie、CBDisc和CBEpisode),但在轮廓视图中只显示前两个级别。
对于所有对象,实现方法都相同:我已经实现了指定子项、子项计数以及对象是否为叶子的方法。这些方法对所有对象(包括那些未显示的孙子:CBEpisode)都被正确调用。
在轮廓视图中,前两个级别的一切都显示正确。但是孙子们从来没有显示过,我没有扩展它们的选项来查看它们。我只能看到CBMovie和CBDiscs。
我想知道是否有其他设置我错过了,关于NSTreeControllers或NSOutlineView配置中节点可以展开多深。
下面是其中一个节点的实现。每个节点类都有不同的路径到其子项,这在-(NSArray*)children方法中指定(正确调用)。
-(NSArray*)children
{
    return [[self Episodes] allObjects];
}

-(int)childrenCount
{
    return [[self Episodes] count];
}

-(BOOL)isLeaf
{
    return ![[self Episodes] count];
}

日志代码的输出。数据源NSTreeController似乎具有正确的结构。

   CBMovie
      CBDisc
         CBEpisode
         CBEpisode
    CBMovie
       CBDisc
       CBDisc
       CBDisc
       CBDisc
    CBMovie
       CBDisc
           CBEpisode
           CBEpisode

这是我如何填充NSOutlineView(基于单元格)。我不使用数据源方法,而是通过编程进行绑定。
NSMutableDictionary *bindingOptions = [[NSMutableDictionary alloc] initWithCapacity:2];

        if (metadata.valueTransformer) {
            [bindingOptions setObject:metadata.valueTransformer forKey:NSValueTransformerNameBindingOption];
        }
        [bindingOptions setObject:[NSNumber numberWithBool:NO] forKey:NSCreatesSortDescriptorBindingOption];
        [bindingOptions setObject:[NSNumber numberWithBool:NO] forKey:NSRaisesForNotApplicableKeysBindingOption];

        [newColumn bind:@"value" toObject:currentItemsArrayController withKeyPath:[NSString stringWithFormat:@"arrangedObjects.%@", metadata.columnBindingKeyPath] options:bindingOptions];

你可以分享一些代码吗? - Stefan Arentz
我正在通过IB将NSOutlineView绑定到NSTreeController。然后,我在所有节点类中仅实现了-(NSArray*)children方法。似乎我不需要其他的方法(Count和Leaf)也可以使其正常工作。 - aneuryzm
NSTreeController 可以表示层次结构的深度没有明确的限制,因此您可以排除这个可能原因。如果您发布一个演示应用程序来展示问题,我的猜测是,在您提供它后30分钟内就会有解决方案。即使这需要您付出一些努力,但从长远来看,这可能是值得的。另外,Core Data 是否参与其中? - Paul Patterson
@Patrick:您描述的行为很奇怪,因为NSTreeController+NSOutlineView组合应该渲染所有级别或者不渲染任何内容。 CBDisk节点是否有展开图标?此外,您能否提供所有三个类的children/childrenCount/isLeaf实现,并确认这三种方法是否在树控制器的“属性检查器”中配置? - Cristik
@Cristik 不,CBDisc没有展开箭头。我可以确认所有方法都已添加到所有3级类中:我在问题中添加的方法就是CBDisc中的那些方法,它们应该有效但实际上并没有。它们被正确调用,并返回Episodes数组。在界面构建器中,我已经正确指定了子项、子项计数和叶子方法名称:事实上,在电影和光盘中都调用了所有方法。 - aneuryzm
显示剩余9条评论
2个回答

1

检查 NSTreeController 的情况

NSTreeController 是一个三层级别的控制器,但只有前两个级别在大纲视图中显示。

你确认所有三个级别都已加载到你的 NSTreeController 中了吗?你可以使用下面的扩展将其内容记录到控制台以进行确认。如果此代码生成的输出与大纲视图中所显示的匹配,则问题可能出现在 NSTreeController 方面,而不是大纲视图。

#import "NSTreeController+Logging.h"

@implementation NSTreeController (Logging)

// Make sure this is declared in the associated header file.
-(void)logWithBlock:(NSString * (^)(NSTreeNode *))block {

    NSArray *topNodes = [self.arrangedObjects childNodes];
    [self logNodes:topNodes withIndent:@"" usingBlock:block];
}

// For internal use only.
-(void)logNodes:(NSArray *)nodes
     withIndent:(NSString *)indent
     usingBlock:(NSString * (^)(NSTreeNode *))block {

    for (NSTreeNode * each in nodes) {
        NSLog(@"%@%@", indent, block(each));
        NSString *newIndent = [NSString stringWithFormat:@"  %@", indent];
        [self logNodes:each.childNodes withIndent:newIndent usingBlock:block];
    }
}

@end

上述代码无需调整,只需使用自定义块调用即可:
-(void)logIt {

    [self.treeController logWithBlock:^NSString *(NSTreeNode * node) {

        // This will be called for every node in the tree. This implementation
        // will see the object's description logged to the console - you may
        // want to do something more elaborate.
        NSString *description = [[node representedObject] description];
        return description;
    }];

}

检查 NSOutlineView 侧边栏

如果所有的数据都已正确加载到 NSTreeController 中,您可以查看如何填充您的 NSOutlineView。代理方法 -[NSOutlineViewDelegate outlineView:viewForTableColumn:item] 是一个很好的起点。参数 itemNSTreeNode 实例,因此,在返回相关视图之前,您可以查看此节点并确保它的行为符合预期。在您的情况下,您应该仔细检查表示 CBDisc 对象的 item 对象的属性。(您可能需要单击披露按钮才能使此方法对相关对象生效。)

-(NSView *)outlineView:(NSOutlineView *)outlineView
    viewForTableColumn:(NSTableColumn *)tableColumn
                  item:(id)item {

    NSTreeNode *node = (NSTreeNode *)item;
    NSManagedObject *representedObject = (NSManagedObject *)node.representedObject;

    // Query the node
    NSLog(@"%@ <%@>", representedObject.description, [representedObject class]);
    NSLog(@"  node is a leafNode: %@", node.isLeaf ? @"YES" : @"NO");
    NSLog(@"  node has child-count of: %lu", (unsigned long)node.childNodes.count);

    // Query the NSManagedObject
    // your stuff here...

    // This is app-specific - you'll probably need to change the identifier.
    return [outlineView makeViewWithIdentifier:@"StandardTableCellView" owner:self];
}

谢谢提供这份代码。是的,NSTreeController数据源正常工作。我有所有子项(我已经将输出添加到问题中)。但是,问题出在哪里呢?是在NSOutlineView中吗? - aneuryzm
在你的问题中,在日志输出上方,你应该明确说明大纲视图中没有出现但应该出现的内容——我假设这是“CBEpisode”的实例。一个“NSOutlineView”的截图也会非常有帮助。最后,包括一些关于你正在实现哪些“NSOutlineViewDelegate”方法的信息。 - Paul Patterson
是的,CBEpisode丢失了。 - aneuryzm
我正在实现几个委托方法。老实说,我应该仔细检查它们,因为这部分代码很旧了。你有没有想到可能导致问题的委托方法? - aneuryzm
感谢您更新问题。我已经更新了我的答案,关于一个可能提供有用信息的委托方法。 - Paul Patterson
嗨,保罗,我忘了提到我不使用基于视图的表格视图,而是使用基于单元格的。因此,您的方法从未被调用。 - aneuryzm

0

所以,我已经弄清楚原因了。

相当愚蠢:主要的大纲列只有20像素宽,子节点的箭头有缩进。

我仅使用大纲列来显示箭头而不是节点标题,这就是为什么它如此狭窄的原因。

我已禁用缩进,现在我可以看到所有箭头。


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