1
votes

I tried many different ways to create a NSTableview with custom NSTableCellView but I could not make it work. The question is, how can I do that thing?

Here is the last thing I tried:

func tableView(tableView: NSTableView, viewForTableColumn tableColumn: NSTableColumn?, row: Int) -> NSView? {

    var cellIdentifier: String = ""


    if tableColumn == tableView.tableColumns[0] {

        cellIdentifier = "CellID"

        if let cell = tableView.makeViewWithIdentifier(cellIdentifier, owner: self ) as? MyTableCellView {

            cell.identifier = cellIdentifier
            // array is an array that contains NSView with layers with different colors
            cell.myView = array[row]
            return cell
        }
    }
    return nil
}

enter image description here

After adding a label:

enter image description here

And the full code:

class ViewController: NSViewController, NSTableViewDelegate, NSTableViewDataSource {

override func viewDidLoad() {
    super.viewDidLoad()
    tableview.setDelegate(self)
    tableview.setDataSource(self)

    let view = NSView(frame: NSRect(x: 0, y: 0, width: 200, height: 200))
    view.layer?.backgroundColor = NSColor.blueColor().CGColor
    array.append(view)
    let view2 = NSView(frame: NSRect(x: 0, y: 0, width: 200, height: 200))
    view2.layer?.backgroundColor = NSColor.greenColor().CGColor
    array.append(view2)

    array2label.append("bu")
    array2label.append("buu")

    tableview.reloadData()

    // Do any additional setup after loading the view.
}

override func viewWillAppear() {


    //tableview.reloadData()

    laView.layer?.backgroundColor = NSColor.greenColor().CGColor
}
@IBOutlet weak var laView: NSView!

@IBOutlet weak var tableview: NSTableView!

var array = [NSView]()
var array2label = [String]()// = ["bu","buu"]

func numberOfRowsInTableView(tableView: NSTableView) -> Int {
    if (tableView.identifier == "Taula") {

        return array.count
        //return taulaGrafics.count
    } else {
        return 0
    }

}

@IBOutlet weak var viewDeProva: NSView!

func tableView(tableView: NSTableView, viewForTableColumn tableColumn: NSTableColumn?, row: Int) -> NSView? {
    print ( "Preparem la TableView" )
    var cellIdentifier: String = ""


    if tableColumn == tableView.tableColumns[0] {

        cellIdentifier = "CellID"

        if let cell = tableView.makeViewWithIdentifier(cellIdentifier, owner: self ) as? MyTableCellView {
            print ( "aqui" )
            print(array)
            print(array2label)

            cell.identifier = cellIdentifier
            cell.myView = array[row]
            cell.label.stringValue = array2label[row]

            return cell
        }
    }
    return nil
}

@IBAction func afegir(sender: NSButton) {
    let view = NSView(frame: NSRect(x: 0, y: 0, width: 200, height: 200))
    view.layer?.backgroundColor = NSColor.yellowColor().CGColor
    array.append(view)
    array2label.append("buLabel")
    tableview.reloadData()
}
@IBAction func treure(sender: NSButton) {
    array.removeLast()
    tableview.reloadData()
}
}

enter image description here

 if let cell = tableView.makeViewWithIdentifier(cellIdentifier, owner: self ) as? MyTableCellView {
            print ( "aqui" )
            print(array)
            print(array2label)

            cell.identifier = cellIdentifier
            cell.myView = array[row]
            cell.myView.wantsLayer = true
            cell.label.stringValue = array2label[row]

            return cell
        }
1
Have you added your custom cell to the tableView in the storyboard? Have you set the identifier?mangerlahn
@Max Yes I do, see the new image on the questionRafa Febrer
As the cellView does nothing but myView, the error could be in there. To test this, add a label or button to the cellView just to check if it is loaded.mangerlahn
On my way! thanks for the answerRafa Febrer
@Max I added the label inside the Viewcell, after seeing the results, what does it mean?Rafa Febrer

1 Answers

0
votes

With this changes the view show the color that is expected to be:

class ViewController: NSViewController, NSTableViewDelegate, NSTableViewDataSource {

override func viewDidLoad() {
    super.viewDidLoad()
    print("DidLoad")
    tableview.setDelegate(self)
    tableview.setDataSource(self)
}

override func viewWillAppear() {
    print("WillAppear")
    array.append(NSColor.blueColor().CGColor)
    array2label.append("buIni")
    tableview.reloadData()
    laView.layer?.backgroundColor = NSColor.greenColor().CGColor
}

@IBOutlet weak var laView: NSView!

@IBOutlet weak var tableview: NSTableView!

var array = [CGColor]()
var array2label = [String]()

func numberOfRowsInTableView(tableView: NSTableView) -> Int {
    if (tableView.identifier == "Taula") {

        return array.count
        //return taulaGrafics.count
    } else {
        return 0
    }

}

@IBOutlet weak var viewDeProva: NSView!

func tableView(tableView: NSTableView, viewForTableColumn tableColumn: NSTableColumn?, row: Int) -> NSView? {
    print ( "Preparem la TableView" )
    var cellIdentifier: String = ""


    if tableColumn == tableView.tableColumns[0] {

        cellIdentifier = "CellID"

        if let cell = tableView.makeViewWithIdentifier(cellIdentifier, owner: self ) as? MyTableCellView {
            print ( "Here" )
            print(array)
            print(array2label)
            cell.identifier = cellIdentifier
            cell.myView.layer?.backgroundColor = array[row]
            cell.label.stringValue = array2label[row]

            return cell
        }
    }
    return nil
}

@IBAction func afegir(sender: NSButton) {
    let color = NSColor.yellowColor().CGColor
    array.append(color)
    array2label.append("buLabel")
    tableview.reloadData()
}
@IBAction func treure(sender: NSButton) {
    array.removeLast()
    array2label.removeLast()
    tableview.reloadData()
}
}

The problem was that the NSView inside the NSTableViewCell can't be replaced by another view, because what you do doing that is changing the prototype cell. So if you replace the view the NSTableViewCell doesn't recognize that NewView layer (I'm not sure 100% why). Looks like just some information is shared.

So, how can we pass info to the tableview cell? How can we show a layer there?? Well the answer is that just modifying the prototype cell NSTableCellView added on the interface builder or its subclass (like my case, see bellow the cell). Modifying its content, but not the NSView!, inside the viewForTableColumn function. See in this piece of code:

if let cell = tableView.makeViewWithIdentifier(cellIdentifier, owner: self ) as? MyTableCellView {

            cell.identifier = cellIdentifier // that is to identify the cell
            cell.myView.layer?.backgroundColor = array[row] // see that the array contains CGCOLORS not NSViews
            // The program was not showing the colors because the
            // view copied doesn't copy its layer, or at least
            // doesn't show it.
            // Even though, if you say: *******---This is incorrect:
            cell.myView = arrayOfNSViews[row] //the program will
            // crash when removing 2 rows, myView = nil !!!!. 
            // That is because when you remove the item of the array
            // somehow you are removing myView too, because it make a
            // copy or a reference to it (Not sure what exactly).
            // Here continues the correct program: ******---

            cell.label.stringValue = array2label[row]

            return cell
}

Also see that in the textField case: cell.label.stringValue = array2label[row], you change the string value of the textfield, not the whole NSTextfield.

So guys remember and repeat my words: "I'm not going to change the view of the cell, just its properties". I just spend 4 days to find that...

Here is the NStableCellView promised:

class MyTableCellView: NSTableCellView {

   @IBOutlet weak var myView: NSView!

   @IBOutlet weak var label: NSTextField!

}

One Image of the view hierarchy:

enter image description here