Right-Clicks/Control-Clicks and Contextual Menus

Discussion in 'Mac Programming' started by simX, Dec 10, 2005.

  1. macrumors 6502a

    simX

    Joined:
    May 28, 2002
    Location:
    Bay Area, CA
    #1
    I'm trying to provide a contextual menu to a table view that I have in my standard Cocoa application. Ideally, this will allow those with two-button mice or those with lightning-quick reflexes to quickly access some options based on the item selected in the list.

    However, I'm having an annoying problem: when you right-click directly on an item in the NSTableView, the item under the mouse isn't automatically selected! Because how my actions are created, they rely on the selected item in the NSTableView, so right-clicking in the table view and then selecting an action will probably not (in most cases) result in the action being applied to the desired item. This negates the usefulness of the contextual menus to a great extent.

    What's the easiest way to modify the mouse event so that a control-click on this NSTableView will first select the item and THEN bring up the contextual menu? (I'm even interested in "workarounds" where you would get the mouse position at the time of the control-click, and then my program would calculate which item should be selected, select it, and then bring up the menu.)
     
  2. Administrator

    HexMonkey

    Staff Member

    Joined:
    Feb 5, 2004
    Location:
    New Zealand
    #2
    The way I do it is to subclass NSTableView and change the table selection in the menuForEvent method. Here's the code I use (note that it requires Panther since it uses -[NSTableView selectedRowIndexes], if you need to support Jaguar use -[NSTableView selectedRowEnumerator] instead):

    Code:
    -(NSMenu*)menuForEvent:(NSEvent*)event
    {
    	//Find which row is under the cursor
    	[[self window] makeFirstResponder:self];
    	NSPoint menuPoint = [self convertPoint:[event locationInWindow] fromView:nil];
    	int row = [self rowAtPoint:menuPoint];
    	
    	/* Update the table selection before showing menu
    	Preserves the selection if the row under the mouse is selected (to allow for
    	multiple items to be selected), otherwise selects the row under the mouse */
    	BOOL currentRowIsSelected = [[self selectedRowIndexes] containsIndex:row];
    	if (!currentRowIsSelected)
    		[self selectRow:row byExtendingSelection:NO];
    	
    	if ([self numberOfSelectedRows] <=0)
    	{
            //No rows are selected, so the table should be displayed with all items disabled
    		NSMenu* tableViewMenu = [[self menu] copy];
    		int i;
    		for (i=0;i<[tableViewMenu numberOfItems];i++)
    			[[tableViewMenu itemAtIndex:i] setEnabled:NO];
    		return [tableViewMenu autorelease];
    	}
    	else
    		return [self menu];
    }
     
  3. thread starter macrumors 6502a

    simX

    Joined:
    May 28, 2002
    Location:
    Bay Area, CA
    #3
    Yes! Woo!

    OMG. You rock! That worked perfectly! You solved it exactly how I would have done it... not interrupting the selection if it's already selected, and selecting it if it isn't.

    Just a quick question, though -- does the menuForEvent: method handle anything else? That is, if I change the NSTableView method so that it uses your code instead, will it affect anything else that you might do with a table view? I assume, given the name of the method, that this just handles the display of a contextual menu, so all you're basically doing is adding some code so that the selection will happen first before the menu comes up. Am I right?
     
  4. Guest

    caveman_uk

    Joined:
    Feb 17, 2003
    Location:
    Hitchin, Herts, UK
    #4
    I guess you could use selectedRowEnumerator for both as although it's now deprecated it still works.
     
  5. Administrator

    HexMonkey

    Staff Member

    Joined:
    Feb 5, 2004
    Location:
    New Zealand
    #5
    Yes, you're correct. From the documentation:

    So by default it would return [self menu] and do nothing else.

    Yeah, I still use it extensively in a lot of my older code. I don't expect Apple will remove it for a long time (if ever) since that would break a lot of applications.
     

Share This Page