NSTextView撤消/重做属性更改(当不是第一响应者时)

时间:2015-10-13 15:12:26

标签: macos cocoa nstextview nsundomanager

我正在使用自定义控件构建基本文本编辑器。对于我的文本对齐控件,我需要涵盖两个用户场景:

  1. 文本视图是第一个响应者 - 将段落属性更改为textView.rangesForUserParagraphAttributeChange

  2. 文本视图不是第一个响应者 - 使段落属性更改为全文范围。

  3. 以下是方法:

    - (IBAction)changedTextAlignment:(NSSegmentedControl *)sender
    {
        NSTextAlignment align;
        // ....
    
        NSRange fullRange = NSMakeRange(0, self.textView.textStorage.length);
        NSArray *changeRanges = [self.textView rangesForUserParagraphAttributeChange];
    
        if (![self.mainWindow.firstResponder isEqual:self.textView])
        {
            changeRanges = @[[NSValue valueWithRange:fullRange]];
        }
    
        [self.textView shouldChangeTextInRanges:changeRanges replacementStrings:nil];
        [self.textView.textStorage beginEditing];
    
        for (NSValue *r in changeRanges)
        {
            @try {
                NSDictionary *attrs = [self.textView.textStorage attributesAtIndex:r.rangeValue.location effectiveRange:NULL];
                NSMutableParagraphStyle *pStyle =  [attrs[NSParagraphStyleAttributeName] mutableCopy];
                if (!pStyle)
                    pStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
    
                [pStyle setAlignment:align];
                [self.textView.textStorage addAttributes:@{NSParagraphStyleAttributeName: pStyle}
                                                 range:r.rangeValue];
            }
            @catch (NSException *exception) {
                NSLog(@"%@", exception);
            }
        }
    
        [self.textView.textStorage endEditing];
        [self.textView didChangeText];
    
        // ....
    
        NSMutableDictionary *typingAttrs = [self.textView.typingAttributes mutableCopy];
        NSMutableParagraphStyle *pStyle =  typingAttrs[NSParagraphStyleAttributeName];
        if (!pStyle)
            pStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
        [pStyle setAlignment:align];
        [typingAttrs setObject:NSParagraphStyleAttributeName forKey:pStyle];
        self.textView.typingAttributes = typingAttrs;
    
    }
    

    因此两种情况都可以正常工作......但是当在“非首先响应者”场景中应用更改时,撤消/重做不起作用。撤消管理器将某些内容推送到其堆栈(即“编辑”菜单中的“撤消”),但调用撤消不会更改文本。它所做的就是明显选择全文范围。

    如何正确更改文本视图属性,以便无论视图是否是第一个应答器,撤消/重做都能正常工作?

    提前谢谢!

2 个答案:

答案 0 :(得分:0)

我不确定,但我有两个建议。一,检查shouldChangeTextInRanges:...的返回值,因为文本系统可能拒绝你提议的更改;无论如何都是一个好主意。第二,我会尝试让非第一响应者案例更像第一响应者案例,以便尝试让它发挥作用;特别是,您可以从选择整个范围开始,这样rangesForUserParagraphAttributeChange实际上就是您更改属性的范围。朝这个方向迈出的另一步是实际上暂时使textview成为你改变期间的第一个响应者。在这种情况下,我认为这两个案件应该完全相同。您可以在完成后立即恢复第一响应者。不是最佳的,但似乎AppKit正在幕后制作一些你可能只需要解决的假设。没有尝试重现问题并玩它,这是我能提供的最好的......

答案 1 :(得分:0)

这个问题是我之后在更新typingAttributes的代码中输入的错误。看这里:

//...

NSMutableParagraphStyle *pStyle =  typingAttrs[NSParagraphStyleAttributeName];

// ...

卫生署!需要变得非常可变......

//...

NSMutableParagraphStyle *pStyle =  [typingAttrs[NSParagraphStyleAttributeName] mutableCopy];

// ...