8

的默认值[NSTextView selectedTextAttributes]在我的应用程序中不可用,因为我允许用户选择与背景颜色几乎完全相同的颜色(语法突出显示)。

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

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

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

我附上了上述代码的屏幕截图,其中包含活动窗口和非活动窗口。— 如何更改非活动窗口的选定文本背景颜色?

积极的 不活跃

4

3 回答 3

11

您可以通过覆盖 的绘图方法来覆盖颜色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)

这是完整的工作示例


正如@Kyle 询问原因setFill,我添加了一些更新。

来自苹果手册:

... charRange 和 color 参数仅用于提供信息;颜色已经设置在图形状态。如果出于任何原因修改它,则必须在从此方法返回之前恢复它。...

这意味着将其他颜色传入supercall 无效,您只需要 NSColor.setFill使其与supercall 一起工作。此外,手册要求将其设置回原始版本。

于 2016-01-03T15:49:33.857 回答
5

不是当窗口在后台时,而是在未选择 NSTextView 时。我不认为你可以改变这种行为。 在此处输入图像描述

您可以创建一个属性字符串并将 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];

在此处输入图像描述

由 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
于 2013-05-11T02:33:15.127 回答
0

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

Swift 5.1中将是:

override func layoutManagerOwnsFirstResponder(in window: NSWindow) -> Bool {
    true
}
于 2019-11-20T09:35:03.790 回答