macos sierra - Programmatically adding a NSTableView to a NSStackView -
i wondering programmatically adding nstableview inside nsstackview using swift 3/macos sierra.
the idea have 2 nstextfields aligned via centery axis in .leading gravity space, tableview in .center gravity space, 2 more nstextfields aligned via centery axis in .trailing gravity space. stack view span width of nsview -- header.
is idea or should avoid doing this? has been difficult correct -- table has large of width despite adding constraints try pin fixed width.
any insight appreciated. i'm new programming macos.
thanks,
here output in interface builder: output of headerview
here code of nsview i'm using: view controller elsewhere i'm not having problems view controller -- it's displaying data in table correctly. it's sizing/positioning of tableview (which i'm trying in nsview via nsstackview) wrong. should have width of 650 instead has width of 907 , same error time in debug console:
2017-09-12 17:43:36.041062-0500 raceprogram[795:36958] [layout] detected missing constraints < racingprogram.raceimportviewheader: 0x6000001ccd50 >. cannot placed because there not enough constraints define size , origin. add missing constraints, or set translatesautoresizingmaskintoconstraints=yes , constraints generated you. if view laid out manually on macos 10.12 , later, may choose not call [super layout] override. set breakpoint on detected_missing_constraints debug. error logged once.
import cocoa @ibdesignable class raceimportviewheader: nsview { // mark: properties private var racequalificationstableview:nstableview private var raceimportheaderstackview:nsstackview private var racenumbertitle: nstextfield private var racenumbervalue: nstextfield public var racequalificationstablerowheight: cgfloat @ibinspectable var bordercolor:nscolor = .black @ibinspectable var backgroundcolor:nscolor = .lightgray enum initmethod { case coder(nscoder) case frame(cgrect) } override convenience init(frame: cgrect) { self.init(.frame(frame))! } required convenience init?(coder: nscoder) { self.init(.coder(coder)) } private init?(_ initmethod: initmethod) { // group initializers view class racequalificationstableview = nstableview() raceimportheaderstackview = nsstackview() racenumbertitle = nstextfield() racenumbervalue = nstextfield() racequalificationstablerowheight = 17.0 // initialize row height racequalifications switch initmethod { case let .coder(coder): super.init(coder: coder) case let .frame(frame): super.init(frame: frame) } self.translatesautoresizingmaskintoconstraints = false drawui() } override func draw(_ dirtyrect: nsrect) { super.draw(dirtyrect) let viewsize: nsrect = self.frame let newrect = nsrect(x: 0, y: 0, width: viewsize.width, height: viewsize.height) // outline header --> layout debug purposes let path = nsbezierpath(rect: newrect) backgroundcolor.setfill() path.fill() bordercolor.setstroke() // set stroke color path.stroke() // fill stroke or border of rectangle } // mark: ui construction func drawui() { let viewframe = self.frame // respect super class let viewbounds = self.bounds // respect view // mark: race number setup func addracenumbertitle(startingpositionx: cgfloat) { // configures label race number let width:cgfloat = 60.0 //arbitrary @ moment let height:cgfloat = 40.0 let leftpadding:cgfloat = 2.5 // super view (frame)is nsview in case let toppadding:cgfloat = (viewbounds.height - height)/2 let racenumbertitlensrect = nsrect(x: leftpadding + startingpositionx, y: viewbounds.height - height - toppadding, width: width, height: height) //swift.print("the racenumbertitlensrect title nsrect \(racenumbertitlensrect)") racenumbertitle = nstextfield(frame: racenumbertitlensrect) racenumbertitle.stringvalue = "race\nnumber" racenumbertitle.maximumnumberoflines = 2 racenumbertitle.iseditable = false racenumbertitle.isbordered = false racenumbertitle.alignment = .center racenumbertitle.backgroundcolor = .clear racenumbertitle.sizetofit() let updatedheight = racenumbertitle.frame.height let newupdatedpadding = (viewbounds.height - updatedheight) / 2 let oldoriginx = racenumbertitle.frame.origin.x let neworiginy = viewbounds.height - updatedheight - newupdatedpadding let neworigin = nspoint(x: oldoriginx, y: neworiginy) racenumbertitle.setframeorigin(neworigin) //addsubview(racenumbertitle) // add view raceimportheaderstackview.addview(racenumbertitle, in: .leading) } func addracenumbervalue(startingpositionx: cgfloat) { // configures value label race number let width:cgfloat = 20.0 //arbitrary @ moment let height:cgfloat = 40.0 let leftpadding:cgfloat = 5.0 // super view (frame)is nsview in case let toppadding:cgfloat = (viewbounds.height - height)/2 let racenumberinrect = nsrect(x: startingpositionx + leftpadding, y: viewbounds.height - height - toppadding, width: width, height: height) swift.print("the racenumberinrect title nsrect \(racenumberinrect)") racenumbervalue = nstextfield(frame: racenumberinrect) racenumbervalue.identifier = "racenumber" racenumbervalue.placeholderstring = "1" racenumbervalue.font = nsfont(name: "impact", size: 20.0) racenumbervalue.maximumnumberoflines = 1 racenumbervalue.iseditable = false racenumbervalue.isbordered = true racenumbervalue.alignment = .center racenumbervalue.backgroundcolor = .clear racenumbervalue.sizetofit() let updatedheight = racenumbervalue.frame.height let oldoriginx = racenumbervalue.frame.origin.x let newupdatedpadding = (viewbounds.height - updatedheight) / 2 let neworiginy = viewbounds.height - updatedheight - newupdatedpadding let neworigin = nspoint(x: oldoriginx, y: neworiginy) racenumbervalue.setframeorigin(neworigin) //addsubview(racenumbervalue) // add view raceimportheaderstackview.addview(racenumbervalue, in: .leading) } // mark: race qualifications table setup func addracequalificationstable(startingpositionx: cgfloat) { // padding variables let leftpadding:cgfloat = 5.0 let toppadding:cgfloat = 5.0 // table properties let width:cgfloat = 650.0 let height:cgfloat = 40 let tablerect = cgrect(x: startingpositionx + leftpadding, y: viewbounds.height - height - toppadding, width: width, height: height) //let insetfortableview:cgfloat = 1.0 //let scrollrect = cgrect(x: tablerect.origin.x-insetfortableview, y: tablerect.origin.y-insetfortableview, width: tablerect.width+2*insetfortableview, height: tablerect.height+2*insetfortableview) let tablenssize = nssize(width: tablerect.width, height: tablerect.height) let scrollnsrect = nsscrollview.framesize(forcontentsize: tablenssize, horizontalscrollerclass: nil, verticalscrollerclass: nil, bordertype: .bezelborder, controlsize: .regular, scrollerstyle: .legacy) swift.print("tablerect \(tablerect)") swift.print("scrollnsrect \(scrollnsrect)") //swift.print("scrollrect \(scrollrect)") let scrollvieworigin:cgpoint = tablerect.origin let scrollviewnssize:cgsize = scrollnsrect let scrollrect = nsrect(origin: scrollvieworigin, size: scrollviewnssize) swift.print("scrollrect \(scrollrect)") let tablescrollview = nsscrollview(frame: scrollrect) racequalificationstableview = nstableview(frame: tablerect) racequalificationstableview.identifier = "racequalificationstable" // setup identifier racequalificationstableview.rowheight = 20.0 swift.print("instrinic size \(racequalificationstableview.intrinsiccontentsize)") //swift.print("tablescrollview contentsize \(tablescrollview.contentsize)") tablescrollview.documentview = racequalificationstableview tablescrollview.autoresizingmask = .viewnotsizable swift.print("tablescroll content size \(tablescrollview.contentsize)") //self.addsubview(tablescrollview) raceimportheaderstackview.addview(tablescrollview, in: .center) } func configureracequalificationstable(showracenumbercol: bool, showracecodecol: bool) { let headeralignment = nstextalignment.center // easy way change justification of headers // mark: race number column options let racenumbercolumn = nstablecolumn(identifier: "racenumbercol") racenumbercolumn.title = "race" racenumbercolumn.minwidth = 40.0 racenumbercolumn.width = 40.0 racenumbercolumn.headertooltip = "race number imported card" racenumbercolumn.headercell.alignment = headeralignment // note: word race going wider race number value // size fit appropriate here. racenumbercolumn.sizetofit() if showracenumbercol { // option of not adding table racequalificationstableview.addtablecolumn(racenumbercolumn) } // mark: driver column options let breedcolumn = nstablecolumn(identifier: "drivercol") drivercolumn.title = "driver" drivercolumn.minwidth = 10 drivercolumn.headertooltip = "driver information" drivercolumn.headercell.alignment = headeralignment drivercolumn.sizetofit() racequalificationstableview.addtablecolumn(drivercolumn) // mark: race code column options let racetypecodecolumn = nstablecolumn(identifier: "racetypecodecol") racetypecodecolumn.title = "race code" racetypecodecolumn.minwidth = 40 racetypecodecolumn.headertooltip = "race classification code" racetypecodecolumn.headercell.alignment = headeralignment racetypecodecolumn.sizetofit() if showracecodecol { // option of not adding table racequalificationstableview.addtablecolumn(racetypecodecolumn) } // mark: race type code description options let racetypecodedesccolumn = nstablecolumn(identifier: "racetypecodedesccol") racetypecodedesccolumn.title = "race desc" racetypecodedesccolumn.minwidth = 50 racetypecodedesccolumn.width = 100 racetypecodedesccolumn.headertooltip = "race classification full description" racetypecodedesccolumn.headercell.alignment = headeralignment racequalificationstableview.addtablecolumn(racetypecodedesccolumn) // mark: race restriction column options let racerestrictioncolumn = nstablecolumn(identifier: "racerestrictioncol") racerestrictioncolumn.title = "restrictions" racerestrictioncolumn.minwidth = 50 racerestrictioncolumn.width = 80 racerestrictioncolumn.headertooltip = "race restrictions" racerestrictioncolumn.headercell.alignment = headeralignment racequalificationstableview.addtablecolumn(racerestrictioncolumn) // mark: sex restriction column options let sexrestrictioncolumn = nstablecolumn(identifier: "sexrestrictioncol") sexrestrictioncolumn.title = "sex" sexrestrictioncolumn.minwidth = 100 sexrestrictioncolumn.width = 100 sexrestrictioncolumn.headertooltip = "sex restrictions" sexrestrictioncolumn.headercell.alignment = headeralignment racequalificationstableview.addtablecolumn(sexrestrictioncolumn) // mark: age restriction column options let agerestrictioncolumn = nstablecolumn(identifier: "agerestrictioncol") agerestrictioncolumn.title = "age" agerestrictioncolumn.minwidth = 100 agerestrictioncolumn.width = 100 agerestrictioncolumn.headertooltip = "age restrictions" agerestrictioncolumn.headercell.alignment = headeralignment racequalificationstableview.addtablecolumn(agerestrictioncolumn) // mark: division column options let divisioncolumn = nstablecolumn(identifier: "divisioncol") divisioncolumn.title = "division" divisioncolumn.minwidth = 50 let mindivisioncolumnwidth = racequalificationstableview.frame.width - racenumbercolumn.width - drivercolumn.width - racetypecodecolumn.width - racetypecodedesccolumn.width - racerestrictioncolumn.width - sexrestrictioncolumn.width - agerestrictioncolumn.width // calculate available room division column if (showracecodecol && showracenumbercol) { // minimum case // no idea why need 25.0 manual adjustment divisioncolumn.width = mindivisioncolumnwidth - 25.0 } else if (showracecodecol && !showracenumbercol) { // add race type code // no idea why need manually adjust 53.5 divisioncolumn.width = mindivisioncolumnwidth + racetypecodecolumn.width - 53.5 } else if (!showracecodecol && showracenumbercol) { // add race number col divisioncolumn.width = mindivisioncolumnwidth + racenumbercolumn.width } else { // else it's maximum space // code making frame large -- increasing // frame size of column 670.0 put manual reduction of // 20 keep frame size same. not sure 20 coming from. divisioncolumn.width = mindivisioncolumnwidth + racenumbercolumn.width + racetypecodecolumn.width - 20.0 } //swift.print("the division column width \(divisioncolumn.width)") divisioncolumn.headertooltip = "division -- unknown means" divisioncolumn.headercell.alignment = headeralignment racequalificationstableview.addtablecolumn(divisioncolumn) //swift.print("racequalificationstableview.frame.width \( racequalificationstableview.frame.width)") } // mark: race distance surface course setup func addracedistancesurfacecoursetable(startingpositionx: cgfloat) { // table properties let width:cgfloat = 250.0 let height:cgfloat = 40.0 // padding variables let leftpadding:cgfloat = 5.0 let topposition:cgfloat = (viewbounds.height - ((viewbounds.height - height)/2) - height) let tablerect = cgrect(x: leftpadding + startingpositionx, y: topposition, width: width, height: height) let tablescrollview = nsscrollview(frame: tablerect) racedistancesurfacecoursetableview = nstableview(frame: tablerect) racedistancesurfacecoursetableview.identifier = "racedistancesurfacecoursetable" // setup identifier //racedistancesurfacecoursetableview.rowheight = 20.0 racedistancesurfacecoursetableview.intercellspacing = nssize(width: 1.0, height: 1.0) racedistancesurfacecoursetableview.headerview = importracetableheaders() tablescrollview.documentview = racedistancesurfacecoursetableview //tablescrollview.hasverticalscroller = false //tablescrollview.verticalscroller = nil // turn off vertical scrolling //tablescrollview.verticalscrollelasticity = .none //racedistancesurfacecoursetableview = nstableviewheader //self.addsubview(tablescrollview) raceimportheaderstackview.addview(racedistancesurfacecoursetableview, in: .center) } // mark: construct fields: //configureheaderview() configurestackview() addracenumbertitle(startingpositionx: 0.0) // add race number title addracenumbervalue(startingpositionx: racenumbertitle.frame.origin.x + racenumbertitle.frame.width) //add race number value text field addracequalificationstable(startingpositionx: racenumbervalue.frame.origin.x + racenumbervalue.frame.width) configureracequalificationstable(showracenumbercol: false, showracecodecol: false) } // mark: tableview functions func reloadtableviewdata(identifier: string) { swift.print("manual reload of data identifier \(identifier)") switch identifier { case "racequalificationstable": racequalificationstableview.reloaddata() case "racedistancesurfacecoursetable": racedistancesurfacecoursetableview.reloaddata() default: break } } // mark: delegate/datasources outlets tableviews // race qualification table (the header table) @iboutlet weak var racequalificationsdelegate: nstableviewdelegate? { { return racequalificationstableview.delegate } set { racequalificationstableview.delegate = newvalue } } @iboutlet weak var racequalificationsdatasource: nstableviewdatasource? { { return racequalificationstableview.datasource } set { racequalificationstableview.datasource = newvalue } } // race distance surface course @iboutlet weak var racedistancesurfacecoursedelegate: nstableviewdelegate? { { return racedistancesurfacecoursetableview.delegate } set { racedistancesurfacecoursetableview.delegate = newvalue } } @iboutlet weak var racedistancesurfacecoursedatasource: nstableviewdatasource? { { return racedistancesurfacecoursetableview.datasource } set { racedistancesurfacecoursetableview.datasource = newvalue } } // mark: label outlets @iboutlet var racenumber:string? { { return racenumbervalue.stringvalue } set { racenumbervalue.stringvalue = newvalue! } }
}
Comments
Post a Comment