i have two table views where you can drag a row from table A to table B.
this works fine.
but i need to know, which row number will dragged from table A.
This is my code of table A and the problem, too:
func tableView(_ tableView: NSTableView, writeRowsWith rowIndexes: IndexSet, to pboard: NSPasteboard) -> Bool {
pboard.declareTypes([NSStringPboardType],owner: nil)
pboard.setString(persons[0].objectID.uriRepresentation().absoluteString, forType: NSStringPboardType)
return true
}
at the moment i always dragged the first element of "persons"
i need a solution where i can set a row number (or something like this) instead of the static "persons[0]".
is there an way for this?
Have you tried persons[rowindexes.first] ?
Related
I'm trying to craft a view based tableView delegate method to alter a column's font IFF its identifier is 'name' and its value matches some global; otherwise the the nib should prevail. I think I have either a noob setup issue or my logic is omitting something.
I have two tables, one view based (tag=0), one cell (tag=1), and both have the same view controller as their delegate. Each tableView's has a unique tag and identifier, an array controller for column value bindings, and each of fits columns has an explicit unique identifier - matching its binding; I had tried omitting this - "the automatic setting" - but this yielded no data!?
So, I added this method, but both tableViews call into it; I would expect only the first. The 2nd table is a detail of the 1st, having its 1st array controller selection.
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
let item = ((tableView.dataSource as! NSArrayController).arrangedObjects as! [AnyObject])[row]
var view = tableView.makeView(withIdentifier: tableColumn!.identifier, owner: self)
if view == nil {
Swift.print("tag: \(tableView.tag) ident: \(tableColumn!.identifier.rawValue)")
view = NSTableCellView.init()
view?.identifier = tableColumn?.identifier
}
guard tableView.tag == 0 else { return view }
guard isGlobalPlist, item.name == '<some-global-string>',
let identifier = tableColumn?.identifier,
identifier.rawValue == "name" else { return view }
if let cellView = view as? NSTableCellView {
if tableView.selectedRowIndexes.intersection(IndexSet.init(integer: row)).count > 0 {
cellView.textField?.font = .boldSystemFont(ofSize: -1)
cellView.textField?.textColor = .white
}
else
{
cellView.textField?.font = .systemFont(ofSize: -1)
cellView.textField?.textColor = .blue
}
}
return view
}
Firstly I notice that the method is called for the 2nd table when I wouldn't have expect it, it being a cell based tableView.
Anyway, I do create the cell when nil return, the docs cite that you need just need to matchup the identifiers:
Note that a cell view’s identifier must be the same as its table column’s identifier for bindings to work. If you’re using bindings, it’s recommended that you use the Automatic identifier setting in Interface Builder.
which I do; both tableView's columns are bound (view, or cell) to their respective array controller using column identifier explicitly entered.
Anyway the original intent I was after was for the view based (1st) tableView:
the view controller was controlling a global resource (isGlobalPlist is true)
the row's 'name' value matches a global value value
to the affect 'name' cell shown in distinct color (blue/yellow - or something) depending on whether the row was selected due to selection highlighting, dark mode etc conditions.
So there would be 1 of 4 possibilities
selected row, matching global -> fore:yellow, back:default
selected row, not matching global -> fore:default, back:default
non-selected row, matching global -> fore:blue, back:default
non-selected row, not matching global -> fore:default, back:default
If the target row matched requirements, the coloring needs to vary depending on its inclusion in the tableView's selected indexes.
The setting seems to properly affect initially - selected row and matching value, but then settings seem to bleed across other rows navigated to - so the selection change. At most there should be 1 row's name column with this affect.
I can't tell if my logic or setup is wrong; I suspect I probably need to refresh as I move about ?
Well I gave up on a view based solution but this fills my need; a cell based solution:
func tableView(_ tableView: NSTableView, dataCellFor tableColumn: NSTableColumn?, row: Int) -> NSCell? {
guard let column = tableColumn else { return nil }
let item : AnyObject = ([table0ArrayController,table1ArrayController][tableView.tag]?.arrangedObjects as! [AnyObject])[row]
let cell : NSTextFieldCell = column.dataCell(forRow: row) as! NSTextFieldCell
cell.textColor = .textColor
guard tableView.tag == 0, isGlobalPlist, item.name == '<some-global-string>' else { return cell }
if tableView.selectedRowIndexes.intersection(IndexSet.init(integer: row)).count > 0 {
cell.textColor = .white
}
else
{
cell.textColor = .blue
}
return cell
}
I wanted to call attention to specific row(s) with color, unless row was selected for the 'name' column only.
I have subclassed NSTableView and NSTableColumn, and I want to control processus of edition of the cells of the table.
I have 2 states for my table class: edition and nonedition.
whatever the state of the table, when the user select a row, the row has to be overlighted.
if the table is in state edition, the controls corresponding to the selected row must be visible.
I use the function rowview to make this possible, but I have no success.
1 when I click on the text cell of a cell, the control appears always.
2 when the rowview function is called, I don't understand the value of the row parameter. Sometimes it is correct, sometimes it is incorrect.
is it someone who could hep me?
I want to make precision: to simplyfy, in my subclassed NSTableView, I write this code:
override func rowView(atRow row: Int, makeIfNecessary: Bool) -> NSTableRowView? {
let aRow = super.rowView (atRow: row, makeIfNecessary: makeIfNecessary)
if aRow != nil {
Swift.print("rowview is called for row (row)")
}
return aRow
}
When I click on row 0, I have the following result: "rowview is called for row 1"
Then when I click on row 1: "rowview is called for row 1 rowview is called for row 0 rowview is called for row 2"
I have a single column, view-based NSTableView in which I want to place two different custom cell views, one alternating with the other in each row, like so:
Odd rows: OddRowNumberCellView.
Even rows: EvenRowNumberCellView.
There a solution for iOS from Natasha in her highly rated answer UITableview with more than One Custom Cells with Swift but it depends on the Dynamic Prototypes setting in the Attributes Inspector, a feature that is not available for MacOS.
Does anyone know how to do this on Mac please? (I'm on macOS Sierra 10.12.4.)
You do exactly the same but instead of Dynamic Protoypes you set an Identifier "OddRow" or "EvenRow" and then in your datasource implementation:
if indexPath.row % 2 == 0 {
let cellView: tableView.make(withIdentifier: "EvenRow")
//set the data here
return cellView
} else {
let cellView: tableView.make(withIdentifier: "OddRow")
//set the data here
return cellView
}
I'm having trouble accessing an optional string in swift from a table view cell. Each cell has a title label as well as a detail text label and the amount of cells at any given time in the table view is dependent on the user (the table view is used to display saved values). Since the strings saved as the detail text label's text in each cell are way too long to read in the table view, I wish to load them in another view that is segued to when a cell is pressed. This is my prepare for segue method:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "cellSegue"
{
let cell = tableView.cellForRowAtIndexPath(tableView.indexPathForSelectedRow()!)
var transfer : ExplanationView = segue.destinationViewController as ExplanationView
if let unwrapped = cell?.textLabel?.text!
{
transfer.infoText.text = unwrapped
}
}
}
When a segue is performed, I get a fatal crash, the offending line is "transfer.infoText.text = unwrapped" and Xcode tells me it found nil when unwrapping an optional. During my debuggingg efforts, I've tried "println(cell?.textLabel?.text!)" and Xcode prints "Optional(String)" where "String" is the actual string I'm trying to access so it seems like I'm on the right track, but obviously there's something I'm missing. I've also tried "cell?.textLabel?.text" but I get the same error. Any help is appreciated
You shouldn't ever extract data from a view. You should extract data from a model. The fact that you have a tableView with cells implies you have a model for the data that goes in those cells. It might be an array of strings or whatever. Instead of trying to extract the data from the cells, just get the data from the data model you used to populate the cells. Something like:
let selectedIndexPath = tableView.indexPathForSelectedRow()
let selectedData = data[selectedIndexPath.row]
Your problem is not unwrapped but instead transfer.infoText.text. Your IBOutlets are not set up at the time of the prepareForSegue. You need add a property (var) to your destination view controller to hold the unwrapped value. Then in viewDidLoad when the IBOutlets are set up, copy the string to your text field.
I'd like to programatically select a row in my NSTableView, with just one column.
func selectColumnIndexes(_ indexes: NSIndexSet!,
byExtendingSelection extend: Bool)
I have been playing around with this, but I am not sure how to write "Select row #2".
Do I have to start with the variable connected to the #IBOutlet of my Table View? I have to indicate it is about my NSTableView somehow.
Thanks!
#Isaiah answer in Swift 3.0:
.selectRowIndexes(NSIndexSet(index: 0) as IndexSet, byExtendingSelection: false)
Okay, I've got it. It turned out to be
#IBOutlet weak var NoteTableView: NSTableView!
NoteTableView.selectRowIndexes(NSIndexSet(index: 0), byExtendingSelection: false)
I couldn't quite figure out the part with NSIndexSet. I was fiddling around with init(), which turned out to be unnecessary.
Swift 4 Solution
I created an extension to make a little easier to do this. Also if you implemented a click action on the table view cell this will invoke it as well
extension NSTableView {
func selectRow(at index: Int) {
selectRowIndexes(.init(integer: index), byExtendingSelection: false)
if let action = action {
perform(action)
}
}
}
/// USAGE:
NSTableView().selectRow(at: 0)