7

私は NSTextView サブクラスを作成しました。このサブクラスは、テキスト自体をプログラムで頻繁に変更します (たとえば、IDE のコードの書式設定のようなものです - 右中括弧の自動挿入など)。

これの私の最初の実装では、NSTextView のinsertText:. これは実際には完全にうまく機能しているように見えました。しかし、 NSTextView のドキュメントを読んでいるときに (私は時々楽しみのために行っています)、ディスカッション セクションで次のことに気付きました。insertText:

このメソッドは、ユーザーが入力したテキストを挿入するためのエントリ ポイントであり、通常、他の目的には適していません。プログラムによるテキストの変更は、テキスト ストレージを直接操作することによって行うのが最適です。

ああ、悪い、私は思った。そのため、すべての insertText 呼び出しを基になる NSTextStorage ( replaceCharactersInRange:withString:、ほとんど) への呼び出しに変更することに忠実に取り組みました。元に戻すを完全に台無しにすることに気付くまで、それは問題なく機能しているように見えました(もちろん、元に戻すはNSTextStorageではなくNSTextViewによって処理されるためです)。

だから、私が引っ張り出してテキストストレージに大量の元に戻すコードを入れる前に、おそらく私はパンクされたのではないかと思いますが、本当にinsertText:それほど悪くはありませんか?

そうですね、私の質問は次のとおりです。NSTextView のinsertText:呼び出しは、NSTextView のテキストをプログラムで変更するのに本当に「適していない」のでしょうか。

4

3 に答える 3

5

insertText:のメソッドですNSResponder-- 一般に、これらはユーザー イベントに応答するメソッドと見なされます。ある程度、それらは「ユーザー アクション」を意味します。プログラムで変更したい場合は直接編集するようにドキュメントに記載されているNSTextStorage場合、「プログラムで」という言葉は、ユーザーの意図とアプリケーションの操作を区別するために使用されています。ユーザー アクションであるかのように、変更を元に戻すinsertText:ことができるようにしたい場合は、使用しても問題ないように思われます。とはいえ、ほとんどの場合、変更がユーザーの操作によって開始されたものではない場合、ユーザーはそれを元に戻すことができる操作とは見なさず、元に戻すことができる操作の単位にすることは混乱を招きます。

たとえば、「foo」という単語をテキスト ビューに貼り付けると、アプリケーションがその単語を (何らかの理由で) 赤く着色したとします。次に元に戻すを選択すると、色付けではなく、元に戻す操作が実行されると思います。色付けはユーザーの意図の一部ではありません。その後、実際にアクションを元に戻すために Cmd-Z をもう一度押す必要がある場合、「なんてことだろう?」と考えてしまいます。

NSUndoManagerbeginUndoGroupingは、 およびを介したイベントのグループ化をサポートしていますendUndoGrouping。これにより、ユーザー インテントの単位 (貼り付け操作) を、アプリケーションの色付けとグループ化して、取り消しの単一の "単位" にすることができます。最も単純なケースでは、ここで試してみたいことは、groupsByEventonNSUndoManagerを YES に設定してから、ユーザー アクションと同じ runLoop のパスでアプリケーションのアクションをトリガーする方法を見つけることです。これによりNSUndoManager、それらが自動的にグループ化されます。

それを超えて、たとえば、プログラムによる変更を非同期に行う必要がある場合など、これらのグループ化を自分で管理する必要がありますが、それを実装するのは簡単ではありません。

于 2013-02-06T13:28:27.137 に答える
1

この質問を投稿してから、元の実装を進めましたが、うまく機能しているようです。したがって、この質問に対する答えは次のとおりだと思います。

insertText:この特定のユース ケースでは、プログラムによるテキストの変更に完全に適しています。

このメモは、テキストビューのすべてのテキストを設定するなど、テキストの純粋なプログラムによる変更を指していると思います。insertText:それがそれにふさわしくないことは間違いなくわかりました。ただし、ユーザーのアクションに直接応答して文字を追加または編集することは、私の意図した目的にとってinsertText:は完全に適切です。

(@ipmcc が彼の回答で言及しているように) テキスト変更をトリガーしたユーザー インタラクションでアトミックにするために、insertText:オーバーライドで独自の取り消し処理を行います。これについては、 @pjv の同様の質問に書きました。githubにもサンプル プロジェクトがあり、いつかブログに書きます。

于 2013-05-26T05:02:47.357 に答える