Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sample code for creating a NSTextField "label"?

In my desktop Mac OS X app, I'd like to programatically create a NSTextField "label" which has the same behavior and properties as a typical label created in Interface Builder.

I usually use (and very much like) IB, but in this case it must be done programatically.

Try as I might, I can't seem to find the combination of method calls that will programatically produce the same label-y behavior as a "Label" dragged from the IB View Library palette.

Can anyone provide or point out some example code of how to do this programatically? Thx.

like image 457
Todd Ditchendorf Avatar asked Oct 02 '09 03:10

Todd Ditchendorf


2 Answers

A label is actually an instance of NSTextField, a subclass of NSView. So, since it is a NSView, it has to be added to another view.

Here's a working code:

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {     NSTextField *textField;      textField = [[NSTextField alloc] initWithFrame:NSMakeRect(10, 10, 200, 17)];     [textField setStringValue:@"My Label"];     [textField setBezeled:NO];     [textField setDrawsBackground:NO];     [textField setEditable:NO];     [textField setSelectable:NO];     [view addSubview:textField]; } 
like image 104
Thibault Martin-Lagardette Avatar answered Oct 06 '22 19:10

Thibault Martin-Lagardette


macOS 10.12 and Later

Starting with macOS 10.12 (Sierra), there are three new NSTextField constructors:

  • NSTextField(labelWithString:), which the header file comment says “Creates a non-wrapping, non-editable, non-selectable text field that displays text in the default system font.”

  • NSTextField(wrappingLabelWithString:), which the header file comment says “Creates a wrapping, non-editable, selectable text field that displays text in the default system font.”

  • NSTextField(labelWithAttributedString:), which the header file comment says “Creates a non-editable, non-selectable text field that displays attributed text. The line break mode of this field is determined by the attributed string's NSParagraphStyle attribute.”

I tested the ones that take a plain (non-attributed string), and they create text fields that are similar to, but not precisely the same as, the text fields created in a storyboard or xib.

The important difference is that both constructors create a text field with textBackgroundColor (normally pure white) as its background color, while the storyboard text field uses controlColor (normally about 90% white).

Unimportantly, both constructors also set their fonts by calling NSFont.systemFont(ofSize: 0) (which produces a different NSFont object than my code below, but they wrap the same underlying Core Text font).

The wrappingLabelWithString: constructor sets the field's isSelectable to true. (This is documented in the header file.)


macOS 10.11 and Earlier

I compared four NSTextField instances: one created by dragging a “Label” to a storyboard, another created by dragging a “Wrapping Label” to a storyboard, and two in code. Then I carefully modified properties of the code-created labels until all their properties were exactly the same as the storyboard-created labels. These two methods are the result:

extension NSTextField {      /// Return an `NSTextField` configured exactly like one created by dragging a “Label” into a storyboard.     class func newLabel() -> NSTextField {         let label = NSTextField()         label.isEditable = false         label.isSelectable = false         label.textColor = .labelColor         label.backgroundColor = .controlColor         label.drawsBackground = false         label.isBezeled = false         label.alignment = .natural         label.font = NSFont.systemFont(ofSize: NSFont.systemFontSize(for: label.controlSize))         label.lineBreakMode = .byClipping         label.cell?.isScrollable = true         label.cell?.wraps = false         return label     }      /// Return an `NSTextField` configured exactly like one created by dragging a “Wrapping Label” into a storyboard.     class func newWrappingLabel() -> NSTextField {         let label = newLabel()         label.lineBreakMode = .byWordWrapping         label.cell?.isScrollable = false         label.cell?.wraps = true         return label     }  } 

If you use one of these methods, don't forget to set your field's frame, or turn off its translatesAutoresizingMaskIntoConstraints and add constraints.


Here is the code I used to compare the different text fields, in case you want to check:

import Cocoa  class ViewController: NSViewController {      @IBOutlet var label: NSTextField!     @IBOutlet var multilineLabel: NSTextField!      override func loadView() {         super.loadView()     }      override func viewDidLoad() {         super.viewDidLoad()          let codeLabel = NSTextField.newLabel()         let codeMultilineLabel = NSTextField.newWrappingLabel()          let labels = [label!, codeLabel, multilineLabel!, codeMultilineLabel]          for keyPath in [             "editable",             "selectable",             "allowsEditingTextAttributes",             "importsGraphics",             "textColor",             "preferredMaxLayoutWidth",             "backgroundColor",             "drawsBackground",             "bezeled",             "bezelStyle",             "bordered",             "enabled",             "alignment",             "font",             "lineBreakMode",             "usesSingleLineMode",             "formatter",             "baseWritingDirection",             "allowsExpansionToolTips",             "controlSize",             "highlighted",             "continuous",             "cell.opaque",             "cell.controlTint",             "cell.backgroundStyle",             "cell.interiorBackgroundStyle",             "cell.scrollable",             "cell.truncatesLastVisibleLine",             "cell.wraps",             "cell.userInterfaceLayoutDirection"         ] {             Swift.print(keyPath + " " + labels.map({ ($0.value(forKeyPath: keyPath) as? NSObject)?.description ?? "nil" }).joined(separator: " "))         }     } } 
like image 30
rob mayoff Avatar answered Oct 06 '22 18:10

rob mayoff