Re: NSTableView and scrollToPoint:
Re: NSTableView and scrollToPoint:
- Subject: Re: NSTableView and scrollToPoint:
- From: Kyle Sluder <email@hidden>
- Date: Sun, 20 Nov 2011 13:14:38 -0800
(Reposted to the list, with permission.)
On Sun, Nov 20, 2011 at 2:59 AM, Peter Hudson <email@hidden> wrote:
>
> Thanks for the test app Kyle - I've run it and it works as you say.
> I suspect my difficulty lies somewhere I have not thought of.
> Attached is a frame shot of the tables on the screen.
> This screen is composed of three different tables
> - one for the dates,
> - one for the line items on the left hand side and
> - one for the data ( contains SW etc )
> The date range can be typically 40 days - so the date and data table would be 40 cols wide.
> The number of line items is typically 100.
> As the user scrolls around the data table, the line item table and the dates table are kept in sync with the appropriate rows / columns ( i.e. date and line item ).
Okay, I suspect you're using two table views in the data area so that
you can keep the left column "frozen" on screen while you scroll all
the other columns.
> These table are subclasses of NSTableView. Not a lot goes on in the sub classes. The main reason to sub class is to have access to adjustScroll:
One might think that mentioning an override of -adjustScroll: would be
relevant information when asking a question about scrolling. ;-)
> The data table implementation looks like this :-
> -(NSRect)adjustScroll:(NSRect)proposedVisibleRect
> {
>
>
>
> NSRect r;
>
>
>
> r = proposedVisibleRect;
> r.origin.y = 0.0;
> [[[dateTableViewRef enclosingScrollView] contentView] scrollToPoint:r.origin]; // Date view
>
>
>
> r = proposedVisibleRect;
> r.origin.x = 0.0;
> [[[categoryItemsTableViewRef enclosingScrollView] contentView ] scrollToPoint:r.origin]; // category / items
>
>
>
> return proposedVisibleRect;
>
>
>
> }
You're misusing -adjustScroll: here, and your implementation contains
a bug that is causing your behavior. The purpose of -adjustScroll is
to improve the user experience by changing the amount scrolled when
scrolling by "line". Check out the Scroll View Programming Guide:
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/NSScrollViewGuide/Articles/Scrolling.html
In particular, pay attention to this note at the end of the section
"Scrolling to a particular location": "The low-level scrolling methods
bypass the adjustScroll: mechanism described in “Constraining
Scrolling.”"
As for the bug: you're using -scrollToPoint: when you mean to be using
-[NSView scrollPoint:] or -[NSScrollView scrollRectToVisible:]. As I
mentioned before, these methods are confusingly-named, but they all
have their individual purpose.
Since you're trying to synchronize scroll views, I should remind you
that Apple has an example of doing just that in the "Synchronizing
Scroll Views" chapter of the Scroll View Programming Guide:
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/NSScrollViewGuide/Articles/SynchroScroll.html
Since you have three views, instead of putting the notification
observer inside the views and pointing their synchronizedScrollView
properties at each other, I'd instead put the implementation in my
window controller subclass, and start observing the clip views in
-awakeFromNib (WARNING: this code was typed directly into Mail and not
tested AT ALL):
// MyWindowController.m
@synthesize dateHeaderTableView, lineItemTableView, dataTableView; //
IBOutlets hooked up to the table views
- (void)awakeFromNib {
NSNotificationCenter *cen = [NSNotificationCenter defaultCenter];
NSClipView *dateHeaderClipView = [[dateHeaderTableView
enclosingScrollView] contentView];
[dateClipView setPostsBoundsChangedNotifications:YES];
[cen addObserver:self selector:@selector(dateHeaderScrolled:)
name:NSViewBoundsDidChangeNotification object:dateClipView];
NSClipView *lineItemClipView = [[lineItemTableView
enclosingScrollView] contentView];
[lineItemClipView setPostsBoundsChangedNotifications:YES];
[cen addObserver:self selector:@selector(lineItemScrolled:)
name:NSViewBoundsDidChangeNotification object:lineItemClipView];
NSClipView *dataClipView = [[dataTableView enclosingScrollView] contentView];
[dataClipView setPostsBoundsChangedNotifications:YES];
[cen addObserver:self selector:@selector(dataScrolled:)
name:NSViewBoundsDidChangeNotification object:dataClipView];
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
- (void)dateHeaderScrolled:(NSNotification *)note {
NSClipView *dateHeaderClipView = [note object];
NSPoint currentDataOrigin = [dataTableView bounds].origin;
NSPoint newDataOrigin = {
.x=[dateHeaderClipView documentVisibleRect].origin.x,
.y=currentDataOrigin.y
};
if (!NSEqualPoints(currentDataOrigin, newDataOrigin))
[dataTableView scrollPoint:newDataOrigin];
}
- (void)lineItemScrolled:(NSNotification *)note {
NSClipView *lineItemClipView = [note object];
NSPoint currentDataOrigin = [dataTableView bounds].origin;
NSPoint newDataOrigin = {
.x=currentDataOrigin.x,
.y=[lineItemClipView documentVisibleRect].origin.y
};
if (!NSEqualPoints(currentDataOrigin, newDataOrigin))
[dataTableView scrollPoint:newDataOrigin];
}
- (void)dataScrolled:(NSNotification *)note {
NSClipView *dataClipView = [note object];
NSPoint currentDateHeaderOrigin = [dateHeaderTableView bounds].origin;
NSPoint newDateHeaderOrigin = {
.x=[dataClipView documentVisibleRect].origin.x,
.y=currentDateHeaderOrigin.y
};
if (!NSEqualPoints(currentDateHeaderOrigin, newDateHeaderOrigin))
[dateHeaderTableView scrollPoint:newDateHeaderOrigin];
NSPoint currentLineItemOrigin = [lineItemTableView bounds].origin;
NSPoint newLineItemOrigin = {
.x=currentLineItemOrigin.x,
.y=[lineItemClipView documentVisibleRect].origin.y,
};
if (!NSEqualPoints(currentLineItemOrigin, newLineItemOrigin))
[dateHeaderTableView scrollPoint:newLineItemOrigin];
}
Hopefully that's not _too_ buggy for a first approximation. The
general strategy is obviously to scroll the other to views when the
third scrolls.
--Kyle Sluder
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden