我编写了一个NSTextView子类,该子类对其内部的文本进行了频繁的编程修改(有点像IDE的代码格式-例如,自动插入小括号)。

我最初的实现是使用NSTextView的insertText:。这实际上似乎完全正常。但是当我阅读NSTextView documentation时(有时我会很有趣),我在Discussion section for insertText: 中注意到了



哦,我不好,我想。因此,我尽职尽责地将所有我的insertText调用更改为对基础NSTextStorage的调用(主要是replaceCharactersInRange:withString:)。看来一切正常,直到我注意到它完全搞定了撤消(当然,因为撤消是由NSTextView而不是NSTextStorage处理的)。

因此,在我将大量的撤消代码放到文本存储中之前,我想知道是否我被朋克了,而且insertText:真的还不错吗?

是的,所以我的问题是:NSTextView的insertText:调用真的“不适合”以编程方式修改NSTextView的文本吗?如果可以,为什么?

最佳答案

insertText:NSResponder的一种方法-通常将它们视为响应用户事件的方法。在某种程度上,它们暗示着“用户行为”。当文档告诉您如果要以编程方式进行更改时直接编辑NSTextStorage时,将使用“以编程方式”一词来区分用户意图和应用程序操作。如果您希望所做的更改像用户操作一样不可撤消,那么insertText:似乎可以使用。也就是说,在大多数情况下,如果修改不是由用户操作发起的,则用户不会将其视为不可撤消的操作,而将其设为不可撤消操作的单位将导致困惑。

例如,假设我在您的文本 View 中粘贴了一个单词“foo”,然后您的应用程序将该单词涂成红色(无论出于何种原因)。如果然后选择“撤消”,则我希望我的操作是未完成的事情,而不是着色。颜色不是我的用户意图的一部分。如果然后我不得不再次按下Cmd-Z才能真正取消我的操作,那我就在想,“WTF?”
NSUndoManager支持通过beginUndoGroupingendUndoGrouping对事件进行分组。这可以允许将用户意图的单位(粘贴操作)与应用程序着色一起分组为单个“撤消”单位。在最简单的情况下,您可能想在这里尝试的是将groupsByEvent上的NSUndoManager设置为YES,然后找到一种方法来触发应用程序的操作在与用户操作相同的runLoop传递中发生。这将导致NSUndoManager自动将它们分组。

除此之外,例如,如果您的程序化修改需要异步进行或以某种方式进行,则需要以某种方式自己管理这些分组,但这可能很容易实现。

关于macos - macos-是NSTextView的insertText : *really* not suitable for programmatic modification of text?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/14722223/

10-13 07:37