joels
joels

Reputation: 7721

How to change NSTextField text color on row selection?

For cocoa, I have an NSTableView set to be view based. When a row is selected, the text fields change their color to white. How do I keep it black?

I should also note that the Highlight is set to Source List (it does the same thing on Regular). Highlight Setting

Unselected row Unselected

Selected Row Selected Row

I was hoping for something similar to the state config for iOS:

enter image description here

This was suggested in WWDC 2011 Session 120 but it's a bit delayed so I'm not going to use it. It may work for someone else though.

- (void)tableViewSelectionDidChange:(NSNotification *)notification
{
    [tableView enumerateAvailableRowViewsUsingBlock:^(NSTableRowView *rowView, NSInteger row){
        NSTableCellView *cellView = [rowView viewAtColumn:0];
        if(rowView.selected){
            cellView.textField.font = [NSFont boldSystemFontOfSize:14];
        }else{
            cellView.textField.font = [NSFont systemFontOfSize:14];
        }
    }];
}

Upvotes: 18

Views: 11735

Answers (7)

Ely
Ely

Reputation: 9131

In macOS 11 or higher, the .dark and .light background styles are deprecated. But you can use .emphased instead:

override var backgroundStyle: NSView.BackgroundStyle {
    willSet {
        textField.textColor = newValue == .emphasized ? .labelColor : .secondaryLabelColor
    }
}

In the example, .labelColor is the selected color, and .secondaryLabelColor the unselected color.

Upvotes: 0

cdyer
cdyer

Reputation: 1259

For my Swift app none of the above seemed to quite work correctly. This method handles the NSTableView losing focus correctly and when the window is not the key window but the cell is still selected.

Within the NSTableCellView subclass use the following:

override var backgroundStyle: NSView.BackgroundStyle {
  willSet {
    if newValue == .dark {
      title.textColor = NSColor.white
    } else {
      title.textColor = NSColor.labelColor
    }
  }
}

Upvotes: 2

Jeffrey Bergier
Jeffrey Bergier

Reputation: 229

I came up with a different solution. Subclassing NSTableCellView would have been fine if Cocoa supported @IBOutletCollection. Because then I could have one Cell subclass that has an array of all NSTextFields in the cell. But since I had many kinds of cells with varying numbers of NSTextFields I didn't like this option. Instead, I took a look at Apple's documentation for the backgroundStyle property in NSTableCellView.

The default implementation automatically forwards calls to all subviews that implement setBackgroundStyle: or are an NSControl, which have NSCell classes that respond to backgroundStyle.

If my TextFields implement setBackgroundStyle then they should get notified when the cell selection changes. However, this forwarding of the background style is not recursive. Because my NSTextFields were within NSStackViews they were not getting the message. To get around this, I just wrote an extension to implement setBackgroundStyle on all NSViews. It just forwards the message on. Lastly, I added an extension to NSTextField to also implement this method. From this extension, I change the text color and call super. This solution is also nice because no subclasses are needed. No subclasses of NSTableCellView or of NSTextField.

Adding this functionality to all views and to all NSTextFields could cause issues with NSTextFields that are not within NSTableViews changing color unexpectedly. But so far, only the ones within my TableViews/OutlineViews are changing color and thats exactly what I was looking for. If you see textfields changing color that you don't expect, you may want to subclass NSTextField and implement a setBackgroundStyle override only on that subclass instead of adding it to all NSTextFields.

The code in Swift 3 I used is pasted below.

extension NSView {
    func setBackgroundStyle(_ newValue: NSBackgroundStyle) {
        for view in self.subviews {
            view.setBackgroundStyle(newValue)
        }
    }
}

extension NSTextField {
    override func setBackgroundStyle(_ newValue: NSBackgroundStyle) {
        switch newValue {
        case .dark:
            self.textColor = NSColor.controlLightHighlightColor
        case .light, .lowered, .raised:
            self.textColor = NSColor.labelColor
        }
        super.setBackgroundStyle(newValue)
    }
}

Upvotes: 3

Nickkk
Nickkk

Reputation: 2647

Based on @sabes's answer, I created this NSTextFieldCell subclass which you can use to set your custom text colors when a row is selected or deselected. You can set the subclass of the relevant text field cell in IB.

@interface SNBlueTextFieldCell : NSTextFieldCell

@end

@implementation SNBlueTextFieldCell

- (void)setBackgroundStyle:(NSBackgroundStyle)backgroundStyle {
    [self setTextColor:(backgroundStyle==NSBackgroundStyleDark ? [NSColor blackColor] : [NSColor blueColor])];
}

@end

Upvotes: 1

paxos
paxos

Reputation: 927

There is no need for custom code to accomplish that.

Just set the color of the label to "label color" in Interface Builder. The automatic white/black thing only works if the label has the "Control Text Color" set and is in an NSTableCellView.

Upvotes: 18

sabes
sabes

Reputation: 335

Override NSTableCellView and add this method to change the text color when the cell is selected.

- (void) setBackgroundStyle:(NSBackgroundStyle)backgroundStyle
{
    NSTableRowView *row = (NSTableRowView*)self.superview;
    if (row.isSelected) {
        self.textField.textColor = [NSColor blackColor];
    } else {
        self.textField.textColor = [NSColor whiteColor];
    }

}

Upvotes: 14

David Beck
David Beck

Reputation: 10159

Depending on why you need to do this, there are 2 approaches.

You can subclass NSTableRowView and override -[NSTableRowView interiorBackgroundStyle] to return NSBackgroundStyleLight. This will tell the cells that they are on a light background and to draw dark text, which will be black.

The other way is to subclass NSTableCellView and override -[NSTableCellView setBackgroundStyle:] and set the colors yourself there.

Upvotes: 17

Related Questions