【问题标题】:How can I set [NSTextView selectedTextAttributes] on a background window?如何在背景窗口上设置 [NSTextView selectedTextAttributes]?
【发布时间】:2013-04-18 01:52:21
【问题描述】:

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

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

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

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

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

【问题讨论】:

  • 你是否尝试过继承 NSWindow 并覆盖 resignKeyWindow
  • @CodaFi 这种方法我应该怎么做?我刚刚尝试设置 selectedTextAttirbutes 但它没有任何效果。
  • 嗯...检查 NSWindow.h。每当窗口退出/获得关键状态时,您都可以使用大量功能来抓取。您可以从那里分配属性。
  • 如果我在 resignKeyWindow 中更改 selectedTextAttributes.NSForegroundColorAttributeName (以及我尝试过的所有其他地方)它可以工作,但更改 NSBackgroundColorAttributeName 没有效果 - 它必须从其他地方获取颜色。
  • 您是否尝试在窗口的字段编辑器上设置属性(也是NSTextView)? Reference here.

标签: objective-c cocoa nstextview


【解决方案1】:

您可以通过覆盖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 的原因时,我添加了一些更新。

来自苹果手册:

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

这意味着将其他颜色传入super调用没有效果,你只需要 NSColor.setFill 使其与 super 通话一起使用。 另外,手册要求将其设置回原来的。

【讨论】:

  • 只是好奇,为什么要打电话给setFill?我希望将新颜色传递给fillBackgroundRectArray 会正确处理所有事情?
  • @Kyle 我更新了我的答案以提供该信息。评论太长了。
【解决方案2】:

不是当窗口在后台时,而是在未选择 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

【讨论】:

  • 谢谢!我让我的子类覆盖 setSelectedRange: 手动将属性应用于文本存储,然后将 selectedTextAttribtues 设置为空字典,它正在工作。我会在一秒钟内编辑你的答案以获得我使用的代码。
  • 请注意,将属性设置为文本存储意味着您将属性保存为彩色文本的一部分,就像在富文本编辑器中所做的那样。我建议改用 NSLayoutManager 的临时属性,它们针对像这样的瞬态样式。
【解决方案3】:

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

Swift 5.1 中:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-10-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-26
    • 1970-01-01
    • 2011-03-19
    相关资源
    最近更新 更多