25

I'm dynamically adding rows to an NSTableView. When I issue [table reloadData] I can see the scroll view move and if I move it by hand I can see the new value on the table. But how can I scroll it automatically?

ruipacheco
  • 11,526
  • 14
  • 63
  • 116

4 Answers4

44
NSInteger numberOfRows = [tableView numberOfRows];

if (numberOfRows > 0)
    [tableView scrollRowToVisible:numberOfRows - 1];

Assuming you're adding rows to the end of the table.

(The reason I ask the table view for the number of rows instead of the data source is that this number is guaranteed to be the number of rows it knows about and can scroll to.)

Wevah
  • 27,760
  • 7
  • 81
  • 68
  • 4
    Somehow (on the latest XCode and SDK) this causes the tableView scroll to the cell *just before* the newly added cell (added at the end of the tableView). Can't figure out why. – SpacyRicochet Feb 05 '14 at 11:38
  • It might depend on how soon you call it; maybe try adding `[tableView noteNumberOfRowsChanged];` before it. – Wevah Feb 05 '14 at 13:15
  • Thanks, will try that. Right now I got it working by putting `[tableView reloadData]` in front of it. – SpacyRicochet Feb 06 '14 at 13:00
19

Use something like this:

 [table scrollRowToVisible:indexOfNewRow];
Frank Schmitt
  • 24,850
  • 8
  • 56
  • 69
  • +1 because this way handles the usual case where table sorting means that the new row isn't necessarily at the bottom of the table. – Abizern Nov 26 '09 at 19:18
1

I solved it as shown below, using the didAddRowView to work properly: Obviously, if I add a new record, the tableview needs to create a new row view.

- (void)tableView:(NSTableView *)tableView  didAddRowView:(NSTableRowView *)rowView forRow:(NSInteger)row {
// it sends notification from all tableviews.
// I am only interested in the dictionary...

if (tableView == dictTableView){
    if ( row == [dictTableView numberOfRows]-1){
        [dictTableView scrollRowToVisible:row];
    }
}

}

But also, in my IBAction I added 2 lines after performing the add statement to the controller

- (IBAction)addNewDictItem:(id)sender {
NSInteger row=[[theDictArrayController arrangedObjects]count];

[theDictArrayController add:sender];
[dictTableView noteNumberOfRowsChanged];
[dictTableView scrollRowToVisible:row-1];

}

0

A improved solution to my previous one is shown below. Catching the "didAddRow" event is probably still too early, so that the new row (to scroll to...) is not available yet.

First, create your own "add" action , keep a flag as reminder and call the controller's add action.

-(IBAction)addNewDictItem:(id)sender {
   [theDictArrayController add:sender];
   dictElementAdded=TRUE;
 }

Now, when the controller adds an object, it selects this object automatically. Just "hop on" this event by catching the notification from the tableview. Nice thing about it: lines and views are created before, and the new row is ready to be selected.

-(void)tableViewSelectionDidChange:(NSNotification *)aNotification {
NSTableView * tableView=[aNotification object];

if (dictElementAdded && tableView == dictTableView  ){
    NSInteger   row= [[tableView selectedRowIndexes ] firstIndex ];        
        [dictTableView scrollRowToVisible:row];
        dictElementAdded = FALSE;
 }
}