Cocoa Text - 即时刷新文本

时间:2011-06-25 05:41:47

标签: cocoa nstextview core-text

在我正在处理的应用程序中,用户输入纯文本,应用程序通过将文本转换为NSAttributedString来重新格式化文本,并显示它。这一切都在现场发生。

目前,我在NSTextView的textDidChange委托方法上执行以下操作:

- (void)textDidChange:(NSNotification *)notification {

    // saving the cursor position
    NSInteger insertionPoint = [[[self.mainTextView selectedRanges] objectAtIndex:0] rangeValue].location;

    // this grabs the text view's contact as plain text
    [self updateContentFromTextView];

    // this creates an attributed strings and displays it
    [self updateTextViewFromContent];

    // resetting the cursor position
    self.mainTextView.selectedRange = NSMakeRange(insertionPoint, 0);
}

虽然这种方法很有效,但并不理想。文本似乎瞬间闪烁(你特别注意拼写错误下的红点),当光标先前接近可见矩形的一个边缘时,滚动位置会重置。就我而言,这是一个非常不良的副作用。

所以我的问题是:有没有更好的方法来做我想做的事情?

1 个答案:

答案 0 :(得分:5)

我认为你对NSTextView如何运作有一点误解。用户永远不会输入“普通字符串”,NSTextView的数据存储总是一个NSTextStorage对象,它是NSMutableAttributedString的子类。

您需要做的是为用户正在编辑的现有属性字符串添加/删除属性,而不是替换整个字符串。

您也不应对‑textDidChange:委托方法中的字符串进行更改,因为从该方法更改字符串可能会导致另一个更改通知。

相反,您应该实现委托方法‑textStorageDidProcessEditing:。每当文本更改时都会调用此方法。然后,您可以像这样修改字符串:

- (void)textStorageDidProcessEditing:(NSNotification*)notification
{
    //get the text storage object from the notification
    NSTextStorage* textStorage = [notification object];

    //get the range of the entire run of text
    NSRange aRange = NSMakeRange(0, [textStorage length]);

    //for example purposes, change all the text to yellow

    //remove existing coloring
    [textStorage removeAttribute:NSForegroundColorAttributeName range:aRange];

    //add new coloring
    [textStorage addAttribute:NSForegroundColorAttributeName 
                        value:[NSColor yellowColor] 
                        range:aRange];
}