Search code examples
macosswiftnsviewnstextviewprogrammatically-created

Adding and removing NSTextField programmatically in Swift


I am trying to write text labels on a graph view representing a variety of data points (imagine a line graph in Excel).

I select a data set using a tableView. Each time a select a new data set the graph is redrawn.

I can draw the line graph using a custom view. No problems.

I can draw the text labels using the following function called from drawRect():

func drawDataPointLabels(size: CGSize) {  //size is the view.bounds
    
    var dataLabelsArray: [(NSColor, String, NSRect)] = []
    
    // graphDetails contain an array of tuples  [(), (), (), ()] - this represents one graph type = eg Monthly Fees ** there will be a maximum of 12 items in the array
    for graphDetails in graphDetailsArray {
        
         // each dataPoint object is a tuple (graphType:  columnLabel: columnColor:  columnHeight:  columnNumber: ) representing one dataPoint
        for dataPoint in graphDetails {
            let graphHeight = size.height / 2
            let graphWidth = size.width - graphOrigin.x - rightMargin
            let columnAndGapSize = graphWidth / 25
            let labelX: CGFloat = (graphOrigin.x + columnAndGapSize) + (columnAndGapSize * dataPoint.columnNumber) * 2
            let labelY: CGFloat = dataPoint.columnHeight * (graphHeight - topMargin - bottomMargin)
            
            // determine the location and frame for the text label to match dataPoint
            let textFrame = NSRect(x: labelX, y: labelY, width: 30, height: 10)
            let dataPointTuple = (dataPoint.columnColor, dataPoint.columnLabel, textFrame)
            dataLabelsArray.append(dataPointTuple)
        }
        
        for dataPoint in dataLabelsArray {
            let (color, label, frameRect) = dataPoint
            let lblDataPoint = NSTextField(frame: frameRect)
            lblDataPoint.stringValue = label
            lblDataPoint.backgroundColor = backgroundColor
            lblDataPoint.textColor = color
            self.addSubview(lblDataPoint)
        }
    }
}

However, I can not work out how to remove the data labels when the view is updated and a new data set presented. The graph redraws but the text labels remain from the previous data set.


Solution

  • Adding the following code to the top of the function has solved the issue for me.

            let subViewsToRemove = self.subviews
    
            for object in subViewsToRemove {
                object.removeFromSuperview()
            }