How to make NSTableView scroll to most recently added row?
Asked Answered
W

4

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?

Warder answered 25/11, 2009 at 20:27 Comment(0)
D
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.)

Disulfiram answered 25/11, 2009 at 20:40 Comment(3)
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.Prolocutor
It might depend on how soon you call it; maybe try adding [tableView noteNumberOfRowsChanged]; before it.Disulfiram
Thanks, will try that. Right now I got it working by putting [tableView reloadData] in front of it.Prolocutor
B
20

Use something like this:

 [table scrollRowToVisible:indexOfNewRow];
Barocchio answered 25/11, 2009 at 20:34 Comment(1)
+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.Pinkiepinkish
N
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];

}

Neckerchief answered 12/6, 2016 at 13:45 Comment(0)
N
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;
 }
}
Neckerchief answered 17/3, 2017 at 17:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.