我有一个绑定到NSArrayController的NSTableView。我想有一个表列显示表行的索引。当你自己实现NSTableDataSource时,这很容易做到,但我无法用绑定表视图来解决它。 我想我正在寻找类似于@count键路径的东西,它给出了arrangeObjects的数量(即@index),但这显然是缺失的。
两个澄清:
答案 0 :(得分:4)
据我了解,您可以选择不绑定该表列,而是使用数据源。我记得NSTableView支持这种“双模式”操作,但找不到任何文档来确认它。
答案 1 :(得分:2)
我最近使用NSRuler子类实现了这一点,该子类在TableView中的每一行旁边绘制行号。我将代码基于类似于here的类似代码。
您可以使用以下方法将其添加到您的桌面视图中:
NSScrollView *scrollView = [tableView enclosingScrollView];
TableLineNumberRulerView *lineNumberView = [[TableLineNumberRulerView alloc] initWithTableView:tableView
usingArrayController:arrayController];
[scrollView setVerticalRulerView:lineNumberView];
[scrollView setHasVerticalRuler:YES];
[scrollView setRulersVisible:YES];
这是接口文件:
//
// TableLineNumberRulerView
// Line View Test
//
// Created by Ben Golding, Object Craft Pty Ltd on 7 May 2014.
// Based on code by Paul Kim on 9/28/08.
#import <Cocoa/Cocoa.h>
@interface TableLineNumberRulerView : NSRulerView<NSCoding>
@property (strong) NSArrayController *arrayController;
@property (strong) NSFont *font;
@property (strong) NSColor *textColor;
@property (strong) NSColor *alternateTextColor;
@property (strong) NSColor *backgroundColor;
@property (strong) NSDictionary *textAttributes;
@property (assign) NSUInteger rowCount;
- (id)initWithTableView:(NSTableView *)tableView usingArrayController:(NSArrayController *)arrayController;
@end
以下是实施:
//
// TableLineNumberRulerView.m
// Line View Test
//
// Created by Ben Golding, Object Craft Pty Ltd on 7 May 2014.
// Based on code by Paul Kim on 9/28/08.
#import "TableLineNumberRulerView.h"
#define DEFAULT_THICKNESS 22.0
#define RULER_MARGIN 5.0
@implementation TableLineNumberRulerView
@synthesize font;
@synthesize textColor;
@synthesize alternateTextColor;
@synthesize backgroundColor;
@synthesize textAttributes;
@synthesize rowCount;
- (id)initWithTableView:(NSTableView *)tableView usingArrayController:(NSArrayController *)arrayController
{
NSScrollView *scrollView = [tableView enclosingScrollView];
if ((self = [super initWithScrollView:scrollView orientation:NSVerticalRuler]) == nil)
return nil;
[self setClientView:tableView];
self.arrayController = arrayController;
[arrayController addObserver:self forKeyPath:@"arrangedObjects" options:NSKeyValueObservingOptionNew context:nil];
self.font = [NSFont labelFontOfSize:[NSFont systemFontSizeForControlSize:NSMiniControlSize]];
self.textColor = [NSColor colorWithCalibratedWhite:0.42 alpha:1.0];
self.alternateTextColor = [NSColor whiteColor];
self.textAttributes = @{
NSFontAttributeName: [self font],
NSForegroundColorAttributeName: [self textColor]
};
self.rowCount = [[arrayController arrangedObjects] count];
return self;
}
- (void)awakeFromNib
{
[self setClientView:[[self scrollView] documentView]]; // this will be an NSTableView instance
}
- (void)finalize
{
[self.arrayController removeObserver:self forKeyPath:@"arrangedObjects"];
}
#pragma mark -
#pragma mark Key-Value observing of changes to array controller
/*
* This picks up changes to the arrayController's arrangedObjects using KVO.
* We check the size of the old and new rowCounts and compare them to see if the number
* digits has changed, and if so, we adjust the ruler width.
*/
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([keyPath isEqualToString:@"arrangedObjects"]) {
NSUInteger newRowCount = [[self.arrayController arrangedObjects] count];
if ((int)log10(self.rowCount) != (int)log10(newRowCount))
[self setRuleThickness:[self requiredThickness]];
self.rowCount = newRowCount;
// we need to redisplay because line numbers may change or disappear in view
[self setNeedsDisplay:YES];
}
}
- (CGFloat)requiredThickness
{
NSUInteger lineCount = [[self.arrayController arrangedObjects] count],
digits = (unsigned)log10((lineCount < 1) ? 1: lineCount) + 1;
NSMutableString *sampleString = [NSMutableString string];
NSSize stringSize;
for (NSUInteger i = 0; i < digits; i++) {
// Use "8" since it is one of the fatter numbers. Anything but "1"
// will probably be ok here. I could be pedantic and actually find the fattest
// number for the current font but nah.
[sampleString appendString:@"8"];
}
stringSize = [sampleString sizeWithAttributes:[self textAttributes]];
// Round up the value. There is a bug on 10.4 where the display gets all wonky when scrolling if you don't
// return an integral value here.
return ceil(MAX(DEFAULT_THICKNESS, stringSize.width + RULER_MARGIN * 2));
}
- (void)drawHashMarksAndLabelsInRect:(NSRect)aRect
{
NSTableView *tableView = (NSTableView *)[self clientView];
NSRect bounds = [self bounds];
NSRect visibleRect = [[tableView enclosingScrollView] documentVisibleRect];
NSRange visibleRowRange = [tableView rowsInRect:visibleRect];
CGFloat yinset = NSHeight([[tableView headerView] bounds]);
if (backgroundColor != nil) {
[backgroundColor set];
NSRectFill(bounds);
[[NSColor colorWithCalibratedWhite:0.58 alpha:1.0] set];
[NSBezierPath strokeLineFromPoint:NSMakePoint(NSMaxX(bounds) - 0/5, NSMinY(bounds))
toPoint:NSMakePoint(NSMaxX(bounds) - 0.5, NSMaxY(bounds))];
}
// NSLog(@"drawHashMarksAndLabelsInRect: bounds %@, ruleThickness %lf", NSStringFromRect(bounds), [self ruleThickness]);
for (NSUInteger row = visibleRowRange.location; NSLocationInRange(row, visibleRowRange); row++) {
// Line numbers are internally stored starting at 0
NSString *labelText = [NSString stringWithFormat:@"%lu", row + 1];
NSSize stringSize = [labelText sizeWithAttributes:self.textAttributes];
NSRect rowRect = [tableView rectOfRow:row];
CGFloat ypos = yinset + NSMinY(rowRect) - NSMinY(visibleRect);
[labelText drawInRect:NSMakeRect(NSWidth(bounds) - stringSize.width - RULER_MARGIN,
ypos + (NSHeight(rowRect) - stringSize.height) / 2.0,
NSWidth(bounds) - RULER_MARGIN * 2.0, NSHeight(rowRect))
withAttributes:self.textAttributes];
}
}
#pragma mark -
#pragma mark NSCoding methods
#define FONT_CODING_KEY @"font"
#define TEXT_COLOR_CODING_KEY @"textColor"
#define ALT_TEXT_COLOR_CODING_KEY @"alternateTextColor"
#define BACKGROUND_COLOR_CODING_KEY @"backgroundColor"
- (id)initWithCoder:(NSCoder *)decoder
{
if ((self = [super initWithCoder:decoder]) != nil) {
if ([decoder allowsKeyedCoding]) {
font = [decoder decodeObjectForKey:FONT_CODING_KEY];
textColor = [decoder decodeObjectForKey:TEXT_COLOR_CODING_KEY];
alternateTextColor = [decoder decodeObjectForKey:ALT_TEXT_COLOR_CODING_KEY];
backgroundColor = [decoder decodeObjectForKey:BACKGROUND_COLOR_CODING_KEY];
} else {
font = [decoder decodeObject];
textColor = [decoder decodeObject];
alternateTextColor = [decoder decodeObject];
backgroundColor = [decoder decodeObject];
}
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)encoder
{
[super encodeWithCoder:encoder];
if ([encoder allowsKeyedCoding]) {
[encoder encodeObject:font forKey:FONT_CODING_KEY];
[encoder encodeObject:textColor forKey:TEXT_COLOR_CODING_KEY];
[encoder encodeObject:alternateTextColor forKey:ALT_TEXT_COLOR_CODING_KEY];
[encoder encodeObject:backgroundColor forKey:BACKGROUND_COLOR_CODING_KEY];
} else {
[encoder encodeObject:font];
[encoder encodeObject:textColor];
[encoder encodeObject:alternateTextColor];
[encoder encodeObject:backgroundColor];
}
}
@end
答案 2 :(得分:1)
假设您的目标是复制iTunes的行为,您的列只需要显示1到(可见行数)。它根本不需要与您的模型相关。
所以,给你的控制器一个动态生成的数组属性,并在实际模型对象的数组上使它成为depend。
对于此属性,实现array accessor methods,索引的getter只需计算idx + 1
,box,然后返回该对象。您可能还需要实现整个数组getter以满足KVC。
确保将列设置为不可编辑,并将绑定设置为无条件设置enabled
。否则,当用户尝试为行输入新索引时,您将获得异常(因为没有此属性的setter)。
需要注意的一点是:这可能会导致问题,因为NSTableView不希望其列绑定到离散数组;它希望它的所有列都绑定到单个数组中的模型对象的不同属性。除了绑定列的内容绑定外,您可能还需要将表视图本身的content
绑定到模型对象数组,并I've had trouble with that before。