The Application Kit interprets right-mouse-down events and left-mouse-down events modified by the Control key as commands to display a contextual menu for the clicked view. Your view subclasses have several alternative approaches for displaying a contextual menu. If the view’s menu is to remain unchanged regardless of context, you can do one of three simple procedures:
Configure in Interface Builder: Add a standalone (rootless) menu to a nib file and customize it to suit, including the specification of targets and actions. Then connect it to your custom view’s menu
outlet, which is inherited from NSView
.
Programmatically assign a generic menu: Override the defaultMenu
class method of NSView
to create and return a menu that’s common to all instances of your subclass. (See Listing 1 for a sample implementation of this method.) This default menu is also accessible via the NSResponder
menu
method unless some other NSMenu
object has been associated with the view.
Programmatically assign an instance-specific menu: In the custom view’s initWithFrame:
or awakeFromNib
methods, create the menu and associate it with the view by using the setMenu:
method (NSResponder
).
After you complete any of these procedures, the Application Kit displays the contextual menu whenever the user left-Control-clicks or right-clicks the view. Note that the Application Kit automatically also validates the menu items of contextual menus, unless you request it not to.
However, you might want the view’s contextual menu to change based on where the mouse click occurs in the view or on the current state of the view; you may want to add, delete, enable, or disable menu items or change some item attributes to reflect the current context. There is more than one way to accomplish this, but a good approach is to override the defaultMenu
and menuForEvent:
methods of NSView
. In the former method implementation, create and return an NSMenu
object that is the “base” contextual menu, suitable for most contexts. Be sure to create menu items for the menu that have all necessary attributes (including action selector and possibly target object). Listing 1 shows how you might do this.
Listing 1 Returning the default menu
+ (NSMenu *)defaultMenu { |
NSMenu *theMenu = [[[NSMenu alloc] initWithTitle:@"Contextual Menu"] autorelease]; |
[theMenu insertItemWithTitle:@"Beep" action:@selector(beep:) keyEquivalent:@"" atIndex:0]; |
[theMenu insertItemWithTitle:@"Honk" action:@selector(honk:) keyEquivalent:@"" atIndex:1]; |
return theMenu; |
} |
For contextual-menu events, the Application Kit invokes the menuForEvent:
method if your view subclass implements it. In your implementation of this method, test for a certain condition (event type, mouse location, view state, and so on) and if that condition holds modify and return the default menu. Otherwise, return the default menu unchanged. Listing 2 gives an example that tests for a mouse click in a certain area and returns a modified contextual menu if that test holds true.
Listing 2 Displaying a dynamically modified contextual menu
- (NSMenu *)menuForEvent:(NSEvent *)theEvent { |
NSPoint curLoc = [self convertPoint:[theEvent locationInWindow] fromView:nil]; |
NSRect magic_square = NSMakeRect(0.0, 0.0, 10.0, 10.0); |
if ([self mouse:curLoc inRect:magic_square]) { |
NSMenu *theMenu = [[self class] defaultMenu]; |
[theMenu insertItemWithTitle:@"Wail" action:@selector(wail:) keyEquivalent:@"" atIndex:[theMenu numberOfItems]-1]; |
return theMenu; |
} |
return [[self class] defaultMenu]; |
} |
If you want your view to display a contextual menu in response to events other than right-mouse clicks and left-mouse-Control clicks, you can directly handle the event message in the appropriate NSResponder
method. For example, if you want users to be able to left-click an image view to get a menu of export options, you would override the mouseDown:
method. In your implementation of the method, create a menu and then invoke the NSMenu
class method popUpContextMenu:withEvent:forView:
, passing in the event object related to the mouse-down event and the view owning the contextual menu. Listing 3 illustrates this approach.
Listing 3 Displaying a contextual menu upon receiving a left-mouse event
- (void)mouseDown:(NSEvent *)theEvent { |
NSMenu *theMenu = [[[NSMenu alloc] initWithTitle:@"Contextual Menu"] autorelease]; |
[theMenu insertItemWithTitle:@"Beep" action:@selector(beep:) keyEquivalent:@"" atIndex:0]; |
[theMenu insertItemWithTitle:@"Honk" action:@selector(honk:) keyEquivalent:@"" atIndex:1]; |
[NSMenu popUpContextMenu:theMenu withEvent:theEvent forView:self]; |
} |
Contextual menus, including any menu you pop up with popUpContextMenu:withEvent:forView:
, automatically insert menu items from any contextual menu plug-ins that the user has installed into the menu. A contextual menu plug-in, which is CFPlugIn
bundle installed in a Library/Contextual Menu Items
directory at the appropriate level of the system, enables applications and other forms of software to extend the list of commands found on contextual menus such as the Finder’s. The applications do not have to be running for their items to appear. If you are trying to programmatically display a menu, you might not want those items to appear. The preferred approach for programmatically displaying a non-contextual menu is to create an NSPopUpButtonCell
object, set its menu, and then call send a attachPopUpWithFrame:inView:
message to the pop-up button cell.
Note: For information on how to create a CFPlugIn
plug-in, see Plug-ins. For information on the Carbon Menu Manager functions you must implement for a contextual menu plug-in, see Menu Manager Reference.
© 2001, 2007 Apple Inc. All Rights Reserved. (Last updated: 2007-06-26)