nstableviewswift5nspopovernstablecellview

How can I pin an NSPopover to a selected NSTableCellView in swift5


I have the code shown below, that pins an NSPopover to my NSTableView. I've looked all over Google, and SO, but I cannot find a way to pin the popover to a specific (selected) cell.

@objc func tableViewDoubleAction(sender: NSTableCellView) {

let message = "Please Choose"
let controller = NSViewController()
controller.view = NSView(frame: CGRect(x: CGFloat(100), y: CGFloat(50), width: CGFloat(300), height: CGFloat(250)))

let popover = NSPopover()
popover.contentViewController = controller
popover.contentSize = controller.view.frame.size

popover.behavior = .transient
popover.animates = true


popover.show(relativeTo: sender.bounds, of: sender as NSView, preferredEdge: NSRectEdge.maxY)

Here's an image to demonstrate the issue:

 an image


Solution

  • From the documentation of NSTableView.doubleAction:

    The clickedRow and clickedColumn properties allow you to determine which row and column the double-click occurred in or if, rather than in a row, the double-click occurred in a column heading.

    @objc func tableViewDoubleAction(sender: NSTableView) {
        let row = sender.clickedRow
    

    From the documentation of clickedRow:

    The index of the row the user clicked to trigger an action message. Returns –1 if the user clicked in an area of the table view not occupied by table rows.

        if row >= 0 {
    

    NSTableView has a method rect(ofRow:):

    Returns the rectangle containing the row at the specified index.

            let rowRect = sender.rect(ofRow: row)
    

    Use this rect to position the popover

            popover.show(relativeTo: rowRect, of: sender, preferredEdge: NSRectEdge.maxY)
    

    Put it all together:

    @objc func tableViewDoubleAction(sender: NSTableView) {
        let row = sender.clickedRow
        if row >= 0 {
            // create the popover
            let rowRect = sender.rect(ofRow: row)
            popover.show(relativeTo: rowRect, of: sender, preferredEdge: NSRectEdge.maxY)
        }
    }