Search code examples
macoscocoasubclassnsbuttonnsbuttoncell

Custom NSButtonCell, drawBezelWithFrame not called


I'm trying to figure out how to custom draw Buttons in Cocoa/OSX. Since my view is custom drawn I will not use IB and want to do it all in code. I created a subclass of NSButtonCell and a subclass of NSButton. In the Subclass of NSButtonCell I override the Method drawBezelWithFrame:inView: and in the initWithFrame Method of my subclassed NSButton I use setCell to set my CustomCell in the Button. However, drawBezelWithFrame gets not called and I don't understand why. Can someone point out what I've done wrong or what I miss here?

Subclass of NSButtonCell:

#import "TWIButtonCell.h"

@implementation TWIButtonCell

-(void)drawBezelWithFrame:(NSRect)frame inView:(NSView *)controlView
{
    //// General Declarations
[[NSGraphicsContext currentContext] saveGraphicsState];

    //// Color Declarations
    NSColor* fillColor = [NSColor colorWithCalibratedRed: 0 green: 0.59 blue: 0.886 alpha: 1];

    //// Rectangle Drawing
    NSBezierPath* rectanglePath = [NSBezierPath bezierPathWithRect: NSMakeRect(8.5, 7.5, 85, 25)];
    [fillColor setFill];
    [rectanglePath fill];
    [NSGraphicsContext restoreGraphicsState];
}

@end

Subclass of NSButton:

#import "TWIButton.h"
#import "TWIButtonCell.h"

@implementation TWIButton

- (id)initWithFrame:(NSRect)frame
{
    self = [super initWithFrame:frame];
    if (self)
    {
        TWIButtonCell *cell = [[TWIButtonCell alloc]init];
        [self setCell:cell];
    }

    return self;
}

- (void)drawRect:(NSRect)dirtyRect
{
    // Drawing code here.
}

@end

Usage:

- (void)addSendButton:(NSRect)btnSendRectRect 
{
    TWIButton *sendButton = [[TWIButton alloc] initWithFrame:btnSendRectRect];
    [self addSubview:sendButton];
    [sendButton setTitle:@"Send"];
    [sendButton setTarget:self];
    [sendButton setAction:@selector(send:)];
}

Solution

  • Following are the things seems to be missing out from your code.

    1. You are not calling the [super drawRect:dirtyRect]
    2. You are not overriding + (Class)cellClass in the Class(TWIButton) which is derived from NSButton.

    Below is the code after changes:

    @implementation TWIButton
    
        - (id)initWithFrame:(NSRect)frame
        {
            self = [super initWithFrame:frame];
            if (self)
            {
                TWIButtonCell *cell = [[TWIButtonCell alloc]init];
                [self setCell:cell];
            }
    
            return self;
        }
    
        - (void)drawRect:(NSRect)dirtyRect
        {
            // Drawing code here.
           //Changes Added!!!
        [super drawRect:dirtyRect];
    
        }
    
        //Changes Added!!!!
        + (Class)cellClass
        {
           return [TWIButtonCell class];
        }
    
        @end
    

    Now keep the break point at drawBezelWithFrame and check it will get called.