Dev
Dev

Reputation: 7066

Mac OS X: strikethrough the text in a label (NSTextField)

Is it possible to strikethrough the text in a label (NSTextField)?

I have tried to use the Font Panel, but apparently these are ignored when I try to set them:

enter image description here

enter image description here

Upvotes: 5

Views: 2298

Answers (3)

Martijn
Martijn

Reputation: 469

I'd like to share an easier approach with more options and also point to a mistake in earlier answers.

Easy
To bypass the string length, use initWithString:attributes: to apply the attributes on the entire string.

Mistake
All the above examples set a boolean value (kCFBooleanTrue) for NSStrikethroughStyleAttributeName. This is incorrect, since the data type of NSStrikethroughStyleAttributeName is an integer of type NSUnderlineStyle.
The reason why the above examples with kCFBooleanTrue work, is that they cast this boolean to an NSNumber, resulting in value 1. Which coincidentally matches that of a single line strikethrough NSUnderlineStyleSingle.

Bonus 1 - style
Using NSUnderlineStyle properly allows even more flexibility, for example by using a thick line (NSUnderlineStyleThick) or a double line (NSUnderlineStyleDouble).

Bonus 2 - color
The strikethrough color can also be defined in the attributes: dictionary via key NSStrikethroughColorAttributeName.

All this combined results in the following example:

// Show text with a red single line strikethrough:
NSMutableAttributedString *text = [[NSMutableAttributedString alloc] initWithString:@"strikethrough"
                                                                         attributes:@{
    NSStrikethroughStyleAttributeName : [NSNumber numberWithInteger:NSUnderlineStyleSingle],
    NSStrikethroughColorAttributeName : [NSColor systemRedColor]
}];

_textField.attributedStringValue = text;

Upvotes: 0

martn_st
martn_st

Reputation: 2636

For me it works great combining the approach by sbooth of creating a custom NSTextFieldCell and overriding drawInteriorWithFrame:inView: as posted below:

- (void) drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView {
    [self setAttributedStringFromStringValue];
    [super drawInteriorWithFrame:cellFrame inView:controlView];
}


- (void) setAttributedStringFromStringValue {  // add strikethrough
    NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:self.stringValue];
    [attributedString addAttribute:NSStrikethroughStyleAttributeName value:(NSNumber *)kCFBooleanTrue range:NSMakeRange(0, attributedString.length)];
    [self setAttributedStringValue:attributedString];
}

Upvotes: 1

sbooth
sbooth

Reputation: 16976

You can do it like this, assuming _textField is set as an outlet in your xib:

- (void) awakeFromNib
{
  NSMutableAttributedString *as = [[_textField attributedStringValue] mutableCopy];
  [as addAttribute:NSStrikethroughStyleAttributeName value:(NSNumber *)kCFBooleanTrue range:NSMakeRange(0, [as length])];
  [_textField setAttributedStringValue:[as autorelease]];
}

Edit:

If you want to write a custom strikethrough NSTextFieldCell subclass instead, the only method that should be necessary to override is setStringValue:

- (void) setStringValue:(NSString *)aString
{
  NSMutableAttributedString *as = [[NSMutableAttributedString alloc] initWithString:aString];
  [as addAttribute:NSStrikethroughStyleAttributeName value:(NSNumber *)kCFBooleanTrue range:NSMakeRange(0, [as length])];
  [self setAttributedStringValue:[as autorelease]];
}

Upvotes: 6

Related Questions