7

I have an NSButton which I want to have a different background color when it's highlighted than when it's not (transparent on not highlighted, if that makes any difference).

At present, I have the following code

[view setWantsLayer:YES];

NSButton* button = [[NSButton alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
[button setBordered:FALSE];
[(NSButtonCell*)[button cell] setHighlightsBy:NSChangeBackgroundCellMask];

[view addSubview:button];

This will change the background to the default window background color on click. If I remove NSChangeBackgroundCellMask the background goes away.

Is there an easy way I can have a different color for the background, or does this require me to subclass NSButton?

cobbal
  • 69,903
  • 20
  • 143
  • 156

3 Answers3

11

In the end, I solved it by subclassing NSButtonCell and overwriting

- (void) highlight:(BOOL)flag withFrame:(NSRect)cellFrame inView:(NSView*)controlView

to make the changes I wanted (changing controlView.layer.backgroundColor based on flag)

cobbal
  • 69,903
  • 20
  • 143
  • 156
  • I'm not seeing this method on the class reference docs for `NSButtonCell`? https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSButtonCell_Class/ – Adam Johns May 04 '16 at 01:46
  • 1
    @AdamJohns It's documented in the [`NSCell` superclass](https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSCell_Class/index.html#//apple_ref/occ/instm/NSCell/highlight:withFrame:inView:) – cobbal May 04 '16 at 01:48
  • This is correct but be careful! In Mojave, if you overwrite any draw methods, this will not work! – Ricardo Anjos Dec 11 '18 at 11:28
2

You will need to subclass your NSButton and override its mouseDown: and mouseUp: events, change the color of your NSButton in these events.

Neha
  • 1,751
  • 14
  • 36
  • 1
    Oddly enough, mouseUp: wasn't getting called properly for me so I ended up subclassing NSButtonCell instead. – cobbal Nov 19 '13 at 08:27
  • Please note: Mouse events of the NSButtonCell are only getting called when you set showsBorderOnlyWhileMouseInside = YES – paxos May 07 '15 at 11:21
  • 1
    mouseUp never called for me – Coldsteel48 May 03 '16 at 11:23
  • NSButton enters its own nested event loop on mouseDown:. That's why you're not getting a mouseUp: event. The nested event loop for tracking the mouse swallows it to know when to return to the main event loop. – uliwitness Aug 29 '16 at 16:24
0

Swift version of Cobbal's answer:

override func highlight(_ flag: Bool, withFrame cellFrame: NSRect, in controlView: NSView) {
        //do nothing, to disable highlight
}
Witterquick
  • 6,048
  • 3
  • 26
  • 50