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

お察しのとおり、これらの方法により、私の作業が少し楽になるはずです。

次に、オブジェクトの次の階層があります(すべてがそのプロトコルを実装しています)->

メイン アプリケーションには、SubprojectItem クラス インスタンスの NSMutableArray を含む Subproject クラス インスタンスの NSMutableArray を含む Project クラスの 1 つのインスタンスが含まれます。

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:そのインデックスで子を返すことが期待されるため、インデックスを取ります。一度に1人の子供を返すことになっています。

プロジェクトのすべての子の配列がプロジェクトのすべての子であることをアウトライン ビューに伝えています。私はそれがあなたが意図したものではないと思います。

あなたがしたい:

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 に答える