8

I've sort of accomplised implementing a custom slider cell that can draw over using images for the scroll bar and knob. The only obstacle that is in the way now is this, when I drag the knob quickly, the images get messed up. I've posted a screen shot.

Screenshot

Here is the code:

#import "customSliderCell.h"
@implementation customSliderCell
- (void)drawKnob:(NSRect)knobRect {

    NSImage * knob = knobImage;
 [[self controlView] lockFocus];
 [knob
 compositeToPoint:NSMakePoint(knobRect.origin.x,knobRect.origin.y+knobRect.size.height)
 operation:NSCompositeSourceOver];

[[self controlView] unlockFocus];
}
- (void)drawBarInside:(NSRect)rect flipped:(BOOL)flipped {
rect.size.height = 8;

    NSRect leftRect = rect;
    leftRect.origin.x=0;
    leftRect.origin.y=2;
    leftRect.size.width = knobrect.origin.x + (knobrect.size.width);
    [leftBarImage setSize:leftRect.size];
    [leftBarImage drawInRect:leftRect fromRect: NSZeroRect operation: NSCompositeSourceOver fraction:1];

    NSRect rightRect = rect;
    rightRect.origin.x=0;
    rightRect.origin.y=2;
    rightRect.origin.x = knobrect.origin.x;
    [rightBarImage setSize:rightRect.size];
    [rightBarImage drawInRect:rightRect fromRect: NSZeroRect operation: NSCompositeSourceOver fraction:1];
}

ah i'm so close. any help regarding as to why this happens and how to solve it will be greatly appreciated, thanks!

Justin Boo
  • 10,132
  • 8
  • 50
  • 71
han
  • 531
  • 5
  • 18

4 Answers4

13

Ok, so it's figured out. apparently the slider was trying to be smart and draw only where the knob has been. so apparently I have to invalidate the rect all the time by overriding setNeedsDisplayInRect in the slider class.

#import "customSlider.h"

@implementation customSlider
-(void)setNeedsDisplayInRect:(NSRect)invalidRect{
    [super setNeedsDisplayInRect:[self bounds]];
}
@end
han
  • 531
  • 5
  • 18
  • 1
    Man, you've just saved me. I was looking for a solution to this exact issue for the last several hours. Thanks! – eploko Sep 30 '11 at 02:23
4

I am a beginner in Objective-c. I also ran into this problem! Here is the solution to find that I spent two days))) Save and restore GraphicsState:

[NSGraphicsContext restoreGraphicsState];
//...
[leftBarImage drawInRect:leftRect fromRect: NSZeroRect operation: NSCompositeSourceOver fraction:1];
//...
[rightBarImage drawInRect:rightRect fromRect: NSZeroRect operation: NSCompositeSourceOver fraction:1];
[NSGraphicsContext saveGraphicsState];

Sorry for bad English.

NSLeader
  • 345
  • 2
  • 10
2

Remove all the -lockFocus and -unlockFocus messages. The framework will take care of setting up the drawing context for you before -drawBarInside:flipped: or -drawKnob: are ever sent.

Also, you shouldn't be creating any objects within a draw method.

NSResponder
  • 16,861
  • 7
  • 32
  • 46
  • Hey thanks NSResponder, i've removed the lock and unlocked and also removed most of the creating object code. however the problem still persists. i'm currently drawing 3 images, left bar, right bar and the knob. It only happens when I move the mouse quickly. If i drag it slow then it draws ok. – han Oct 22 '10 at 01:07
  • Even when I use the private method (which I don't really like) and commented out the left drawing bar. it seems that the same problem still persists if i drag the knob from right to left quickly. And when i release the mouse, then the missing spaces disappear and a nice image is drawn over it. – han Oct 22 '10 at 01:16
1

Ha, it's another story. No, NSResponder is right and you should remove all 'lockFocus' stuff, however, this issue is a result of the default slider bar drawn by the NSSliderCell somewhere outside of the drawBarInside:flipped:flipped. I have faced this issue not so far ago as well.

Here is discussion and solution: http://www.cocoabuilder.com/archive/cocoa/177288-preventing-nsslider-bar-from-drawing.html , in short, you can override whole drawCell:inView: or use a "dirty hack trick" with overriding a private method. I personally don't like hacks, but in this case I did

- (BOOL)_usesCustomTrackImage {
return YES;
}

And it solved the problem for me

Gobra
  • 4,263
  • 2
  • 15
  • 20
  • Hey Gobra, yea i've seen your post before. I've tried that method but it still doesnt work unfortunately :( btw the left side is an image, not the default bar. It was a random image that I grabbed off my computer for testing purposes. – han Oct 22 '10 at 01:10
  • Oh yea, and even if the bar is there, my images seem to be drawn over it and it doesnt really show the bar. – han Oct 22 '10 at 01:19