6

NSArrayController にバインドされた NSTableView があります。テーブル行のインデックスを示すテーブル列の 1 つが必要です。これは、自分で NSTableDataSource を実装すると簡単に実行できますが、バインドされたテーブル ビューではわかりません。ここで、arrangedObjects (つまり @index) の数を取得する @count キー パスのようなものを探していると思いますが、これは明らかに欠落しています。

2 つの説明:

  1. 各行に表示されるインデックスは、その行のインデックスであり、モデルまたは配列コントローラーでデータが実際に配置される方法とはまったく関係ありません。たとえば、データ全体が 10000 アイテムである場合、インデックスは 1 から 10000 に移動する必要があります。ユーザーが検索語を入力し、テーブルにアイテムが 4 つしか表示されていない場合、数値は 1 から 4 に移動する必要があります。表示されているアイテムは、実際には元の配列全体からのものです。
  2. クライアントからこれをするように頼まれたので、これが必要です:-)。クライアントには、特定の行の前後の行数を推定できる方法が必要です。たとえば、追加された行数を知りたいとします。
4

3 に答える 3

4

私が理解しているように、そのテーブル列をバインドせず、代わりにデータソースを使用することを選択できます。NSTableView はこの種の「デュアルモード」操作をサポートしていることを思い出しますが、それを確認するためのドキュメントが見つかりません。

于 2010-01-02T18:27:41.513 に答える
2

私は最近、TableView の各行の横に行番号を描画する NSRuler サブクラスを使用してこれを実装しました。ここで見つけた同様のものに基づいてコードを作成しました。

以下を使用して、これをテーブルビューに追加できます。

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
于 2014-05-15T05:29:49.790 に答える
1

iTunes の動作を複製することを目的としていると仮定すると、列に 1 から (表示される行の数) を表示するだけで済みます。実際には、モデルに関連付ける必要はまったくありません。

したがって、コントローラーに動的に生成された配列プロパティを与え、実際のモデル オブジェクトの配列に依存するようにします。

このプロパティに対して、配列アクセサ メソッドを実装し、インデックス付きの getter で単に計算idx + 1し、ボックス化し、そのオブジェクトを返します。KVC を満たすために、配列全体の getter を実装する必要がある場合もあります。

列が編集不可に設定されていること、およびバインディングが not conditionally set に設定されていることを確認してくださいenabled。そうしないと、ユーザーが行の新しいインデックスを入力しようとしたときに、(このプロパティのセッターがないため) 例外が発生します。

1 つの注意事項: NSTableView はその列が個別の配列にバインドされることを想定していないため、これにより問題が発生する可能性があります。すべての列が 1 つの配列内のモデル オブジェクトのさまざまなプロパティにバインドされることを想定しています。content列のコンテンツ バインディングのバインドに加えて、テーブル ビュー自体の をモデル オブジェクトの配列にバインドする必要がある場合があります。

于 2010-01-02T15:12:38.040 に答える