0

所以,我想在我的应用程序中使用 NSOutlineView 来显示一个特定的,因为缺乏更好的名称,层次结构。为了解释,下面是它在代码中的样子:我有一个协议,它声明了我想显示的对象使用的一些方法:

@protocol OutlineViewItem <NSObject>

@required -(BOOL)hasChildren; //Tells whether the object has children
@required -(NSInteger)numberOfChildren; //returns 0 if none or number of children
@required -(id)getChildren; //return NSMutableArray containing children
@required -(NSString*)getDisplayableName; //returns a string that would be displayed in NSOutlineView

@end

可以猜到,这些方法应该让我的任务更容易一些。

然后,我有以下对象层次结构(它们都实现了该协议)->

主应用程序包含一个 Project 类的实例,它包含一个 NSMutableArray 的 Subproject 类实例,它包含一个 NSMutableArray 的 SubprojectItem 类实例。

我如何在 Project 类中使用这些协议方法的一个示例(子项目是前面提到的 NSMutableArray:

-(BOOL)hasChildren{
    if(subprojects == nil || [subprojects count] < 1){
        return NO;
    }
    return YES;
}

-(NSInteger)numberOfChildren{
    if(subprojects == nil){
        return 0;
    }
    return [subprojects count];
}

-(id)getChildren{
    return subprojects;
}

-(NSString*)getDisplayableName{
    return name;
}

Subproject 和 SubprojectItem 类以类似的方式实现这些方法。

在我的应用程序中,我定义了主窗口类(ProjectWindow)来实现 NSOutlineViewDataSource 和 Delegate 协议,并将 NSOutlineView 的数据源和委托绑定到 ProjectWindow。

在 ProjectWindowClass 中,我实现了如下方法:

- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item
{
    return item == nil ? project : [item getChildren];
    //if I understand it correctly, it return the children of a given node.
    //if item is nil, it should return the root, that is, project, or the children of item.
}

- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item
{
    return item == nil? YES : [item hasChildren];
    //Same as above: project is expendable, other nodes can be expanded if contain children    
}

- (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item
{
    return item == nil? 1 : [item numberOfChildren];
    //Same as above: there's 1 project, or it returns num of children;
}

- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
{
    return item == nil ? @"ROOT" : [item getDisplayableName];
    //I think that's what is going to be displayed in NSOutlineView, next to the expendable arrow
}

但是,当我尝试运行它时,遇到了以下异常:

2013-08-23 22:45:12.930 myProject[1903:303] -[__NSArrayM hasChildren]: unrecognized selector sent to instance 0x101a16f30

如果我了解整个 NSOutlineViewDataSource,它应该返回根项,如果使用 item == nil 请求,如果 item != nil 则返回 item 的子项。但是,虽然我认为它应该是这样的,但它不起作用,应用程序挂起。

那么,我应该如何实现所有这些数据源方法以使其按预期工作?

4

1 回答 1

1
- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item
{
    return item == nil ? project : [item getChildren];
    //if I understand it correctly, it return the children of a given node.

不是所有的一次!

outlineView:child:ofItem:需要一个索引,因为它预计会在该索引处返回子级。它应该一次返回一个孩子。

您正在告诉大纲视图,该项目的所有子项的数组是该项目的每个子项。我不认为那是你的意思。

你要:

return item == nil ? project : item[index];

(顺便说一句,你不应该命名一个变量index。有一个用这个名字命名的函数,所以如果你忘记或拼错了变量的声明,当你把这个index函数用作数组索引时,就会很开心。)

- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
{
    return item == nil ? @"ROOT" : [item getDisplayableName];
    //I think that's what is going to be displayed in NSOutlineView, next to the expendable arrow

是的,所以你想要一个本地化的字符串。在字符串NSLocalizedString周围使用。@"ROOT"更好的是,将它移到项目中的一个方法中,然后无条件地询问项目的可显示名称。

于 2013-08-24T05:16:40.590 回答