正确的方法获取rearrangeObject发送到一个NSTreeController更改树中的节点后? [英] Correct way to get rearrangeObjects sent to an NSTreeController after changes to nodes in the tree?

查看:522
本文介绍了正确的方法获取rearrangeObject发送到一个NSTreeController更改树中的节点后?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

获取 rearrangeObjects 在树中的节点更改后发送到NSTreeController?我有一个示例应用程序(下面的完整代码)使用NSOutlineView和NSTreeController与一个简单的树对象的Node对象。

What is the appropriate way to get rearrangeObjects to be sent to an NSTreeController after changes to nodes in the tree? I have a sample application (full code below) using an NSOutlineView and NSTreeController with a simple tree of Node objects.

在应用程序的版本1,当您编辑名称一个节点,该树不会被求助,直到您单击列标题或使用菜单中的重新排列项。后者被设置为直接发送rearrangeObject到NSTreeController。

In Version1 of the app, when you edit the name of a Node, the tree doesn't get resorted until you click the column header or use the "Rearrange" item in the menu. The latter is set up to directly send rearrangeObjects to the NSTreeController.

在版本2中,我尝试从节点的setName:方法发送rearrangeObjects。这似乎不是一个好的解决方案,因为它意味着模型现在已经知道视图/控制器。此外,它有副作用,大纲视图失去焦点后重命名(如果你选择一个节点并编辑它的名称,选择栏从蓝色变成灰色)出于某种原因(为什么?)。

In Version2, I tried sending rearrangeObjects from the Node's setName: method. This doesn't seem like a good solution because it means the model now has knowledge of the view/controller. Also, it has the side effect that the outline view loses focus after the rename (if you select a Node and edit its name, the selection bar turns from blue to gray) for some reason (why is that?).

NSArrayController有一个方法 setAutomaticallyRearrangesObjects:但是NSTreeController没有?那么,解决这个问题的正确方法是什么?

NSArrayController has a method setAutomaticallyRearrangesObjects: but NSTreeController does not? So what is the appropriate way to solve this?

/* example.m

    Compile version 1:
        gcc -framework Cocoa -o Version1 example.m
    Compile version 2:
        gcc -framework Cocoa -o Version2 -D REARRANGE_FROM_SETNAME example.m

*/

#import <Cocoa/Cocoa.h>

NSTreeController *treeController;
NSOutlineView    *outlineView;
NSScrollView     *scrollView;

@interface Node : NSObject {
    NSString *name;
    NSArray *children;
}
@end

@implementation Node
- (id) initWithName: (NSString*) theName children: (id) theChildren
{
    if (self = [super init]) {
        name = [theName retain];
        children = [theChildren retain];
    }
    return self;
}

- (void) setName: (NSString*) new
{
    [name autorelease];
    name = [new retain];
#ifdef REARRANGE_FROM_SETNAME
    [treeController rearrangeObjects];
#endif
}
@end

NSArray *createSortDescriptors()
{
    return [NSArray arrayWithObject: [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES]];
}

void createTheTreeController()
{
    Node *childNode1 = [[[Node alloc] initWithName:@"B" children:[NSArray array]] autorelease];
    Node *childNode2 = [[[Node alloc] initWithName:@"C" children:[NSArray array]] autorelease];
    Node *childNode3 = [[[Node alloc] initWithName:@"D" children:[NSArray array]] autorelease];

    Node *topNode1 = [[[Node alloc] initWithName:@"A" children:[NSArray arrayWithObjects:childNode1,childNode2,childNode3,nil]] autorelease];
    Node *topNode2 = [[[Node alloc] initWithName:@"E" children:[NSArray array]] autorelease];
    Node *topNode3 = [[[Node alloc] initWithName:@"F" children:[NSArray array]] autorelease];

    NSArray *topNodes = [NSArray arrayWithObjects:topNode1,topNode2,topNode3,nil];

    treeController = [[[NSTreeController alloc] initWithContent:topNodes] autorelease];
    [treeController setAvoidsEmptySelection:NO];
    [treeController setChildrenKeyPath:@"children"];
    [treeController setSortDescriptors:createSortDescriptors()];
}

void createTheOutlineView()
{
    outlineView = [[[NSOutlineView alloc] initWithFrame:NSMakeRect(0, 0, 284, 200)] autorelease];
    [outlineView bind:@"content" toObject:treeController withKeyPath:@"arrangedObjects" options:nil];
    [outlineView bind:@"sortDescriptors" toObject:treeController withKeyPath:@"sortDescriptors" options:nil];
    [outlineView bind:@"selectionIndexPaths" toObject:treeController withKeyPath:@"selectionIndexPaths" options:nil];

    NSTableColumn *column = [[[NSTableColumn alloc] initWithIdentifier:@"NameColumn"] autorelease];
    [[column headerCell] setStringValue:@"Name"];
    [outlineView addTableColumn:column];
    [outlineView setOutlineTableColumn:column];
    [column bind:@"value" toObject:treeController withKeyPath:@"arrangedObjects.name" options:nil];
    [column setWidth:250];

    scrollView = [[[NSScrollView alloc] initWithFrame:NSMakeRect(0, 0, 300, 200)] autorelease];
    [scrollView setDocumentView:outlineView];
    [scrollView setHasVerticalScroller:YES];
}

void createTheWindow()
{
    id window = [[[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 300, 200)
        styleMask:NSTitledWindowMask backing:NSBackingStoreBuffered defer:NO]
            autorelease];    
    [window cascadeTopLeftFromPoint:NSMakePoint(20,20)];
    [window setTitle:@"Window"];
    [window makeKeyAndOrderFront:nil];

    [[window contentView] addSubview:scrollView];
}

void createTheMenuBar()
{
    id menubar = [[NSMenu new] autorelease];
    id appMenuItem = [[NSMenuItem new] autorelease];
    [menubar addItem:appMenuItem];
    [NSApp setMainMenu:menubar];
    id appMenu = [[NSMenu new] autorelease];
#ifndef REARRANGE_FROM_SETNAME
    id rearrangeMenuItem = [[[NSMenuItem alloc] initWithTitle:@"Rearrange"
        action:@selector(rearrangeObjects) keyEquivalent:@"r"] autorelease];
    [rearrangeMenuItem setTarget: treeController];
    [appMenu addItem:rearrangeMenuItem];
#endif
    id quitMenuItem = [[[NSMenuItem alloc] initWithTitle:@"Quit"
        action:@selector(terminate:) keyEquivalent:@"q"] autorelease];
    [appMenu addItem:quitMenuItem];
    [appMenuItem setSubmenu:appMenu];
}

void setUpAutoReleasePoolAndApplication()
{
    [NSAutoreleasePool new];
    [NSApplication sharedApplication];
    [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
}

void activateAppAndRun()
{
    [NSApp activateIgnoringOtherApps:YES];
    [NSApp run];
}

int main(int argc, const char * argv[])
{
    setUpAutoReleasePoolAndApplication();
    createTheTreeController();
    createTheOutlineView();
    createTheWindow();
    createTheMenuBar();
    activateAppAndRun();
    return 0;
}


推荐答案

部分回答我自己的问题,看了苹果的 iSpend示例应用程序。他们的文件TransactionsController_Sorting.m包括一个方法scheduleRearrangeObjects,以不同的方式调用rearrangeObjects。以相同的方式更改自己的代码意味着在setName:方法中包含此代码片段:

I'm at least able to partly answer my own question after having looked at Apple's iSpend sample application. Their file TransactionsController_Sorting.m includes a method scheduleRearrangeObjects that invokes rearrangeObjects in a different way. Changing my own code in the same way means including this snippet in the setName: method:

#ifdef REARRANGE_FROM_SETNAME
    // Commented out: [treeController rearrangeObjects];
    [treeController performSelector:@selector(rearrangeObjects) withObject:nil afterDelay:0.0];
#endif

使用此更改,大纲视图在重命名节点后不再失去焦点。现在剩下要做的是将这个代码移出模型,进入视图/控制器; TransactionsController_Sorting似乎也说明了如何做到这一点。 (我仍然不明白为什么上述变化阻止大纲视图失去焦点,任何人有解释?)

With this change, the outline view no longer loses focus after renaming a node. What's left to do now is take this code out of the model and into the view/controller; TransactionsController_Sorting seems to also illustrate how to do that. (I still don't understand why the above change prevents the outline view from losing focus though, anyone have an explanation?)

这篇关于正确的方法获取rearrangeObject发送到一个NSTreeController更改树中的节点后?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆