Wesley McCloy
Wesley McCloy

Reputation: 465

NSTextField font styling resets when selected

Context:

In Interface Builder I have a non-editable label (NSTextField). The contents of the label is created using Cocoa Bindings. The value of the binding is an NSAttributedString (created using a talue transformer). See image:

Binding

The value transformer essentially specifies the font for specific characters, as per Markdown formatting (i.e. Italic and Bold). Such that String --> NSAttributedString. The label's attributedStringValue is changed appropriately

Issue:

When selecting the label in the UI. The font resets to what is specified in IB, and not what was set as the NSAttributedString. If you don't select the text then everything looks good.

Before clicking on the label:

enter image description here

After clicking/selected the label:

enter image description here

Attempted Solutions:

Upvotes: 3

Views: 1388

Answers (3)

Sean Mayes
Sean Mayes

Reputation: 168

Swift 5 solution

First you need to set this property for your NSTextField

cell.textField?.allowsEditingTextAttributes = true

Then, where you are creating the NSAttributedString, do this first

// Default font and color, to be used where no attritubes are set
let default_font = NSFont(name: "Courier New", size: 14)
let default_color = NSColor.white
let entire_str_range = NSMakeRange(0, text.string.count)

mutable_attr_str.removeAttribute(NSAttributedString.Key.font, range: entire_str_range)
mutable_attr_str.addAttribute(NSAttributedString.Key.font, value: default_font!, range: entire_str_range)

mutable_attr_str.removeAttribute(NSAttributedString.Key.foregroundColor, range: entire_str_range)
mutable_attr_str.addAttribute(NSAttributedString.Key.foregroundColor, value: default_color, range: entire_str_range)

mutable_attr_str.removeAttribute(NSAttributedString.Key(rawValue: "NSOriginalFont"), range: entire_str_range)
mutable_attr_str.addAttribute(NSAttributedString.Key(rawValue: "NSOriginalFont"), value: default_font!, range: entire_str_range)

Then set up your NSAttributedString however you like. When clicked, it should keep your additional attributes, and the parts of the string with no attributes will default to the above font and color.

Upvotes: 0

Mark Coniglio
Mark Coniglio

Reputation: 401

I believe I found the solution to this issue, which seems unsolved based on the original poster's comments above.

I had an NSTextField that was selectable but not editable. The text was set by creating NSAttributedString with font and text color attributes, and passing this to the NSTextField's setAttributedStringValue method.

The problem as that the line spacing of the text was wrong until I clicked a text field and then clicked a different text field, as shown in the GIF below. Once the clicking was done, the text displayed properly.

enter demonstration of the problem

Upon examining the text attributes of the NSTextField before and after editing, I noticed that NSOriginalFont was set to .AppleSystemUIFont 12pt instead of my font, which was Helvetica Neue 11pt.

BEFORE

NSFont = "\"HelveticaNeue 11.00 pt. P [] (0x600000e46400) fobj=0x1040163d0, spc=3.06\"";
NSOriginalFont = "\".AppleSystemUIFont 12.00 pt. P [] (0x600000d8f0f0) fobj=0x10361b1a0, spc=3.39\"";

AFTER:

NSFont = "\"HelveticaNeue 11.00 pt. P [] (0x600000e46400) fobj=0x1040163d0, spc=3.06\"";
NSOriginalFont = "\"HelveticaNeue 11.00 pt. P [] (0x600000e46400) fobj=0x1040163d0, spc=3.06\"";

I solved the problem by setting the NSAttributedString's font attribute not only NSFontAttributeName (i.e., @"NSFont") but also @"NSOriginalFont".

[controlText removeAttribute:NSFontAttributeName range:(NSMakeRange(0, len))];
[controlText addAttribute:NSFontAttributeName value:font range:(NSMakeRange(0, len))];
[controlText removeAttribute:@"NSOriginalFont" range:(NSMakeRange(0, len))];
[controlText addAttribute:@"NSOriginalFont" value:font range:(NSMakeRange(0, len))];

Upvotes: 2

Eugene Mankovski
Eugene Mankovski

Reputation: 1180

You need to set allowsEditingTextAttributes = true

For example:

class ViewController: NSViewController {

dynamic var markdownText : String?

@IBOutlet weak var label: NSTextField!

override func viewDidLoad() {

    super.viewDidLoad()

    label.allowsEditingTextAttributes = true
}
}

Then you can select text as in my example:

enter image description here

Here is the code:https://github.com/emankovski/BindingFormattedText

Upvotes: 11

Related Questions