2

ドキュメントベースの ARC を使用するアプリケーションで NSTokenField の簡単な最初の例を試し、Document クラスを NSTokenFieldDelegate にしました。それは機能しますが、デリゲートメソッド tokenField:completionsForSubstring:indexOfToken:indexOfSelectedItem: は、トークンの文字列の最初ではないトークンを正常に編集した場合でも、indexOfToken に 0 以外は表示されません。OS X 10.8.2 と 10.8 フレームワークで XCode 4.5 を使用しています。

質問: なぜ常に 0 なのですか? ユーザーが編集しているフィールドの間接的に見えるトークンの配列 0 .. n - 1 のトークンのインデックスであると思います。

再現するには、上記のようにプロジェクトを開始し、以下のテキストを追加します。次に、XIB エディターを使用して NSTokenField をドキュメント ウィンドウにドラッグし、トークン フィールドをドキュメントの tokenField として設定し、ドキュメント インスタンスをトークン フィールドのデリゲートにします。

Document.h :

#import <Cocoa/Cocoa.h>

@interface Document : NSDocument <NSTokenFieldDelegate>
{
    IBOutlet NSTokenField *tokenField;  // of (Token *).
    NSMutableDictionary *tokens;        // of (Token *).
}
@end

Token.h :

#import <Foundation/Foundation.h>

@interface Token : NSObject
@property (strong, nonatomic) NSString *spelling;
- (id)initWithSpelling:(NSString *)s;
@end

Token.m :

#import "Token.h"

@implementation Token
@synthesize spelling;

- (id)initWithSpelling:(NSString *)s
{
    self = [super init];
    if (self)
        spelling = s;
    return self;
}

@end

Document.m :

#import "Document.h"
#import "Token.h"

@implementation Document

- (id)init
{
    self = [super init];
    if (self) {
        tokens = [NSMutableDictionary dictionary];
    }
    return self;
}

...

#pragma mark NSTokenFieldDelegate methods

- (NSArray *)tokenField:(NSTokenField *)tokenField
completionsForSubstring:(NSString *)substring
           indexOfToken:(NSInteger)tokenIndex
    indexOfSelectedItem:(NSInteger *)selectedIndex
{
    NSLog(@"tokenField:completionsForSubstring:\"%@\" indexOfToken:%ld indexOfSelectedItem:",
          substring, tokenIndex);
    NSMutableArray *result = [NSMutableArray array];
    for (NSString *key in tokens) {
        //NSLog(@"match? \"%@\"", key);
        if ([key hasPrefix:substring])
            [result addObject:key];
    }
    return result;
}

- (id)tokenField:(NSTokenField *)tokenField representedObjectForEditingString:(NSString *)editingString
{
    NSLog(@"tokenField:representedObjectForEditingString:\"%@\"", editingString);
    Token *token;
    if ((token = [tokens objectForKey:editingString]) == nil) {
        token = [[Token alloc] initWithSpelling:editingString];
        [tokens setObject:token forKey:editingString];
        //NSLog(@"token %@", [token description]);
        NSLog(@"tokens %@", [tokens description]);
    }
    return token;
}

- (NSString *)tokenField:(NSTokenField *)tokenField displayStringForRepresentedObject:(id)representedObject
{
    NSString *spelling = [representedObject spelling];
    NSLog(@"tokenField:displayStringForRepresentedObject: = \"%@\"", spelling);
    return spelling;
}

@end

トークンの入力は、改行またはコンマ文字で終了します。

4

2 に答える 2

1

これは間違いなく Apple に報告する必要があるようです。

で編集されたトークンのインデックスを決定するために、NSTokenField最初に のサブクラスを作成しNSTextViewて、カスタム フィールド エディターを用意しました。NSTextView(この方法を使用する場合は、インスタンスを でフィールド エディターに設定することを忘れないでください-[NSTextView setFieldEditor:]。) 次に、 をサブクラス化NSTokenFieldCellし、オーバーライド-[NSCell fieldEditorForView:]します。

  1. NSTextViewサブクラスのインスタンスを作成し、
  2. このNSTextViewインスタンスをselfのデリゲートに設定し、
  3. NSTextViewこのインスタンスを返します。

サブクラスに実装tokenFieldCell:completionsForSubstring:indexOfToken:indexOfSelectedItem:します。NSTextView

- (NSArray *)tokenFieldCell:(NSTokenFieldCell *)tokenFieldCell completionsForSubstring:(NSString *)substring indexOfToken:(NSInteger)tokenIndex indexOfSelectedItem:(NSInteger *)selectedIndex
{
    // The tokenIndex passed to this function seems to be 0 in all cases, so we
    // need to determine the tokenIndex ourselves. The range returned by
    // NSText's selectedRange method treats non-plain-text tokens as if they
    // have unit length. So, for each token, subtract from the range location
    // either the token's length if it's a plain text token, or 1 if it's any
    // other style of token. Each time we subtract from the range location,
    // increment tokenIndex. When the range location becomes less than or equal
    // to 0, tokenIndex will be the index of the edited token.
    tokenIndex = 0;
    NSInteger rangeLocation = self.selectedRange.location;
    for (id token in tokenFieldCell.objectValue) {
        if ([self tokenFieldCell:tokenFieldCell styleForRepresentedObject:token] == NSPlainTextTokenStyle) {
            rangeLocation -= [self tokenFieldCell:tokenFieldCell displayStringForRepresentedObject:token].length;
        } else {
            rangeLocation--;
        }
        if (rangeLocation > 0) {
            tokenIndex++;
        } else {
            break;
        }
    }
}

ここでの考え方は、非プレーンテキスト トークンの長さが 1 であると仮定してselectedRangeanが計算されるという事実を利用することです。位置が負になるまで位置からトークンの長さを引くことで、トークン インデックスを決定できます。NSTextViewselectedRange

これが機能するには、NSTextViewサブクラスも実装する必要があることに注意してください。tokenFieldCell:displayStringForRepresentedObject:tokenFieldCell:styleForRepresentedObject:

于 2012-10-26T22:33:01.907 に答える