Subclass NSProgressIndicator

i like to subclass a NSProgressIndicator. I've used this code and i set the Subclass in the Interface Builder:

- (void)drawRect:(NSRect)dirtyRect {
NSRect rect = NSInsetRect([self bounds], 1.0, 1.0);
CGFloat radius = rect.size.height / 2;
NSBezierPath *bz = [NSBezierPath bezierPathWithRoundedRect:rect xRadius:radius yRadius:radius];
[bz setLineWidth:2.0];
[[NSColor blackColor] set];
[bz stroke];

rect = NSInsetRect(rect, 2.0, 2.0);
radius = rect.size.height / 2;
bz = [NSBezierPath bezierPathWithRoundedRect:rect xRadius:radius yRadius:radius];
[bz setLineWidth:1.0];
[bz addClip];
rect.size.width = floor(rect.size.width * ([self doubleValue] / [self maxValue]));

When the app starts its looks like this: App start

But during the copy progress the old bar shows up. During copying

Whats wrong?


It seems that the progress bar's progress is not drawn in drawRect:, so just overriding drawRect: is not enough. However, if you make the progress bar layer backed, you are responsible for doing all the drawing.

From the documentation:

The view class automatically creates a backing layer for you (using makeBackingLayer if overridden), and you must use the view class’s drawing mechanisms.

Check the "Core Animation Layer" in IB or add this to your sub class:

- (void)awakeFromNib {
    [super awakeFromNib];
    [self setWantsLayer:YES];

I followed the above advice (thanks!), but unfortunately discovered that when the NSProgressIndicator was resized, it disappeared, but only on the first viewing (it was inside a drawer).

Rather than try and understand what was happening, I realised you don't actually need the old control, as what I was doing is very simple (a strength indicator that changes color). Just create a subclass of NSView.

So this is it:

@interface SSStrengthIndicator : NSView
/// Set the indicator based upon a score from 0..4
@property (nonatomic) double strengthScore;

@implementation SSStrengthIndicator
- (void)setStrengthScore:(double)strength
    if (_strengthScore != strength) {
        _strengthScore = strength;
        [self setNeedsDisplay:YES];

- (void)drawRect:(NSRect)dirtyRect
    NSRect rect = NSInsetRect([self bounds], 1.0, 2.0);
    double  val = (_strengthScore + 1) * 20;
    if (val <= 40)
        [[NSColor redColor] set];
    else if (val <= 60)
        [[NSColor yellowColor] set];
        [[NSColor greenColor] set];

    rect.size.width = floor(rect.size.width * (val / 100.0));
    [NSBezierPath fillRect:rect];


 ? How to increase height of Yosemite NSProgressIndicator?
 ? UI does not update when main thread is blocked in Cocoa app
 ? UI does not update when main thread is blocked in Cocoa app
 ? UI does not update when main thread is blocked in Cocoa app
 ? dispatch_queue_t still blocking main thread
 ? NSTask blocks main thread
 ? UI not updating in main thread
 ? Keep managedObjectContextDidUnregisterObjectsWithIDs: from blocking main thread
 ? Cocoa: Subclassing NSProgressIndicator on Lion
 ? Cocoa: Subclassing NSProgressIndicator on Lion