Setting C function as selector for NSButton produces no results

706 views Asked by At

I have a function which creates an instance of button, and I'd like the callback to go to a separate function. This doesn't work (no error or anything, just nothing happens when I click on the button). I need it to be a C function because I'm interfacing with Golang (using cgo).

void Start(void){
    ...
    NSRect buttonFrame = NSMakeRect(59, 33, 82, 32);
    NSButton *button = [[NSButton alloc] initWithFrame:buttonFrame];
    [button setAction:@selector(ButtonClick:)];
    ...
}
void ButtonClick(void){
    NSLog(@"Button clicked!");
}
2

There are 2 answers

6
jscs On BEST ANSWER

You cannot use a C function as the action for an NSButton. The button requires a target which is an object and the selector for a method on that target. If there's no target, there must still be an object in your window's responder chain that will respond to the selector.

You must create an object (doesn't have to be an instance; you can use a class object if you so choose) in order for the button to operate. The method also needs to have a particular signature: it must take one argument, which will be the button when it's called.

If you must use the function you've already written, you will have to write an ObjC class that calls through to it from the action method:

#import <Cocoa/Cocoa.h>

@interface ButtonPasser : NSObject

+ (IBAction)buttonPassthrough:(id)sender;

@end

@implementation ButtonPasser

+ (IBAction)buttonPassthrough:(id)sender
{
    buttonClick();
}

@end

void start(void){
    ...
    NSRect buttonFrame = NSMakeRect(59, 33, 82, 32);
    NSButton *button = [[NSButton alloc] initWithFrame:buttonFrame];
    [button setTarget:[ButtonPasser class]];
    [button setAction:@selector(buttonPassthrough:)];
    ...
}

This uses the class object and a class method, since I'm not sure what you would do with an instance after you created it. Using an instance would be much more usual, however.

3
CorbinMc On

Your problem is that neither your Start or ButtonClick methods (should be start and buttonClick) are instance methods. They both must be tied to an object in order for buttonClick to be set as an action.

Once these are both instance methods you should be able to add [button setTarget:self]; above your setAction call.

If you cannot make start an instance method, you should add another method in between your calls.