如何实现撤消/重做与NSTextView的textValue的程序化更改? [英] How to implement undo/redo with programatic change of the textValue of a NSTextView?

查看:487
本文介绍了如何实现撤消/重做与NSTextView的textValue的程序化更改?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I created a simple demo app with a NSTextView and a button, the provided a NSTextViewDelegate to the textView and added an action:

- (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];
}

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

Undo/redo works without problems, if I change text by hand. But if I change the text with the action method, undo works as expected, but redo does not work anymore (nothing happens) and the undo manager seems to be scrambled...

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

OK - to avoid problems with NSTextView I created a model class, bound the NSTextView to it and moved the undo/redo to the model, but this shows the same behavior as before - what the I'm doing wrong - this should be easy, shouldn't it?

#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


推荐答案

不需要在这里添加NSUndoManager,只是让NSTextView做这项工作。

No need to add the NSUndoManager here, just let the NSTextView do the job.

你只需要确保你只调用更高级的方法的NSTextView以 insert ... 开头,而不是直接设置textView或textStorage的文本/字符串:

You just need to make sure you are calling the higher level methods only of NSTextView beginning with insert… and not setting the text/string of the textView or the textStorage directly:

    [self.textView insertText:newString];

如果你绝对需要使用setString或其他较低级别的方法,那么你只需要添加处理textDidChange委托的方法: -shouldChangeTextInRange:replacementString -didChangeText (这是通过插入...方法btw完成的):

If you absolutely need to use setString or other lower level methods, then you just need to add the required methods handling the textDidChange delegation: -shouldChangeTextInRange:replacementString and -didChangeText (which is done by the insert... methods btw):

if( [self.textView shouldChangeTextInRange:editedRange replacementString:editedString]) {
    // do some fancy stuff here…
    [self.textView.textStorage replaceCharactersInRange:editedRange
                          withAttributedString:myFancyNewString];
    // … and finish the editing with
    [self.textView didChangeText];
}

这会自动允许NSTextView的undoManager进入。我认为undoManager正在准备undoGrouping in shouldChangeTextInRange:并调用didChangeText中的撤消:

This automatically lets the undoManager of NSTextView kick in. I think the undoManager is preparing an undoGrouping in shouldChangeTextInRange: and invoking the undo in didChangeText:.

这篇关于如何实现撤消/重做与NSTextView的textValue的程序化更改?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆