Question

I'm subclassing NSButtonCell to customize the drawing (customizable theme). I'd like to customize the way checkboxes and radio buttons are drawn.

Does anyone know how to detect whether a button is a checkbox or radio button?

There is only -setButtonType:, no getter, and neither -showsStateBy nor -highlightsBy seem to give any unique return values for checkboxes that don't also apply to regular push buttons with images and alternate images.

So far I've found two (not very pretty) workarounds, but they're the kind of thing that'd probably get the app rejected from MAS:

  1. Use [self valueForKey: @"buttonType"]. This works, but since the method is not in the headers, I presume this is something Apple wouldn't want me to do.

  2. Override -setButtonType: and -initWithCoder: to keep track of the button type when it is set manually or from the XIB. Trouble here is the XIB case, because the keys used to save the button type to disk are undocumented. So again, I'd be using private API.

I'd really like this to be a straight drop-in replacement for NSButtonCell instead of forcing client code to use a separate ULIThemeSwitchButtonCell class for checkboxes and a third one for radio buttons.

Was it helpful?

Solution

A button does not know anything about its style.

From the documentation on NSButton

Note that there is no -buttonType method. The set method sets various button properties that together establish the behavior of the type. -

You could use tag: and setTag: (inherited by NSButton from NSControl) in order to mark the button either as a checkbox or a radio button. If you do that programatically then you should define the constant you use. You can also set the tag in Interface Builder, but only as an integer value (magic number).

OTHER TIPS

In initWithCoder, here is my adaptation of the BGHUDButtonCell.m solution, updated for Mac OS Sierra:

-(id)initWithCoder:(NSCoder *)aDecoder {

   if ( !(self = [super initWithCoder: aDecoder]) ) return nil;

   NSImage *normalImage = [aDecoder decodeObjectForKey:@"NSNormalImage"];
   if ( [normalImage isKindOfClass:[NSImage class]] )
   {
      DLog( @"buttonname %@", [normalImage name] );
      if ( [[normalImage name] isEqualToString:@"NSSwitch"] )
         bgButtonType = kBGButtonTypeSwitch;
      else if ( [[normalImage name] isEqualToString:@"NSRadioButton"] )
         bgButtonType = kBGButtonTypeRadio;
   }
   else
   {
      // Mac OS Sierra update (description has word "checkbox")
      NSImage *img = [self image];
      if ( img && [[img description] rangeOfString:@"checkbox"].length )
      {
         bgButtonType = kBGButtonTypeSwitch;
      }
   }
}

This is strange to me that it's missing from NSButton. I don't get it. That said, it's easy enough to extend NSButton to store the last set value:

import Cocoa

public class TypedButton: NSButton {
    private var _buttonType: NSButton.ButtonType = .momentaryLight
    public var buttonType: NSButton.ButtonType {
        return _buttonType
    }

    override public func setButtonType(_ type: NSButton.ButtonType) {
        super.setButtonType(type)
        _buttonType = type
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top