ane*_*yzm 8 macos cocoa objective-c nsoutlineview
我想不排序我的NSOultineView的父节点.
我的大纲视图的数据源是NSTreeController.
当单击列标题时,我想仅从层次结构的第二级及其子节点对树进行排序,并使父节点保持相同的顺序.
更新 这是我将列绑定到值并分配排序描述符的方法.
[newColumn bind:@"value" toObject:currentItemsArrayController withKeyPath:[NSString stringWithFormat:@"arrangedObjects.%@", metadata.columnBindingKeyPath] options:bindingOptions];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:metadata.columnSortKeyPath ascending:YES selector:metadata.columnSortSelector];
[newColumn setSortDescriptorPrototype:sortDescriptor];
Run Code Online (Sandbox Code Playgroud)
您可以使用自定义比较器。
为了演示这种方法的基本思想,我们假设您使用NSTreeNode树节点类。所有根节点都存储在NSArray命名的 中content,并且您的三个根节点是cat、dog和fish:
NSTreeNode *cat = [NSTreeNode treeNodeWithRepresentedObject:@"cat"];
// ...the same for dog and fish
self.content = @[cat, dog, fish];
Run Code Online (Sandbox Code Playgroud)
然后,创建您的NSSortDescriptor原型。请注意,您应该使用self作为键而不是要比较的字符串(在本例中representedObject)来访问原始节点对象。在比较器中,检查该对象是否包含在根对象数组中。如果YES,则返回,NSOrderedSame因为它将保持数组中初始顺序的顺序不变content,否则使用该compare:方法进行标准比较。
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"self" ascending:YES comparator:^NSComparisonResult(NSTreeNode *obj1, NSTreeNode *obj2) {
if ([self.content containsObject:obj1] && [self.content containsObject:obj2]) {
return NSOrderedSame;
}
return [obj1.representedObject compare:obj2.representedObject];
}];
[[outlineView.tableColumns firstObject] setSortDescriptorPrototype:sortDescriptor];
Run Code Online (Sandbox Code Playgroud)
编辑2
如果您有多个列需要单独排序,则不能将self其用作每个列的键,因为该键在所有列中应该是唯一的sortDescriptorPrototype。在这种情况下,您可以创建一个自定义对象作为representedObject并将所有数据(包括指向对象中的树节点的指针)包装起来。
编辑1
上述方法的正确性需要使用稳定的排序NSOutlineView算法对其行进行排序。也就是说,相同的项目在排序之前和之后将始终保持相同的相对顺序。然而,我在苹果文档中找不到任何关于此处使用的排序算法稳定性的证据,尽管根据我的经验,上述方法实际上是可行的。
如果您感觉不安全,您可以根据当前顺序是升序还是降序来显式比较根树节点。为此,您需要ivar保存当前订单。只需实现outlineView:sortDescriptorsDidChange:委托方法:
- (BOOL)outlineView:(NSOutlineView *)outlineView sortDescriptorsDidChange:(NSArray *)oldDescriptors {
ascending = ![oldDescriptors.firstObject ascending];
return YES;
}
Run Code Online (Sandbox Code Playgroud)
并更改return NSOrderedSame为:
if ([self.content containsObject:obj1] && [self.content containsObject:obj2]) {
NSUInteger index1 = [self.content indexOfObject:obj1];
NSUInteger index2 = [self.content indexOfObject:obj2];
if (ascending)
return (index1 < index2) ? NSOrderedAscending : NSOrderedDescending;
else
return (index1 < index2) ? NSOrderedDescending : NSOrderedAscending;
}
Run Code Online (Sandbox Code Playgroud)
编辑3
如果由于某种原因无法实现outlineView:sortDescriptorsDidChange:,您可以手动将观察者附加到outlineView的sortDescriptors数组中:
[outlineView addObserver:self forKeyPath:@"sortDescriptors" options:NSKeyValueObservingOptionNew context:nil];
Run Code Online (Sandbox Code Playgroud)
通过这种方式,当用户单击标题时您也可以收到通知。之后,不要忘记实现以下观察方法,作为 KVO 过程的一部分:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([keyPath isEqualToString:@"sortDescriptors"]) {
// Again, as a simple demonstration, the following line of code only deals with the first sort descriptor. You should modify it to suit your need.
ascending = [[change[NSKeyValueChangeNewKey] firstObject] ascending];
}
}
Run Code Online (Sandbox Code Playgroud)
为了防止内存泄漏,您必须在outlineView释放之前删除此观察者(如果不是更早的话)。如果您不熟悉 KVO,请务必查看Apple 的指南。
| 归档时间: |
|
| 查看次数: |
456 次 |
| 最近记录: |