NSTableView updating

I have an NSTableView which shows the longitude and latitude points of objects on a map. Some objects, like trails, have many rows in the table. When I change objects I want to update the NSTableView and then select row 0. I tried

[obectCoordTable reloadData];

[objectCoordTable selectRowIndexes: [NSIndexSet indexSetWithIndex: 0] byExtendingSelection: NO];


This does not work because reloadData does not reload the table. It only schedules a reload for some time later

(on next iteration of Main Loop?). So my attempt to select row 0 happens first. Then just before the table

data are reloaded a (void)tableViewSelectionDidChange: happens with selected row reset to -1. So my

selection of row 0 is ineffective.


How do I select row 0 after the reload is finished? There seems to be no delegate method to notify the user

when a complete data reload is completed.


Do I have to schedule the selectRowIndexes for execution at a later time and hope it is after the data reload? That might work but seems a bit too hokey?


Thanks.


Richard Stover

Answered by RJStover in 424109022

Unfortunately NSTableView does not respond to layoutIfNeeded. But your suggestion led me into looking

at other possibilities.


Instead of doing the selectRowIndexes: after the reloadData I set a BOOL flag, needsReselect.


Then in the delegate tableView:objectValueForTableColumn:row: method I put this code:

// If we are updating the table content at row 0 and we need to reset the selection to row 0

// then do that now.   

if ((rowIndex == 0) && needsReselect) {


          // Select row 0.

          [objectCoordTable selectRowIndexes: [NSIndexSet indexSetWithIndex: 0] byExtendingSelection: NO];


          // Get the rectangle for the table contents.

          CGRect r = objectCoordTable.superview.layer.contentsRect;


          // Narrow the rect to an area that is part of row 0.

          NSRect row0 = NSMakeRect(0.0, r.size.height - 10.0, r.size.width, 5.0);


          // Scroll to that rect

          [objectCoordTable.superview scrollRectToVisible:row0];

          needsReselect = NO;

     }

This seems a little more obvious that using a dispatch queue and it seems to work. Note that I had to explicitly reset

the scroll as well. I checked, and if I'm not in the middle of the tableView:objectValueForTableColumn: the scoll

adjusts without need to control it explicitly.


It would be nice if there was a delegate method to mark the end of a reloadData, or an NSNotification about it.


Thanks for the help.

Do I have to schedule the selectRowIndexes for execution at a later time and hope it is after the data reload?

No. You need to have something deterministic.


A solution could be to force redraw, by foring layout for instance.

Or to put the index selection in a dispatch queue.


See discussion here (that's UIKit but will give hints).

https://stackoverflow.com/questions/16071503/how-to-tell-when-uitableview-has-completed-reloaddata

Accepted Answer

Unfortunately NSTableView does not respond to layoutIfNeeded. But your suggestion led me into looking

at other possibilities.


Instead of doing the selectRowIndexes: after the reloadData I set a BOOL flag, needsReselect.


Then in the delegate tableView:objectValueForTableColumn:row: method I put this code:

// If we are updating the table content at row 0 and we need to reset the selection to row 0

// then do that now.   

if ((rowIndex == 0) && needsReselect) {


          // Select row 0.

          [objectCoordTable selectRowIndexes: [NSIndexSet indexSetWithIndex: 0] byExtendingSelection: NO];


          // Get the rectangle for the table contents.

          CGRect r = objectCoordTable.superview.layer.contentsRect;


          // Narrow the rect to an area that is part of row 0.

          NSRect row0 = NSMakeRect(0.0, r.size.height - 10.0, r.size.width, 5.0);


          // Scroll to that rect

          [objectCoordTable.superview scrollRectToVisible:row0];

          needsReselect = NO;

     }

This seems a little more obvious that using a dispatch queue and it seems to work. Note that I had to explicitly reset

the scroll as well. I checked, and if I'm not in the middle of the tableView:objectValueForTableColumn: the scoll

adjusts without need to control it explicitly.


It would be nice if there was a delegate method to mark the end of a reloadData, or an NSNotification about it.


Thanks for the help.

Thanks for feedback. Don't forget to close the thread.

NSTableView updating
 
 
Q