Search code examples
objective-cmacoscocoadesktop-applicationnsmenu

Getting the initiator for an NSMenuItem


I have a view with 3 images which have there own @property in their class. When I right click one of these images, I show a NSMenu with submenu which has NSMenuItems. All the items are send to the IBAction called - (IBAction)selectImage:(id)sender with each a different tag. The sender is, of course, the NSMenuItem. How can I find out which image the user right clicked upon? So I an basically looking for the caller to the parent of the sender.

Or maybe, I am building my menu all wrong?


Solution

  • You're approaching the problem the wrong way. Instead of setting an explicit target on your menu items, use the First Responder (or nilif you're doing it in code).

    By default, the first responder will be the view that owns the contextual menu ("For a context menu, the search is restricted to the responder chain of the window in which the context menu was displayed, starting with the associated view" according the documentation).

    Therefore, if you subclass your NSImageView and implement the actions that you need there, it will, by default, receive the messages. They can be a simple redirection to your controller object, but you will know which view was clicked on this way (because it's self in this case!)


    This answer is an edit of this previous answer, which is significantly less elegant:

    Start by creating a subclass of NSMenu (let's call it PPMenu) that has an additional property to store a weak reference to your image view (let's call it imageView). Set that class as your menu's class in your XIB, and set the menu as the image view's context menu there as well (or, if they don't exist in the XIB, just add an outlet).

    Now, if you override -menuForEvent: is your NSImageView subclass, you'll be able to customize the context menu... Start by calling super there to retrieve the PPMenu instance (if it is set up in IB, otherwise use the outlet), and set the imageView property that you've added to self (since you're in the image view code).

    Now, in your action's code, you can use ((PPMenu*)(sender.menu)).imageView to retrieve the image view associated with the menu.