0

I have a NSMenuItem, and I create it using this:

NSMenuItem* nsMenuItem = [[NSMenuItem alloc] initWithTitle:[NSString stringWithUTF8String:menuItem->getText()] action: keyEquivalent:@""];

Now I pass in a function pointer, which I want to call when the selector gets invoked.

How do I do this?

I have tried:

id block = [^{
             functionPointer();
             } copy];
        
NSMenuItem* nsMenuItem = [[NSMenuItem alloc] initWithTitle:[NSString stringWithUTF8String:menuItem->getText()] action:@selector(invoke) keyEquivalent:@""];
[nsMenuItem setTarget:block];

However, the menu item is still grayed out.

How do I pass in a function pointer as a selector?

I'm building a cross platform app, and so basically I call to create a new menu, and my core C++ code will pass in a function pointer for the Menu Item.

ManUser123
  • 41
  • 1
  • 5
  • watch out for the types "IMP" and "SEL" in objective-C [use of IMP and SEL](https://stackoverflow.com/questions/2650190/objective-c-and-use-of-sel-imp) – Ol Sen Oct 27 '20 at 19:47
  • is this code above meant to be used as objective-c or objective-c++ ? In other words i assume you want to call a c++ function (IMP) given to the menuItem as Selector (SEL) applied on a object (id) – Ol Sen Oct 27 '20 at 20:24

1 Answers1

0

First, you need to understand how menus work. Did you read the documentation? Especially the section about enabling menu items is very insightful.

To give a short overview: the selector is the name of a function that will be called when the menu item is invoked. It's not a function, it's the name of a function. In Smalltalk one would say it is the message to be send.

The target is the object that is receiving the message.

The Menu mechanism checks if the target implements the selector function. Since your target is a block, it does not implement any function at all, hence the menu item is always disabled.

What you need do is the following:

  • store the block to be executed somewhere
  • add a generic selector like "performBlock" to your menu item
  • set the class that stores the block as a target
  • in that class, implement a fuction performBlock and call the block there

You could subclass NSMenuItem and keep the block in there, see this example here.

Andreas Oetjen
  • 9,889
  • 1
  • 24
  • 34
  • I'm building a cross platform app, and so basically I call to create a new menu, and my core C++ code will pass in a function pointer for the Menu Item. That's why I cannot set the class – ManUser123 Oct 27 '20 at 19:56
  • You need to create a wrapper class with a `performBlock` (arbitrary name) function that just holds the function pointer, and set this as the target. Or you could subclass `NSMenuItem` and do the stuff in there. – Andreas Oetjen Oct 27 '20 at 19:59
  • Yeah, I just created a wrapper class with that. The issue is when I call [[WrapperClass alloc] init], it automatically gets destroyed – ManUser123 Oct 27 '20 at 20:00
  • Check out subclassing (see my edits above), this helps against ARC cleanup – Andreas Oetjen Oct 27 '20 at 20:03