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:
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:
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]];
}
NSTextFieldCell
only has font
and color
attributes. You could solve this problem with a custom NSTextFieldCell
subclass (it shouldn't be too difficult to write), or you could bind to a custom glue object that would call setAttributedStringValue:
on your text field whenever its setter was called via bindings. Or you could forego bindings entirely. None of the solutions are particularly elegant, but I think they would work. –
Perfidious NSTextFieldCell
. I create a subclass called StrikethroughTextFieldCell
and I reimplement the method drawInteriorWithFrame:inView:
: - (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView { [super drawInteriorWithFrame:cellFrame inView:controlView]; NSMutableAttributedString *as = [self.attributedStringValue mutableCopy]; [as addAttribute:NSStrikethroughStyleAttributeName value:(NSNumber *)kCFBooleanTrue range:NSMakeRange(0, as.length)]; [self setAttributedStringValue:as]; }
. Unfortunately, however, does not work as expected. –
Tyrr setStringValue:
. I've updated my answer to show this. Also, obviously you'll need to set the custom cell class in IB. –
Perfidious setStringValue:
is never called when I use Cocoa Bindings. This is why I tried, unsuccessfully, to override drawInteriorWithFrame:inView:
. –
Tyrr setObjectValue:
is called, probably because the value of my NSTextFieldCell
is bounded to a NSNumber
. Anyway, when the setAttributedStringValue
is called it enters in a recursive loop... –
Tyrr 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];
}
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;
© 2022 - 2024 — McMap. All rights reserved.
awakeFromNib
I don't know the length of the text that will be inserted in the text field. In fact, I use Cocoa Bindings and I don't ever directly control the content of the text field. There is no a way to strikethrough a label regardless of its content? – Tyrr