Search code examples
swiftmacoscocoanstableviewnsarraycontroller

NSTableView detect NSTableColumn for selected cell at start of cell edition


I'm trying to programatically get get a a column.identifier for the cell that is being edited. I'm trying to get by registering my NSViewController for NSControlTextDidBeginEditingNotification and when I get the notification I track the data by mouse location:

var selectedRow = -1
var selectedColumn: NSTableColumn?

func editingStarted(notification: NSNotification) {
    selectedRow = participantTable.rowAtPoint(participantTable.convertPoint(NSEvent.mouseLocation(), fromView: nil))

    let columnIndex = participantTable.columnAtPoint(participantTable.convertPoint(NSEvent.mouseLocation(), fromView: nil))
   selectedColumn = participantTable.tableColumns[columnIndex]

}

The problem I have is that the mouse location is giving me the wrong data, is there a way to get the mouse location based on the location of the table, or could there be a better way to get this information?

PS. My NSViewController is NSTableViewDelegate and NSTableViewDataSource, my NSTableView is View Based and connects to an ArrayController which updates correctly, and I could go to my Model object and detect changes in the willSet or didSet properties, but I need to detect when a change is being made by the user and this is why I need to detect the change before it happens on the NSTableView.


Solution

  • This question is 1 year old but I got the same issue today and fixed it. People helped me a lot here so I will contribute myself if someone found this thread.
    Here is the solution :

    1/ Add the NSTextFieldDelegate to your ViewController :

    class ViewController: NSViewController, NSTableViewDelegate, NSTableViewDataSource, NSTextFieldDelegate {
    

    2/ When a user wants to edit a cell, he had first to select the row. So we will detect that with this delegate function :

        func tableViewSelectionDidChange(_ notification: Notification) {
            let selectedRow = self.tableView.selectedRow
    
            // If the user selected a row. (When no row is selected, the index is -1)
            if (selectedRow > -1) {
            let myCell = self.tableView.view(atColumn: self.tableView.column(withIdentifier: "myColumnIdentifier"), row: selectedRow, makeIfNecessary: true) as! NSTableCellView
    
            // Get the textField to detect and add it the delegate
            let textField = myCell.textField
            textField?.delegate = self
        }
    }
    

    3/ When the user will edit the cell, we can get the event (and the data) with 3 different functions. Pick the ones you need :

    override func controlTextDidBeginEditing(_ obj: Notification) {
        // Get the data when the user begin to write
    }
    
    override func controlTextDidEndEditing(_ obj: Notification) {
        // Get the data when the user stopped to write
    }
    
    override func controlTextDidChange(_ obj: Notification) {
        // Get the data every time the user writes a character
    }