删除 NSTextView 文本选择的属性
Removing an Attribute of NSTextView Text Selection
我有一个通过界面生成器添加的 NSTextView 对象。我可以按如下方式更改所选文本段的背景颜色。
- (void)emphasizeText {
NSColor *c = [colorWell.color colorUsingColorSpaceName:NSCalibratedRGBColorSpace]; //colorWell is an NSColorWell object that has been added through interface builder
NSRange selection = textView1.selectedRange; //textView1 is an NSTextView object that has been added through interface builder
[textView1.textStorage addAttributes:@{NSBackgroundColorAttributeName:c} range:selection];
}
但是,我无法从所选文本段中删除添加的属性 (NSBackgroundColorAttributeName)。参考this topic,我有以下代码。
- (void)deemphasizeText {
NSMutableAttributedString *aStr = [textView1.attributedString mutableCopy];
NSRange selection = textView1.selectedRange;
[aStr enumerateAttribute:NSBackgroundColorAttributeName inRange:selection options:0 usingBlock:^(id value,NSRange range,BOOL *stop) {
if (value) {
[aStr removeAttribute:NSBackgroundColorAttributeName range:range];
}
}];
}
虽然应用程序不会崩溃,但没有任何变化。我做了几个变体,比如
- (void)deemphasizeText {
NSRange selection = textView1.selectedRange;
NSMutableAttributedString *aStr = [[NSMutableAttributedString alloc] initWithAttributedString:(NSMutableAttributedString *)[textView1.textStorage attributedSubstringFromRange:selection]];
[aStr enumerateAttribute:NSBackgroundColorAttributeName inRange:NSMakeRange(0,aStr.length) options:0 usingBlock:^(id value,NSRange range,BOOL *stop) {
if (value) {
[aStr removeAttribute:NSBackgroundColorAttributeName range:range];
}
}];
}
再次选择的细分没有改变。我做错了什么?
非常感谢。
首先,您的 -deemphasizeText
方法明确地使用文本存储可变字符串的副本。人们不会期望修改该副本来修改原始文件。
其次,您应该将对文本存储的所有修改都包含在对 -beginEditing
和 -endEditing
的调用中。事实上,你真的应该在文本视图上围绕更改调用 -shouldChangeTextInRange:replacementString:
和 -didChangeText
。
最后,无需枚举属性字符串并仅从其存在的范围中删除属性。只需删除整个选择范围的属性。
所以:
- (void)emphasizeText {
NSColor *c = [colorWell.color colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
NSRange selection = textView1.selectedRange;
if ([textView1 shouldChangeTextInRange:selection replacementString:nil])
{
NSTextStorage* storage = textView1.textStorage;
[storage beginEditing];
[storage addAttributes:@{NSBackgroundColorAttributeName:c} range:selection];
[storage endEditing];
[textView1 didChangeText];
}
}
- (void)deemphasizeText {
NSRange selection = textView1.selectedRange;
if ([textView1 shouldChangeTextInRange:selection replacementString:nil])
{
NSTextStorage* storage = textView1.textStorage;
[storage beginEditing];
[storage removeAttribute:NSBackgroundColorAttributeName range:selection];
[storage endEditing];
[textView1 didChangeText];
}
}
其他需要考虑的事项:
- 正在调整选择范围以适合您正在进行的修改。调用
-rangeForUserCharacterAttributeChange
;检查它的位置是否为 NSNotFound
,如果是则中止;检查它是否与当前的 selectedRange
不同,如果不同,则将 selectedRange
设置为匹配;然后在该范围内操作。
- 使用
-rangesForUserCharacterAttributeChange
和-shouldChangeTextInRanges:replacementStrings:
支持多个选择范围。
我有一个通过界面生成器添加的 NSTextView 对象。我可以按如下方式更改所选文本段的背景颜色。
- (void)emphasizeText {
NSColor *c = [colorWell.color colorUsingColorSpaceName:NSCalibratedRGBColorSpace]; //colorWell is an NSColorWell object that has been added through interface builder
NSRange selection = textView1.selectedRange; //textView1 is an NSTextView object that has been added through interface builder
[textView1.textStorage addAttributes:@{NSBackgroundColorAttributeName:c} range:selection];
}
但是,我无法从所选文本段中删除添加的属性 (NSBackgroundColorAttributeName)。参考this topic,我有以下代码。
- (void)deemphasizeText {
NSMutableAttributedString *aStr = [textView1.attributedString mutableCopy];
NSRange selection = textView1.selectedRange;
[aStr enumerateAttribute:NSBackgroundColorAttributeName inRange:selection options:0 usingBlock:^(id value,NSRange range,BOOL *stop) {
if (value) {
[aStr removeAttribute:NSBackgroundColorAttributeName range:range];
}
}];
}
虽然应用程序不会崩溃,但没有任何变化。我做了几个变体,比如
- (void)deemphasizeText {
NSRange selection = textView1.selectedRange;
NSMutableAttributedString *aStr = [[NSMutableAttributedString alloc] initWithAttributedString:(NSMutableAttributedString *)[textView1.textStorage attributedSubstringFromRange:selection]];
[aStr enumerateAttribute:NSBackgroundColorAttributeName inRange:NSMakeRange(0,aStr.length) options:0 usingBlock:^(id value,NSRange range,BOOL *stop) {
if (value) {
[aStr removeAttribute:NSBackgroundColorAttributeName range:range];
}
}];
}
再次选择的细分没有改变。我做错了什么?
非常感谢。
首先,您的 -deemphasizeText
方法明确地使用文本存储可变字符串的副本。人们不会期望修改该副本来修改原始文件。
其次,您应该将对文本存储的所有修改都包含在对 -beginEditing
和 -endEditing
的调用中。事实上,你真的应该在文本视图上围绕更改调用 -shouldChangeTextInRange:replacementString:
和 -didChangeText
。
最后,无需枚举属性字符串并仅从其存在的范围中删除属性。只需删除整个选择范围的属性。
所以:
- (void)emphasizeText {
NSColor *c = [colorWell.color colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
NSRange selection = textView1.selectedRange;
if ([textView1 shouldChangeTextInRange:selection replacementString:nil])
{
NSTextStorage* storage = textView1.textStorage;
[storage beginEditing];
[storage addAttributes:@{NSBackgroundColorAttributeName:c} range:selection];
[storage endEditing];
[textView1 didChangeText];
}
}
- (void)deemphasizeText {
NSRange selection = textView1.selectedRange;
if ([textView1 shouldChangeTextInRange:selection replacementString:nil])
{
NSTextStorage* storage = textView1.textStorage;
[storage beginEditing];
[storage removeAttribute:NSBackgroundColorAttributeName range:selection];
[storage endEditing];
[textView1 didChangeText];
}
}
其他需要考虑的事项:
- 正在调整选择范围以适合您正在进行的修改。调用
-rangeForUserCharacterAttributeChange
;检查它的位置是否为NSNotFound
,如果是则中止;检查它是否与当前的selectedRange
不同,如果不同,则将selectedRange
设置为匹配;然后在该范围内操作。 - 使用
-rangesForUserCharacterAttributeChange
和-shouldChangeTextInRanges:replacementStrings:
支持多个选择范围。