12

デリゲートとして機能するNSTextViewサブクラスがあります。NSTextStorage私は2つのことをしようとしています:

  1. いくつかの方法でテキストを強調表示する
  2. テキストを評価し、回答をテキストビューに追加します。

私はこれを 2 つの異なるメソッドで実行しています。どちらも- (void)textStorageWillProcessEditing:(NSNotification *)notificationデリゲート コールバックによって呼び出されます。

構文の強調表示は問題なく実行できますが、回答を追加すると、挿入ポイントが行末にジャンプしてしまい、その理由がよくわかりません。私の評価方法は次のようになります。

NSString *result = ..;
NSRange lineRange = [[textStorage string] lineRangeForRange:[self selectedRange]];
NSString *line = [[textStorage string] substringWithRange:lineRange];
line = [self appendResult:result toLine:line]; // appends the answer

[textStorage replaceCharactersInRange:lineRange withString:line];

そうすることで結果がうまく追加されますが、問題は、前述のように、挿入ポイントが最後にジャンプすることです。

私はもう試した:

  1. 上記の呼び出しを と でラップし[textStorage beginEditing]ます-endEditing
  2. テキストストレージを変更する前に選択範囲(つまり、挿入ポイント)を保存して、後でリセットできるようにしますが、サイコロはありません。

私はこれを正しく行っていますか?私はこれを最もハックな方法でやろうとしていますが、これが私の解析/強調表示を行うのに理想的な場所であるかどうかもわかりません. ドキュメントは私にこれを信じさせますが、おそらくそれは間違っています。

4

3 に答える 3

5

挿入ポイントが移動する理由

驚いたことに、これらの提案が機能する (または機能しない) 理由についての実際の説明は見つかりませんでした。

掘り下げてみると、挿入ポイントが移動する理由は次のとおり.editedCharactersです。NSTextStorageEditedCharactersNSLayoutManager.processEditing(from:editedMask:...)

.editedAttributes/のみNSTextStorageEditedAttributesを送信すると、挿入ポイントはタッチされません。これは、強調表示するときに達成したいことです: 属性のみを変更します。

ハイライトが挿入ポイントに影響する理由

ここでの強調表示の問題は、単一の処理実行中にNSTextStorageすべての呼び出しを収集editedし、ユーザーが編集した変更 (入力時の挿入など) から開始して範囲を結合し、これと によって報告されたすべての範囲の和集合を形成することaddAttributes(_:range:)です。これにより、両方の を使用して 1 つのNSLayoutManager.processEditing(from:editedMask:...)呼び出しが行われます。editedMask[.editedCharacters, .editedAttributes]

したがって、強調表示された範囲を送信したいのですが、代わりに.editedAttributesユニオンを形成することになります。.editedCharactersその共用体は、挿入ポイント waaaaaaaay を本来あるべき場所を超えて移動します。

processEditingスーパー ファーストを呼び出すように順序を変更すると、レイアウト マネージャーに編集の完了が通知されるため、機能します。しかし、このアプローチは、非常に大きな段落を入力しているときに、レイアウトが無効になったり、スクロール ビューが揺れたりするという特殊なケースではうまくいかないことがあります。

ちなみに、これは へのフックにも当てはまりますNSTextStorageDelegate

レイアウトが完全に終了した後にコールバックにフックして、代わりに強調表示をトリガーします。processEditing

Cocoa フレームワークに固有の理由に基づいて確実に機能する唯一の解決策はtextDidChange(_:)、レイアウト処理が実際に終了した後に、排他的に強調表示を実行することです。同様に仕事にサブスクライブしNSTextDidChangeNotificationます。

欠点: 基になる文字列をプログラムで変更するには、ハイライト パスをトリガーする必要があります。これらはtextDidChange(_:)コールバックを呼び出さないためです。


問題の原因について詳しく知りたい場合は、私の研究、さまざまなアプローチ、およびソリューションの詳細を、参照用のはるかに長いブログ投稿に掲載します. この投稿は、それ自体が自己完結型のソリューションです

于 2017-11-30T08:56:14.987 に答える
0

それは簡単です!私はこの問題を2つの部分に分けました。textStorageデリゲート コールバックの結果として構文の強調表示は引き続き行いますが、別の場所で評価と追加を行うようになりました。

-insertText:と の両方をオーバーライド-deleteBackwards:することになりました ( についても同じことをしたいかもしれませ-deleteForwards:ん)。どちらのオーバーライドも次のようになります。

- (void)insertText:(id)insertString {
    [super insertText:insertString];
    NSRange selectedRange = [self selectedRange];
    [self doEvaluationAndAppendResult];
    [self setSelectedRange:selectedRange];
}

ここで挿入ポイントを手動でリセットする必要がありました。なぜそれが必要なのかを理解したいと思っていますが、少なくともこれはハックではないように感じます.

于 2012-08-28T12:45:51.090 に答える