如何使用Cocoa Bindings实现基于视图的源列表(NSOutlineView)?

17

有没有人找到一份清晰简洁的示例或指南,介绍如何使用 Lion 中引入的基于视图的 NSOutlineView 实现源列表?我已经查看了苹果的示例项目,但是没有方向感或解释,我很难理解它们的工作原理。

我知道如何使用优秀的 PXSourceList 作为备选方案,但如果可能的话,我真的很想开始使用基于视图的源列表。

2个回答

30

你在标签中加入了cocoa-bindings标签,所以我假设你的意思是“使用绑定”。我快速设计了一个示例。从Xcode中的新非文档型Cocoa应用程序模板开始,将其命名为任何你喜欢的名称。首先,我添加了一些代码来生成一些虚假数据进行绑定。这是我的AppDelegate头文件的样子:

#import <Cocoa/Cocoa.h>

@interface SOAppDelegate : NSObject <NSApplicationDelegate>

@property (assign) IBOutlet NSWindow *window;

@property (retain) id dataModel;

@end

这是我的AppDelegate实现的样子:

#import "SOAppDelegate.h"

@implementation SOAppDelegate

@synthesize window = _window;
@synthesize dataModel = _dataModel;

- (void)dealloc
{
    [_dataModel release];
    [super dealloc];
}

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    // Insert code here to initialize your application

    // Make some fake data for our source list.
    NSMutableDictionary* item1 = [NSMutableDictionary dictionaryWithObjectsAndKeys: @"Item 1", @"itemName", [NSMutableArray array], @"children", nil];
    NSMutableDictionary* item2 = [NSMutableDictionary dictionaryWithObjectsAndKeys: @"Item 2", @"itemName", [NSMutableArray array], @"children", nil];
    NSMutableDictionary* item2_1 = [NSMutableDictionary dictionaryWithObjectsAndKeys: @"Item 2.1", @"itemName", [NSMutableArray array], @"children", nil];
    NSMutableDictionary* item2_2 = [NSMutableDictionary dictionaryWithObjectsAndKeys: @"Item 2.2", @"itemName", [NSMutableArray array], @"children", nil];
    NSMutableDictionary* item2_2_1 = [NSMutableDictionary dictionaryWithObjectsAndKeys: @"Item 2.2.1", @"itemName", [NSMutableArray array], @"children", nil];
    NSMutableDictionary* item2_2_2 = [NSMutableDictionary dictionaryWithObjectsAndKeys: @"Item 2.2.2", @"itemName", [NSMutableArray array], @"children", nil];
    NSMutableDictionary* item3 = [NSMutableDictionary dictionaryWithObjectsAndKeys: @"Item 3", @"itemName", [NSMutableArray array], @"children", nil];

    [[item2_2 objectForKey: @"children"] addObject: item2_2_1];
    [[item2_2 objectForKey: @"children"] addObject: item2_2_2];

    [[item2 objectForKey: @"children"] addObject: item2_1];
    [[item2 objectForKey: @"children"] addObject: item2_2];

    NSMutableArray* dataModel = [NSMutableArray array];

    [dataModel addObject: item1];
    [dataModel addObject: item2];
    [dataModel addObject: item3];

    self.dataModel = dataModel;
}

@end

我创建的假数据结构没有特别的意义,我只是想展示一些具有几个子级的内容等等。唯一重要的是,在 Interface Builder 中指定绑定时的关键路径需要与你的数据中的键(在这种情况下,是虚假数据)相匹配。

然后选择MainMenu.xib文件,在 IB 编辑器中执行以下步骤:

  1. 使用对象库 (Ctrl-Cmd-Opt-3) 将 NSTreeController 添加到你的 .xib
  2. 选择 NSTreeController,并使用属性检查器 (Cmd-Opt-4) 设置关键路径 > 子项children (对于该示例;对于你的数据,应该是返回子对象数组的任何内容)。
  3. 仍然选择 NSTreeController,使用绑定检查器 (Cmd-Opt-7) 将内容数组绑定到 AppDelegate,模型键路径为dataModel
  4. 接下来,使用对象库 (Ctrl-Cmd-Opt-3) 将 NSOutlineView 添加到你的 .xib
  5. 在窗口内按照你的需求进行排列 (通常是整个窗口的高度,紧贴左侧)
  6. 选择 NSOutlineView (注意,第一次单击它时,你很可能选择了包含它的 NSScrollView。第二次单击后,你将进入了 NSOutlineView 本身。请注意,如果你扩大左侧的 IB 编辑器区域,在那里看到所有对象作为树状图展示,这样可以更轻松地导航和选择它们)。
  7. 使用属性检查器 (Cmd-Opt-4) 设置 NSOutlineView:
    • 内容模式: 视图为基础
    • 列数: 1
    • 高亮显示: 源列表
  8. 使用绑定检查器 (Cmd-Opt-7) 将 "内容" 绑定到 "Tree Controller",控制器键: arrangedObjects (这就是视图为基础的 NSTableView/NSOutlineViews 的行为开始与 NSCell-based 大不相同的地方)。
  9. 在对象列表 (在 #6 中提到) 中展开 NSOutlineView 的视图层次结构,并选择静态文本 - 表格视图单元格
  10. 使用绑定检查器 (Cmd-Opt-7) 将绑定到表格视图单元格视图,模型键路径:objectValue.itemName (我在虚假数据中使用了 itemName,你应该使用与你的数据项名称对应的任何键)。

保存。运行。 你应该会看到一个源列表,一旦你展开了具有子级的节点,就可能会看到像这样的东西:

enter image description here

如果你是苹果开发者计划的成员,你应该可以访问 WWDC 2011 视频。其中一个视频专门介绍了如何使用基于视图的 NSTableView (和 NSOutlineView),并包括对绑定的相当全面的覆盖。

希望能有所帮助!


1
请注意,WWDC 2011视频的会话编号为120,标题为“基于视图的NSTableView”。 - jemeshsu
1
对于那些使用这个的人,请考虑:https://dev59.com/6Gw05IYBdhLWcg3wrDpS - bijan
1
@Olivier 我曾经遇到过同样的问题,答案在这里:https://dev59.com/6Gw05IYBdhLWcg3wrDpS。虽然这是一个有点老的帖子,但我希望能对某些人有所帮助! - TheNextman
亲爱的ipmcc,我有一个问题,您的数据模型是否可以使用自定义对象?我不明白如何使用例如具有不同属性的3个不同对象,在表格单元视图中,我需要不同的模型键路径而不是相同的,这种情况下我需要添加代码吗? - francesco.venica
这将很容易成为一个独立的问题,因此考虑以那种方式提问。简而言之,一般来说,绑定是“声明性”的,因为您在设计时“声明”它们要绑定到的属性,并且不会更改。据我的经验,编写一个“shim”(类别或其他内容)使得所有3个类都公开相同的属性比在运行时更改关键路径更容易。严格来说,可能会在运行时创建和销毁绑定,但我发现这比它的价值更麻烦。(即,如果您正在编写代码,则只需在代码中实现您的目标,而无需使用绑定) - ipmcc
显示剩余7条评论

5
请看这个例子。

SideBarDemo

这是一个侧边栏演示的示例代码。

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