views:

35

answers:

1

I'm trying to subclass NSScroller in order to draw my own scroller knob. To do this, I've subclassex NSScrollView and usex the following code to instantiate my custom NSScrollers:

- (void)awakeFromNib;
{
    NSRect horizontalScrollerFrame = [[self horizontalScroller] frame];
    NSRect verticalScrollerFrame = [[self verticalScroller] frame];
    NSString *scrollBarVariant = [[[NSUserDefaults standardUserDefaults] persistentDomainForName:NSGlobalDomain] valueForKey:@"AppleScrollBarVariant"];

    if (![scrollBarVariant isEqualToString:@"DoubleBoth"]) {
        [self setVerticalScroller:[[[TRScroller alloc] initWithFrame:verticalScrollerFrame] autorelease]];
        [self setHorizontalScroller:[[[TRScroller alloc] initWithFrame:horizontalScrollerFrame] autorelease]];
    }
}

This works and my NSScrollers display correctly. But I'm occasionally seeing rendering issues upon first loading my application. Within Interface Builder I have laid out a number of NSScrollViews with their scrollbars set to hide automatically. The issue I'm seeing is that when the application first loads, the scrollbar backgrounds are rendered across the NSScrollViews contents.

alt text

I believe this is because I instantiate my NSScroll subclass (TRSubclass) via awakeFromNib, which means that the scrollbars are given the frame of the NSScrollView before it is automatically resized to meet the windows saved location and size (in other words, it's using the frame that's assigned by default within Interface Builder). What's the best way around this?

I've tried forcing the NSScrollView to redisplay (using setNeedsDisplay: and display:) but with no luck. Has anyone else come across a similar issue?

+1  A: 

I'm using the same schema in my applications and I fighted this issues a lot. I use the same trick: scrollers are substituted in [scrollView awakeFromNib] methods, but I don't face such rendering issues at the moment. You can try to play with "draws background" property of the NSScrollView - it really helps sometimes

- (void)changeSubs
{
    // change clip view
    // ...

    // change scrollers
    NSRect horizontalScrollerFrame = [[self horizontalScroller] frame];
    NSRect verticalScrollerFrame = [[self verticalScroller] frame];
    if (![[self verticalScroller] isKindOfClass:[CRScroller class]])
        [self setVerticalScroller:[[[CRScroller alloc] initWithFrame:verticalScrollerFrame] autorelease]];
    if (![[self horizontalScroller] isKindOfClass:[CRScroller class]])
        [self setHorizontalScroller:[[[CRScroller alloc] initWithFrame:horizontalScrollerFrame] autorelease]];
}

- (id)initWithFrame:(NSRect)frame
{
    self = [super initWithFrame:frame];
    if (self)
    {
    [self changeSubs];
    }
    return self;
}

- (id)initWithCoder:(NSCoder *)aDecoder
{
    NSKeyedUnarchiver* unpacker = (id)aDecoder;
    [unpacker setClass:[CRClipView class] forClassName:[NSClipView className]];
    [unpacker setClass:[CRScroller class] forClassName:[NSScroller className]];

    self = [super initWithCoder:aDecoder];
    if (self)
    {
    }
    return self;
}

- (void)awakeFromNib
{
    [self changeSubs];
}

There are few tricks here, they work depending on a way NSScrollView is created. 'isKindOfClass' check helps to avoid double-swap.

Gobra
Turning off "Draws Background" on my NSScrollViews has no effect, unfortunately. I'd be interested in seeing your code, in any case.
ndg
I have edited my post, check the code. As for "draws background" option - it should be turned ON. And it also matters what background color is set, have you changed NSClipView instance inside the scroll view (actually it's clip view that renders the background) etc.
Gobra