0

I have a swift program that displays a custom table. Originally I incorrectly used a NSTextField for each cell and ran into a formatting issue. As can be seen in the picture below, the text in each cell is up against the top border. I was unable to figure out how to solve the problem so I posted my original code below. A response suggested that I change the NSTextField to a NSTableCellView. So I changed my code (new code is now below) to incorporate the NSTableCellView. Unfortunately, I ended up with the same formatting problem. I thought I could apply a constraint to the NSTableCellView relative to its parent but with no success (attempt commented out in delegate). It would be appreciated if someone could point me in the right direction to solve this issue. If I need to post more of my code, please let me know.

enter image description here

// Coordinators delegate
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {

    let dataCell = CustomTableCellView()
    switch tableColumn?.identifier.rawValue {
    case "fund":
        dataCell.Setup(rectWidth: 100.0, row: row, column: tableColumn!, numberOfRows: closingValues.count)
        dataCell.textField?.stringValue = closingValues[row].fundName
    case "date":
        dataCell.Setup(rectWidth: 120.0, row: row, column: tableColumn!, numberOfRows: closingValues.count)
        dataCell.textField?.stringValue = SQLDateFormatter.string(from: closingValues[row].timeStamp)
    default:
        dataCell.Setup(rectWidth: 100.0, row: row, column: tableColumn!, numberOfRows: closingValues.count)
        dataCell.textField?.stringValue = String(format: "$%.2f", closingValues[row].close)
    }
//            let constraints = [
//                dataCell.topAnchor.constraint(equalTo: ??parent??.topAnchor, constant: 5.0)
//            ]
//            NSLayoutConstraint.activate(constraints)
    return dataCell
}

// Custom NSTableCellView
class CustomTableCellView: NSTableCellView {
    
    override init(frame frameRect: NSRect) {
        super.init(frame: frameRect)
    }
    func Setup(rectWidth: CGFloat, row: Int, column: NSTableColumn, numberOfRows: Int) {
        self.autoresizingMask = .width
        let nsRectangle: NSRect = NSMakeRect(0, 0, rectWidth, 24)
        let customTextField: CustomTextField = CustomTextField(frame: nsRectangle)
        customTextField.SetTextAttributes(row: row, column: column, numberOfRows: numberOfRows)
        self.textField = customTextField
        self.addSubview(customTextField)
    }
    required init?(coder decoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

Chris
  • 105
  • 8
  • 1
    What are you trying to accomplish? Why `CustomTextField` and why don't you use `NSTableCellView`? – Willeke Aug 28 '23 at 08:28
  • I am trying to vertically align the text in the body of the table. I will look at utilizing NSTableCellView which I assume will allow me to do so. – Chris Aug 28 '23 at 19:47
  • Does this answer your question? [NSTextField margin and padding? (Swift)](https://stackoverflow.com/questions/39906160/nstextfield-margin-and-padding-swift) – Willeke Aug 28 '23 at 20:08
  • I think you are right about using NSTableCellView. Have changed delegate to utilize but am stuck on this line "guard let dataCell = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "dataCell"), owner: self) as? NSTableCellView else { return nil }". It always returns nil. I think I need to add "dataCell" as an identifier to the TableCellView but have not yet figured out how to do so. Thank you for sharing your knowledge. – Chris Aug 28 '23 at 22:30
  • This question is now a duplicate of [Is it possible to create a view-based NSTableView purely in code?](https://stackoverflow.com/questions/33992756/is-it-possible-to-create-a-view-based-nstableview-purely-in-code) – Willeke Aug 31 '23 at 20:16

1 Answers1

0

After some more thought, I realized all I needed to do is get access to the base line offset of the cell text. So I made 2 changes to my CustomTextField class (the code for which is included below). 1) Commented out all text attributes from the SetTextAttributes function. 2) Added all the code above super.draw(dirtyRect) in the override func draw(_ dirtyRect: NSRect). By going to an attributed string value I got access to the base line offset. This allowed me to move the text down vertically. Problem solved.

enter image description here

class CustomTextField :NSTextField {
    
    var row: Int = 0
    var column: NSTableColumn = NSTableColumn()
    var numberOfRows: Int = 0
    
    override init(frame frameRect: NSRect) {
        super.init(frame: frameRect)
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
    }
    
    func SetTextAttributes(row: Int, column: NSTableColumn, numberOfRows: Int)   {
//        textColor = .blue
//        backgroundColor = .white
//        isBordered = false
//        isEditable = false
//        font = NSFont(name: "Arial", size: 16)!
//        alignment = .center
        self.row = row
        self.column = column
        self.numberOfRows = numberOfRows
    }
    
    override func draw(_ dirtyRect: NSRect) {
        isBordered = false
        isEditable = false
        let paragraphStyle = NSMutableParagraphStyle()
        paragraphStyle.alignment = .center
        attributedStringValue = NSAttributedString(string: stringValue, attributes:
                                                    [NSAttributedString.Key.foregroundColor: NSColor.blue,
                                                     NSAttributedString.Key.backgroundColor: NSColor.white,
                                                     NSAttributedString.Key.font: NSFont(name: "Arial", size: 16)!,
                                                     NSAttributedString.Key.paragraphStyle: paragraphStyle,
                                                     NSAttributedString.Key.baselineOffset: -4.0
                                                    ])
        super.draw(dirtyRect)
        NSColor.lightGray.set()
        let customBorder = NSBezierPath()
        customBorder.move(to: NSMakePoint(0.0, dirtyRect.height))
        customBorder.line(to: NSMakePoint(0.0, 0.0))
        customBorder.line(to: NSMakePoint(dirtyRect.width, 0.0))
        if column.title == "Closing" {
            customBorder.line(to: NSMakePoint(dirtyRect.width, dirtyRect.height))
        }
        if row == numberOfRows - 1 {
            
            if column.title == "Fund" || column.title == "Date" {
                customBorder.move(to: NSMakePoint(dirtyRect.width, dirtyRect.height))
                customBorder.line(to: NSMakePoint(0.0, dirtyRect.height))
            }
            customBorder.line(to: NSMakePoint(0.0, dirtyRect.height))
        }
        customBorder.lineWidth = 2
        customBorder.stroke()
    }
}


Chris
  • 105
  • 8