在树中的节点发生更改后,将rearrangeObjects发送到NSTreeController的正确方法是什么?

2023-12-12

合适的获取方式是什么重新排列对象更改树中的节点后发送到 NSTreeController?我有一个示例应用程序(完整代码如下),使用 NSOutlineView 和 NSTreeController 以及简单的 Node 对象树。

在应用程序的版本 1 中,当您编辑节点的名称时,只有单击列标题或使用菜单中的“重新排列”项,树才会重新排序。后者被设置为直接将rearrangeObjects发送到NSTreeController。

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

NSArrayController 有一个方法设置自动重新排列对象:但 NSTreeController 没有?那么解决这个问题的适当方法是什么?

/* 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: 方法中:

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

通过此更改,重命名节点后大纲视图不再失去焦点。现在剩下要做的就是将此代码从模型中取出并放入视图/控制器中; TransactionsController_Sorting 似乎也说明了如何做到这一点。 (我仍然不明白为什么上述更改可以防止大纲视图失去焦点,有人有解释吗?)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在树中的节点发生更改后,将rearrangeObjects发送到NSTreeController的正确方法是什么? 的相关文章

  • NSTextField 委托通知——如何获取文本?

    我一直在尝试学习使用 Xcode 但我对如何注册感到困惑NSTextField已经改变 本质上 我有一个NSTextField和一个按钮 单击该按钮会填充字段中的文本 但是 我希望能够获取该字段的文本 而无需使用文本字段 操作 结束编辑时发
  • 如何显示从 xib 加载的工作表? (MacOSx)

    我有一个 xib 文件 其中只有一个 NSPanel 我试图将此面板显示为模式表 带有beginSheet modalForWindow modalDelegate didEndSelector contextInfo 该 xib 文件的所
  • Objective-C 2.0中的多线程问题

    我有我的主应用程序委托 其中包含一个返回对象的方法 该应用程序委托在主线程上运行 我还有一个在不同线程上运行的 NSOperation 除了希望有时能够在主线程上调用我的应用程序委托方法之外 我还需要从 NSOperation 线程中调用它
  • 如何让程序在登录时自动启动?

    如何设置菜单栏应用程序在登录时自动启动 我希望这是默认的 我可以简单地通过在 info plist 中添加一个 bool 来做到这一点吗 此解决方案仅适用于非沙盒应用程序 LSSharedFile此解决方案中使用的功能仅适用于非沙盒应用程序
  • 用xCode制作图表[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 您好 我需要绘制一些数组来分析信号 我有一个可可项目正在进行 谁能告诉我在哪里可以找到简化这项任务的工具 基本上我想像在图形计算器上一样显
  • 类不符合 Swift 中的“CBPeripheralManagerDelegate”

    我正在尝试用 Swift 构建 iBeacon 发射器 但我无法让我的班级采用CBPeripheralManagerDelegate协议 在 Objective C 中需要这个协议来初始化 PeripheralManager 对象 但是在
  • 如何使用核心动画来动画 NSTextField 的背景颜色?

    我正在尝试使用核心动画来突出显示无效的文本字段 my field animator setBackgroundColor NSColor yellowColor 更新字段背景颜色 但不会以动画方式显示更改 正确更新字段位置等属性 我假设这是
  • Swift - 将图像从 URL 写入本地文件

    我学习 swift 的速度相当快 并且我正在尝试开发一个下载图像的 OS X 应用程序 我已经能够将要查找的 JSON 解析为 URL 数组 如下所示 func didReceiveAPIResults results NSArray pr
  • macOS 公证错误:“使用的签名算法太弱”

    我想知道是否有人熟悉这个错误 该错误仅在我将应用程序上传到 Apple 进行公证时才会发生 AppName zip AppName app Contents Resources EWSMacCompress tar gz EWSMacCom
  • 具有多列的 NSTableView

    有什么简单的方法可以将我的 NSTableView 设置为多列以仅在一列中显示某些数据 我已经设置了 IBOutlets 但我不知道从哪里开始 假设您没有使用 Cocoa Bindings Core Data 您可以通过实现以下两个方法来在
  • NSPopUpButton、绑定和缩短的寿命

    我试图了解使用 NSPopUpButton 是多么困难 它无疑是 Cocoa 中最难编程的用户元素 至少就我而言是这样 我想到的用例如下 我有一个名为 Port 的类 代表串行端口 属性中有一个名称字段 在 NSPopUpButton 中
  • 如何使虚线可移动

    我用下面的代码画了一条虚线 get the current CGContextRef for the view CGContextRef currentContext CGContextRef NSGraphicsContext curre
  • 检查 u 键是否被按下 Swift Cocoa [重复]

    这个问题在这里已经有答案了 我正在尝试检测是否U键是否被按下 如果是的话应该print BUT BUT 但我不确定如何检查不同的按键 因为按键的文档非常糟糕 我找到了带有键码的答案 但它们仅适用于 QWERTY 键盘 视图控制器 swift
  • 将 NSWindow 的内容变灰

    我有一个NSWindow with 2 NSViews an NSSplitView和一个习惯NSView 访问数据以填充这些视图可能需要一些时间 在此期间 我想将这些视图的内容灰显 我的第一个方法是有一个黑色的第三个NSView覆盖另外2
  • 为 Linux 编译 Objective-C 应用程序(API 覆盖范围)

    我可能在这里问一些奇怪的问题 但我不确定从哪里开始 问题是我正在考虑使用 Obj C 和 Foundation 类在 Mac 上编写一个命令行工具 但存在一个非常大的风险 那就是我希望能够为不同的 Linux 发行版编译它 以便将来作为服务
  • 最近打开的应用程序[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 有什么方法可以获取最近打开的应用程序 例如 4 个 的列表吗 如果是这样 怎么办 可可麦克 看看LaunchServices LSSh
  • NSArrayController 无需将大型数据集加载到数组中

    我想使用 NSArrayController 向 NSTableView 提供数据 我面临的问题是我不想将所有数据预先加载到数组中 然后使用数组控制器setContent 方法 我的数据模型是一个管理数百万条记录的大型现有代码库 它包含有效
  • Cocoa - 捕获 NSStatusItem 鼠标悬停事件

    当用户的鼠标悬停在我的 NSStatusItem 上时 如何执行函数 如果您分配自定义NSView给你的NSStatusItem s view属性 您可以覆盖NSResponder方法mouseEntered mouseMoved and
  • 无法将项目添加到 NSMutableArray ivar

    我的目标是将字符串添加到数组中 并在我调用的方法中执行此操作 在这个方法中 我在数组中得到一个空值 但不知道为什么 我在课程开始时有这样的内容 NSMutableArray listOfEvents 以及我在每个事件上调用的方法 void
  • NSSavePanel:压制“确认替换?”对话

    在导航服务领域 人们可以指定kNavDontConfirmReplacement作为创建一个选项NavDialogRef当使用已存在的文件名保存时 不会要求用户确认文件的替换 如何指定与 Cocoa 等效的行为NSSavePanel 具体方

随机推荐