1

一連のタイプライターページのように動作するNSTextViewを作成しようとしています。各ページには、使用可能な行と列の数が固定されています。

基になる表現は理想的にはディスプレイと一致し、ディスプレイはファイル形式と一致します。ページはフォームフィード文字で終わり'\f'ます。たとえば、2つの4x4ページを保存すると、次のようになります(読みやすくするために文字間のスペース)。

T  H  I  S  \n
P  A  G  E  \n
I  S  \n
F  U  L  L  \n
\f
N  O  T  \n
T  H  I  S  \n
O  N  E  \n
\n
\f

注意すべき点がいくつかあります。

  • 改行とフォームフィードは行/列の合計にカウントされません
  • 列数より短い行には、末尾の空白が埋め込まれません(ただし、エディターが上書きモードで動作している場合は空白が埋め込まれる可能性があります)。
  • 行数より短いページには改行が埋め込まれます

NSArrayテキストを行に変換し、通知ごとに長い行を分割してから、テキストを連結行に設定するなど、いくつかのアプローチを試しましたが、textDidChange実際には非効率的であり、入力が終了以外の場所で行われるとカーソル位置が失われます。資料。

結局、これを空白で埋められた大きなページとして動作させたいと思います。入力は上書きモードでのみ行われ、行の終わりで折り返されます。そのアプローチをどこから始めればよいのかわかりません。助言がありますか?

4

1 に答える 1

0

サブクラス化によるラッピングの完全ではないにしても、許容できる解決策を見つけましたNSTextStorage

貼り付けでも入力でも、ドキュメントの最後にテキストを追加すると、完全に期待どおりに動作します。また、テキストを削除または置換するときにも動作します。少し奇妙なのは、すでにいっぱいになっている行の途中にテキストを挿入するときだけです。これにより、挿入されたテキストの直前で折り返しが発生します。正常に機能しますが、その位置で入力を続けると、多数の短い行が作成されることを意味します。

たとえば、以下のテキストは20列で折り返されます。元のテキストはx、、挿入されたテキストはoです。挿入されたテキストは、2行目の8文字目から始まります。

xxxxxxxxxxxxxxxxxxxx
xxxxxxx
ooooooo
ooooooo
oooooooxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxx

以下のコード:

- (void)breakLinesInArray:(NSMutableArray *)lines atLength:(NSUInteger)length
charsPreceding:(NSUInteger)preceding charsFollowing:(NSUInteger)following
{
    NSUInteger line = 0;
    while (line < [lines count]) {
        NSUInteger maxLineLength = length;
        if (line == 0) {
            maxLineLength = length - preceding;
        } else if (line == [lines count] - 1) {
            maxLineLength = length - following;
        }
        NSString *original = [lines objectAtIndex:line];
        if (maxLineLength > 0 && [original length] > maxLineLength) {
            NSString *first = [original substringToIndex:maxLineLength];
            NSString *second = [original substringFromIndex:maxLineLength];
            [lines replaceObjectAtIndex:line withObject:first];
            [lines insertObject:second atIndex:line + 1];
        }
        ++line;
    }
}

- (void)replaceCharactersInRange:(NSRange)range withString:(NSString *)str
{
    static const NSUInteger kMaxLineLength = 20;
    NSString *text = [text_ string];
    NSUInteger firstLineStart = 0;
    NSUInteger lastLineEnd = 0;
    NSMutableArray *lines = [NSMutableArray arrayWithArray:[str componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]]];
    [text getLineStart:&firstLineStart end:nil contentsEnd:&lastLineEnd forRange:range];
    NSUInteger firstLineStartFragmentLength = range.location - firstLineStart;
    NSUInteger lastLineEndFragmentLength = lastLineEnd - (range.location + range.length);
    [self breakLinesInArray:lines atLength:kMaxLineLength charsPreceding:firstLineStartFragmentLength charsFollowing:lastLineEndFragmentLength];
    NSString *newString = [lines componentsJoinedByString:@"\n"];
    NSInteger changeInLength = [newString length] - range.length;
    NSInteger newLastLineLength = firstLineStartFragmentLength + lastLineEndFragmentLength + changeInLength;
    if ((firstLineStartFragmentLength || lastLineEndFragmentLength) && newLastLineLength > (NSInteger)kMaxLineLength) {
        newString = [@"\n" stringByAppendingString:newString];
        ++changeInLength;
    }
    [text_ replaceCharactersInRange:range withString:newString];
    [self edited:NSTextStorageEditedCharacters range:range changeInLength:changeInLength];
}
于 2012-06-16T01:02:46.397 に答える