如何在后台窗口中设置[NSTextView selectedTextAttributes]?

时间:2013-04-18 01:52:22

标签: objective-c cocoa nstextview

[NSTextView selectedTextAttributes]的默认值在我的应用中无法使用,因为我允许用户选择几乎与背景颜色完全相同的颜色(语法高亮显示)。

我已经写了一些数学来确定合适的颜色,可以用它来设置它:

textView.selectedTextAttributes = @{
  NSBackgroundColorAttributeName: [NSColor yellowColor],
  NSForegroundColorAttributeName: [NSColor redColor]
  };

但是当窗口在后台时,它仍然使用系统默认的浅灰色。

我在活动与非活动窗口中附加了上述代码的屏幕截图。 - 如何更改非活动窗口的选定文本背景颜色?

active inactive

3 个答案:

答案 0 :(得分:10)

您可以通过覆盖NSLayoutManager的绘图方法来覆盖颜色。

final class LayoutManager1: NSLayoutManager {
    override func fillBackgroundRectArray(rectArray: UnsafePointer<NSRect>, count rectCount: Int, forCharacterRange charRange: NSRange, color: NSColor) {
        let color1 = color == NSColor.secondarySelectedControlColor() ? NSColor.redColor() : color
        color1.setFill()
        super.fillBackgroundRectArray(rectArray, count: rectCount, forCharacterRange: charRange, color: color1)
        color.setFill()
    }
}

NSTextView的布局管理器替换为它。

textView.textContainer!.replaceLayoutManager(layoutManager1)

这是full working example

当@Kyle询问setFill的原因时,我添加了一些更新。

来自Apple手册:

  

... charRange和颜色参数仅用于提供信息;颜色是   已设置为图形状态。如果由于任何原因您修改它,您必须先恢复它   从这个方法返回。 ...

这意味着将其他颜色传入super调用无效,您只需要 NSColor.setFill使其与super电话合作。 此外,手册需要将其设置回原始版本。

答案 1 :(得分:5)

当窗口处于后台时,不是在未选择NSTextView时。我认为你不能改变这种行为。 enter image description here

您可以创建一个属性字符串,并在失去焦点时将NSBackgroundColorAttributeName属性添加到所选文本的范围内。即使焦点丢失,属性字符串也会保持相同的颜色。

NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:@"hello world"];
[string addAttribute:NSForegroundColorAttributeName value:[NSColor redColor] range:NSMakeRange(1, 7)];
[string addAttribute:NSBackgroundColorAttributeName value:[NSColor yellowColor] range:NSMakeRange(1, 7)];
[self.myTextView insertText:string];

enter image description here

编辑Abhi Beckert:这就是我实现这个答案的方法(注意我还必须禁用内置的选定文本属性,否则它们会覆盖我正在设置的那些):

@implementation MyTextView

- (id)initWithCoder:(NSCoder *)aDecoder
{
  if (!(self = [super initWithCoder:aDecoder]))
    return nil;

  // disable built in selected text attributes
  self.selectedTextAttributes = @{};

  return self;
}

- (id)initWithFrame:(NSRect)frameRect textContainer:(NSTextContainer *)container
{
  if (!(self = [super initWithFrame:frameRect textContainer:container]))
    return nil;

  // disable built in selected text attributes
  self.selectedTextAttributes = @{};

  return self;
}

- (void)setSelectedRanges:(NSArray *)ranges affinity:(NSSelectionAffinity)affinity stillSelecting:(BOOL)stillSelectingFlag
{
  // remove from old ranges
  for (NSValue *value in self.selectedRanges) {
    if (value.rangeValue.length == 0)
      continue;

    [self.textStorage removeAttribute:NSBackgroundColorAttributeName range:value.rangeValue];
  }

  // apply to new ranges
  for (NSValue *value in ranges) {
    if (value.rangeValue.length == 0)
      continue;

    [self.textStorage addAttribute:NSBackgroundColorAttributeName value:[NSColor yellowColor] range:value.rangeValue];
  }

  [super setSelectedRanges:ranges affinity:affinity stillSelecting:stillSelectingFlag];
}

@end

答案 2 :(得分:0)

您可以通过从layoutManagerOwnsFirstResponder(in:)覆盖NSLayoutManager来指定将NSTextView视为第一响应者,并且选择将使用您定义的属性。

Swift 5.1 中,将是:

override func layoutManagerOwnsFirstResponder(in window: NSWindow) -> Bool {
    true
}