10

我创建了一个带有 NSTextView 和一个按钮的简单演示应用程序,为 textView 提供了一个 NSTextViewDelegate 并添加了一个操作:

- (IBAction)actionButtonClicked:(id)sender {
    NSString *oldText = [[[self.textView textStorage] string] copy];
    NSString *newText = @"And... ACTION!";

    [[self.textView undoManager] registerUndoWithTarget:self.textView
                                               selector:@selector(setString:)
                                                 object:oldText];
    [[self.textView undoManager] setActionName:@"ACTION"];

    [self.textView setString:newText];
}

如果我手动更改文本,撤消/重做工作没有问题。但是,如果我使用操作方法更改文本,撤消按预期工作,但重做不再起作用(没有任何反应)并且撤消管理器似乎被打乱了......

好的 - 为了避免 NSTextView 出现问题,我创建了一个模型类,将 NSTextView 绑定到它并将撤消/重做移动到模型,但这显示了与以前相同的行为 - 我做错了什么 - 这应该很容易,不应该吗?

#import "GFTextStore.h"

@implementation GFTextStore

@synthesize textVal = textVal_;

-(void)changeText{
    if (!undoMan_) {
        undoMan_ = [[[NSApplication sharedApplication] mainWindow] undoManager];   
    }

    NSAttributedString *oldText = [self.textVal copy];
    NSString *tempStr = [[oldText string] stringByAppendingFormat:@"\n%@",[[NSCalendarDate date]description]];
    NSAttributedString *newText = [[NSAttributedString alloc] initWithString:tempStr];

    [self setTextVal:newText];


    [undoMan_ registerUndoWithTarget:self
                            selector:@selector(setTextVal:)
                              object:oldText];

    [undoMan_ setActionName:@"ACTION"];
}
@end
4

3 回答 3

16
于 2012-08-01T13:39:57.103 回答
5

-setString:是从 继承的方法NSText。要NSTextView仅使用方法处理此问题以便处理撤消,只需执行以下操作:

[self.textView setSelectedRange:NSMakeRange(0, [[self.textView textStorage] length])];
[self.textView insertText:@"And… ACTION!"];

以这种方式更改文本可以完全避免使用撤消管理器。

于 2011-11-25T00:33:14.087 回答
2

假设您希望您的 NSTextView 在用户按下 Enter 键时创建一个新的撤消组(Apple Pages 行为)。然后你可以在你的 NSTextView 子类中输入这个代码:

override func shouldChangeTextInRange(affectedCharRange: NSRange, replacementString: String?) -> Bool {
    super.shouldChangeTextInRange(affectedCharRange, replacementString: replacementString)
    guard replacementString != nil else { return true }

    let newLineSet = NSCharacterSet.newlineCharacterSet()
    if let newLineRange = replacementString!.rangeOfCharacterFromSet(newLineSet) {

        // check whether it's a single character (user hit Return key)
        let singleCharRange = (replacementString!.startIndex)! ..< (replacementString!.startIndex.successor())!
        if newLineRange == singleCharRange {
            self.breakUndoCoalescing()
        }
    }

    return true
}
于 2016-04-06T10:03:47.107 回答