Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get the position of a row from within the visible tableView not the whole tableView

Simply put- I have an NSTableView with a lot of rows. Only about 20 are visible with the rest only visible with scrolling.

I know how to get the row id and the position of the row relative to the entire NSTableView but I need to get the position within the visible view...

That is, if row 1500 is in the visible view, I need it's y coordinate relative to that view, not relative to the entire list of rows.

Can't seem to figure this one out on my own...

Thanks in advance.

like image 594
julian Avatar asked Nov 29 '25 14:11

julian


1 Answers

It's not clear what you mean by “the visible view” (lots of views are visible) or “that view” (the row view? the table view? the scroll view). I guess you want the bounding rectangle of the row, relative to the scroll view's geometry.

Every view defines a geometry (a coordinate system) for the placement of its subviews. A subview's frame is in the geometry of its superview. If you change the geometry of the superview, then on the screen, the subviews appear to move. This is how scroll views work.

An NSScrollView doesn't change its own geometry to scroll the document (in your case, the table). (Note that this is different than iOS, where UIScrollView does change its own geometry to scroll.) The NSScrollView has the scrollers and an NSClipView subview (which it confusingly calls its contentView), and the clip view has the document view (your table view) as its subview:

+ NSScrollView
  |
  +-- NSScroller (the scroll view's horizontalScroller)
  |
  +-- NSScroller (the scroll view's verticalScroller)
  |
  +-- NSClipView (the scroll view's contentView)
      |
      +-- NSTableView (the scroll view's documentView, but not a direct subview of it)
          |
          +-- NSTableRowView
          |
          +-- NSTableRowView
          |
          +-- NSTableRowView
          |
          +-- NSTableRowView
          |
          ...

If the table view has 5000 rows, and the table view's rowHeight is 17 (the default), and the table view's intercellSpacing.height is 2 (the default), then the table view's frame.size.height will be 5000 * (17+2) = 95000. The frame.origin.y of the row view for row number i is 19 * i. Row view 0's frame.origin.y is 0 and row view 4999's frame.origin.y is 94981. But these y coordinates don't necessarily have anything to do with where the rows appear relative to the scroll view or the enclosing window or the screen!

To scroll the table, the scroll view adjusts the geometry of its clip view by setting the clip view's bounds.origin. Remember that the scroll view's contentView property points to the clip view. To scroll horizontally, the scroll view changes contentView.bounds.origin.x, and to scroll vertically, the scroll view changes contentView.bounds.origin.y. This has the effect of moving the table view (and all its subviews) relative to the scroll view, the enclosing window, and the screen.

So, you can get the rectangle enclosing a row by asking the table view, for example like this:

CGRect tableViewRowRect = [self.tableView rectOfRow:1500];

The rectangle returned by -[NSTableView rectOfRow:] is in the geometry of the table view; it is relative to the table view's origin, which (if the table view has been scrolled) may be far off the screen.

If you want the rectangle of the row relative to the scroll view, convert it like this:

NSScrollView *scrollView = self.tableView.enclosingScrollView;
CGRect scrollViewRowRect = [self.tableView convertRect:tableViewRowRect
    toView:scrollView];

If you want the rectangle of the row relative to the enclosing window's content view, you can convert to that view:

NSView *rootView = self.tableView.window.contentView;
CGRect rootViewRowRect = [self.tableView convertRect:tableViewRowRect
    toView:rootView];

If you want the rectangle in the window's base coordinate system (for example, to compare to a mouse event's locationInWindow), you can do that too:

CGRect windowRowRect = [self.tableView convertRect:tableViewRowRect
    toView:nil];

And if you want the rectangle in NSScreen coordinates (for example, to compare to a window's frame), you can even do that:

NSWindow *window = self.tableView.window;
CGRect screenRowRect = [window convertRectToScreen:windowRowRect];
like image 118
rob mayoff Avatar answered Dec 02 '25 03:12

rob mayoff



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!