9

How can you get a indexes of visible rows for an NSOutlineView? I need to know which level and which rows are visible.

[EDIT] What I'm actually looking for is an NSOutlineView equivalent to CocoaTouch/UITableView - (NSArray *)indexPathsForVisibleRows

Cal
  • 1,625
  • 4
  • 20
  • 30

4 Answers4

23

you can do the following:

NSScrollView* scrollView = [self.tableView enclosingScrollView];

CGRect visibleRect = scrollView.contentView.visibleRect;

NSRange range = [self.tableView rowsInRect:visibleRect];

in the range you will get the location as the first visible cell and in the length the amount of cells are shown so you can know the index of the visible cells.

user2067656
  • 426
  • 3
  • 7
  • 1
    Great answer! And then iterate over [self.tableView itemAtRow:range.location] – stevesliva Mar 26 '14 at 20:44
  • 1
    Not sure how this is any different from the answer I posted nearly two and a half years earlier, aside from the unnecessary involvement of the scroll view (you can ask a view directly for its `-visibleRect`) and the fact the OP is asking about an outline view (tree) vs. a table (list)... – Joshua Nozzi Oct 02 '14 at 17:36
13

NSOutlineView is an NSTableView subclass. Therefore -rowsInRect: can be combined with -visibleRect (from NSView). Use -levelForRow: to determine the level.

Andriy
  • 2,767
  • 2
  • 21
  • 29
Joshua Nozzi
  • 60,946
  • 14
  • 140
  • 135
  • Seems like you would have to iterate the model to count up to row number. I don't really want linear time.... Unless I'm missing something? – Cal Jan 19 '11 at 03:35
  • I'm not sure what you mean. You can translate rows to their real objects by itemForRow:, etc. – Joshua Nozzi Jan 19 '11 at 03:51
  • Sorry... My question wasn't detailed enough. I actually want to be able to get a tree coordinates for the visible rows. For example in my case the tree is has two levels so it would have two indexes for the leaf nodes. – Cal Jan 19 '11 at 04:04
  • 1
    Ah. I think I get your meaning. I don't believe there's a direct way to get an NSIndexPath from an item without building it by recursively asking the outline view for the -parentOfItem: until it responds with nil. For the few rows that would be on screen and only two levels deep though, I honestly don't believe you're facing a performance problem. Try then measure. :-) – Joshua Nozzi Jan 19 '11 at 04:09
  • This is also helpful for an `NSTableView` and loading images asynchronously. – Keith Smiley Mar 10 '13 at 00:17
  • 1
    @Cal, the model is iterated only if you have dynamic heights for your rows. Otherwise, getting the rows in a visible rectangle is solved behind the scenes using a simple formula. – Radu Simionescu Feb 26 '15 at 12:54
0

In Swift 3:

let rows = IndexSet(integersIn: 0..<outlineView.numberOfRows)
let rowViews = rows.flatMap { outlineView.rowView(atRow: $0, makeIfNecessary: false) as? RowView }

for rowView in rowViews 
    //iterate over rows
}
J.beenie
  • 861
  • 10
  • 22
  • From the documentation for `.rowView`: "In general, makeIfNecessary should be (...) false if you want to update properties on a view only if it is available (generally this means it is visible)."A visible row is always available. However some rows could be ready to display or have leave the table and be available without being displayed a with this we could get them when we only want the visibles. – João Colaço Mar 04 '19 at 22:31
  • OP asked for *visible* rows – Alan May 15 '23 at 14:39
0

I changed my datasource to return an NSIndexPath for outlineView:child:ofItem:. This way I could use [outlineview rowAtPoint:point] (and similar) to get the NSIndexPath.

This change required me to make a set of these indexPaths so they wouldn't get released until I don't need them. Also, all the other code which normally expected a model object now needs to lookup the model object from the index path. In my case this was efficient.

Cal
  • 1,625
  • 4
  • 20
  • 30