How to change selection color for NSTableView which use NSArrayContoller as content source?
Asked Answered
K

3

9

I have an NSTableView (view Based) who show info's from an NSarrayController. All connections are made from IB. Everything works fine, but blue selection color doesn't look ok with my design idea, so I want to change this color with my own color, but until now I failed.

class MyTable: NSTableView, NSTableViewDelegate {
    override func drawBackgroundInClipRect(clipRect: NSRect) {

        if self.isRowSelected( self.selectedRow ){
            //NSColor.brownColor().colorWithAlphaComponent(0.9).setFill()
           // NSBezierPath.fillRect(clipRect)
            println("selected")

        }
    }


}

My real problem is that: I have no idea where should I start, what to subclass, NSTableView , NSTableCellView etc.

Recent I discovered a method to do that which say I should subclass NSTableRowView, and override drawSelectionInRect function. I've did that, but in IB i don't have an NSTableRowView Object.

Thanks.

Kwiatkowski answered 6/4, 2015 at 15:16 Comment(0)
A
21

I did that in this way. First subclass NSTableRowView as you said:

class MyRowView: NSTableRowView {

    override func drawRect(dirtyRect: NSRect) {
        super.drawRect(dirtyRect)

        if selected == true {
            NSColor.greenColor().set()
            NSRectFill(dirtyRect)
        }
    }
}

And then just add this method:

func tableView(tableView: NSTableView, rowViewForRow row: Int) -> NSTableRowView? {
    let myCustomView = MyRowView()
    return myCustomView
}

If I remember right, that should do it.

Edit: I just try my example and it works. In IB i set my tableview's delegate and datasource to ViewController and named my only column to "name." Here is my whole ViewController class:

class ViewController: NSViewController, NSTableViewDataSource, NSTableViewDelegate {

    var persons = [Person]()

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
        populate()
    }

    func populate() {
        var first = Person(name: "John")
        var second = Person(name: "Jesse Pinkman")

        persons = [first, second]
    }

    func numberOfRowsInTableView(tableView: NSTableView) -> Int {
        return persons.count
    }

    func tableView(tableView: NSTableView, viewForTableColumn tableColumn: NSTableColumn?, row: Int) -> NSView? {
        if tableColumn?.identifier == "name" {
            let view = tableView.makeViewWithIdentifier(tableColumn!.identifier!, owner: self) as! NSTableCellView
            view.textField?.stringValue = persons[row].name
            return view
        }
        return nil
    }

    func tableView(tableView: NSTableView, rowViewForRow row: Int) -> NSTableRowView? {
        let myCustomView = MyRowView()
        return myCustomView
    }

}
Adequacy answered 6/4, 2015 at 15:30 Comment(4)
Right now i've added this, but still not work. When I select a row in table this function is not called.Kwiatkowski
For me that works. While ago, I had syntax error in my answer, missed '()' after 'greenColor'. But I used Viewcontroller which conforms protocols NSTableViewDataSource, NSTableViewDelegate and didn't subclass my tableview.Adequacy
In the end, with your help, i changed that color. Thanks!Kwiatkowski
Fantastic solution, extremely simple and easy to implement and modify. I was working with a case where in the table different rows are "inactive" and I wanted to make the active ones a little easier to find by changing the background to a very light grey. I changed your "tableView(tableView: NSTableView, rowViewForRow row: Int)" to return the custom view on the active rows and a plain NSTableRowView() on regular rows - worked like a charm, thanks!Southwesterly
D
6

Swift 4 version of @Prontto 's excellent answer.

class MyRowView: NSTableRowView {
    override func draw(_ dirtyRect: NSRect) {
        super.draw(dirtyRect)

        if isSelected == true {
            NSColor.green.set()
            dirtyRect.fill()
        }
    }
}

.

// In your NSTableViewDelegate
func tableView(_ tableView: NSTableView, rowViewForRow row: Int) -> NSTableRowView? {
    return MyRowView()
}
Dolhenty answered 22/4, 2018 at 17:34 Comment(1)
Perfect answer thanks Also don't forget to set Highlight : Regular in Storyboard's inspector. If set to None it won't appear.Acknowledge
B
5

The preferred method is to override drawSelection(in:) which the default implementation of draw(_:) calls when it needs to draw the selection for a selected row. You don't have to check the selection state yourself.

override func drawSelection(in dirtyRect: NSRect) {
    NSColor.green.setFill()
    dirtyRect.fill()
}

However, if you override draw(in:) as well and do not call the superclass implementation, you will have to call drawSelection(in:) manually and determine the selection state yourself. Another benefit to overriding drawSelection(in:) is that "the selection will automatically be alpha-blended if the selection is animating in or out.".

Blumenfeld answered 21/11, 2017 at 2:47 Comment(1)
Really helpful. In Swift 4 (XCode 9.4) NSRectFill(dirtyRect) becomes dirtyRect.fill() though.Bacteriostat

© 2022 - 2024 — McMap. All rights reserved.