reloadData in NSTableView but keep current selection
Asked Answered
L

5

21

I have anNSTableView showing the contents of a directory. I watch for FSEvents, and each time I get an event I reload my table view. Unfortunately, the current selection then disappears. Is there a way to avoid that?

Legpull answered 6/6, 2011 at 5:55 Comment(0)
W
6

It depends on how you populate your NSTableView.

If you have the table view bound to an NSArrayController, which in turn contain the items that your table view is displaying, then the NSArrayController has an option to preserve the selection. You can select it (or not) from within Interface Builder as a property on the NSArrayController. Or you can use the setPreservesSelection method in code.

However, if you completely replace the array of items that the NSArrayController manages each time you get your FSEvents, then maybe the preservation of selection cannot work. Unfortunately the Apple docs on this property of NSArrayController are a bit vague as to when it can and cannot preserve the selection.

If you are not using an NSArrayController, but maybe using a dataSource to populate the table view, then I think you'll have to manage the selection yourself.

Wakeen answered 9/6, 2011 at 0:46 Comment(2)
Thanks for the explanation. I am really thinking to use an NSArrayControllerLegpull
I found setPreservesSelection to be highly unreliable. Sometimes it works, sometimes it doesn’t.Alessi
A
14

Well, you can save selection before calling reloadData and restore it after that.

NSInteger row = [self.tableView selectedRow];
[self.tableView reloadData];
[self.tableView selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:NO];

This worked for me in some cases. But if you insert some items BEFORE the selected row, you should andjust your row variable by adding count of added items to it.

Accrete answered 29/11, 2012 at 10:38 Comment(1)
What is the behavior if the selected index is no longer valid (larger than the number of items) after the data is reloaded?Cromlech
E
12

Swift 4.2

Create an extension and add a method which preserves selection.

extension NSTableView {

    func reloadDataKeepingSelection() {
        let selectedRowIndexes = self.selectedRowIndexes
        self.reloadData()
        self.selectRowIndexes(selectedRowIndexes, byExtendingSelection: false)
    }
}

Do this in case you use the traditional way of populating table views (not NSArrayController).

Emogeneemollient answered 28/12, 2016 at 16:52 Comment(1)
small note, this will select the first & previous selected item, set "byExtendingSelection" to false if you only want the previously selected itemHilaire
W
6

It depends on how you populate your NSTableView.

If you have the table view bound to an NSArrayController, which in turn contain the items that your table view is displaying, then the NSArrayController has an option to preserve the selection. You can select it (or not) from within Interface Builder as a property on the NSArrayController. Or you can use the setPreservesSelection method in code.

However, if you completely replace the array of items that the NSArrayController manages each time you get your FSEvents, then maybe the preservation of selection cannot work. Unfortunately the Apple docs on this property of NSArrayController are a bit vague as to when it can and cannot preserve the selection.

If you are not using an NSArrayController, but maybe using a dataSource to populate the table view, then I think you'll have to manage the selection yourself.

Wakeen answered 9/6, 2011 at 0:46 Comment(2)
Thanks for the explanation. I am really thinking to use an NSArrayControllerLegpull
I found setPreservesSelection to be highly unreliable. Sometimes it works, sometimes it doesn’t.Alessi
J
6

In the case of using Data Source, Apple Documentation in the header file on reloadData() is that

The selected rows are not maintained.

To get around, you can use reloadDataForRowIndexes(rowIndexes: NSIndexSet, columnIndexes: NSIndexSet). As mentioned in the same header file

For cells that are visible, appropriate dataSource and delegate methods will be called and the cells will be redrawn.

Thus the data will be reloaded, and the selection is kept as well.

Juanitajuanne answered 19/2, 2016 at 7:44 Comment(0)
A
4

A variant on @silvansky's answer.

This one has no need to keep track of count of items inserted/deleted. And it maintains multiple selection.

The idea is to...
1. create an array of selected objects/nodes from the current selection.
2. refresh the table using reloadData
3. for each object obtained in step 1, find/record it's new index
4. tell the table view/outline view to select the updated index set

- (void)refresh {
    // initialize some variables
    NSIndexSet *selectedIndexes = [self.outlineView selectedRowIndexes];
    NSMutableArray *selectedNodes = [NSMutableArray array];
    NSMutableIndexSet *updatedSelectedIndex = [NSMutableIndexSet indexSet];

    // 1. enumerate all selected indexes and record the nodes/objects
    [selectedIndexes enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
        [selectedNodes addObject:[self.outlineView itemAtRow:idx]];
    }];

    // 2. refresh the table which may add new objects/nodes
    [self.outlineView reloadData];

    // 3. for each node in step 1, find the new indexes
    for (id selectedNode in selectedNodes) {
        [updatedSelectedIndex addIndex:[self.outlineView rowForItem:selectedNode]];
    }

    // 4. tell the outline view to select the updated index set
    [self.outlineView selectRowIndexes:updatedSelectedIndex byExtendingSelection:NO];
}
Ailbert answered 22/4, 2015 at 0:28 Comment(3)
Brad, Did you try this? reloadData is lazily loaded so you won't have the updated data after the call. To test try this code after a drag / move operation which changes the order of the rows. I don't think it will produce the desired result.Carilla
@SteveSheldon I do recall this working, but unfortunately this project no longer runs so I cannot test anymore.Ailbert
@SteveSheldon, I think this works; I have used a similar technique; and if I recall, Apple's docs even mention this. Which updated data are you referring to? and after which call?Insistent

© 2022 - 2024 — McMap. All rights reserved.