7

I have an NSMenuItem with a bunch of items in it, however... the list just doesn't get enabled.

What I mean:
List

This is my code:

- (void)didFetchNewList:(NSArray *)list
{
    NSArray *smallList = [list subarrayWithRange:NSMakeRange(0, 10)];

    NSMenu *menu = [[NSMenu alloc] initWithTitle:@""];

    for (NSDictionary *dict in smallList)
    {
        NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
        [dateFormatter setDateFormat:@"MMM dd @ HH:mm:ss"];

        NSMenuItem *soMenuItem = [[NSMenuItem alloc] initWithTitle:
                  [dateFormatter stringFromDate:[dict objectForKey:@"date"]]
                                                            action:nil
                                                     keyEquivalent:@""];
        [soMenuItem setEnabled:YES];

        [menu addItem:soMenuItem];        
    }

    [menu addItem:[NSMenuItem separatorItem]];

    NSMenuItem *soMenuItem =  [[NSMenuItem alloc]
                     initWithTitle:@"Settings" action:nil keyEquivalent:@"S"];
    [soMenuItem setEnabled:YES];
    [menu addItem:soMenuItem];

    [statusItem setMenu:menu];
    [statusItem setEnabled:YES];

}

I am setting everything as enabled, yet it is still disabled. How can I solve this?

NSGod
  • 22,699
  • 3
  • 58
  • 66
Paul Peelen
  • 10,073
  • 15
  • 85
  • 168

1 Answers1

12

When you create an NSMenuItem your item will have to have a valid target and a valid selector. This means the target cannot be nil, and has to respond to the passed selector. Keep in mind that in this case a NULL selector will not enable the menu item.

NSMenu *myMenu;
NSMenuItem *myItem;

myMenu = [[NSMenu alloc] initWithTitle:@""];
myItem = [[NSMenuItem alloc] initWithTitle:@"Test" action:@selector(validSelector:) keyEquivalent:@""];
[myItem setTarget:myTarget];
[myMenu addItem:myItem];
// Do anything you like
[myMenu release];
[myItem release];

EDIT: I saw you're calling -[NSMenuItem setEnabled:] with YESafter you create the menu item. This not necessary, as they will be enabled by default.

EDIT 2: As NSGod pointed out (see comment below) the target can be nil. In that case the first responder of your application will receive the passed method. That is, as long as the first responder has that method implemented. (edit 3) However if this is not the case, the method will be sent to the next responder in the responder chain. This continues until either a responder is found that responds to the selector or there are no responders left to examine. When no responder is found you menu item won't get enabled.

v1Axvw
  • 3,054
  • 3
  • 26
  • 40
  • 5
    While the menu items do need have a valid selector, they don't necessarily have to have a target (in other words, the target **can** be `nil`). A `nil` target means "use the first object in the responder chain that responds to my selector". It is functionally equivalent to setting the target of the menu item to the `First Responder` proxy object in the nib file. (See http://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/MenuList/Articles/EnablingMenuItems.html#//apple_ref/doc/uid/20000261-74653-BAJBGJHB) – NSGod Jan 06 '12 at 00:26
  • Aha! I was already thinking about why the hell the initialization method doesn't have a target argument. Thanks for clearing that up! – v1Axvw Jan 06 '12 at 00:30
  • 3
    Your second edit is still not totally correct: The first responder will receive the action message, but it does not need to implement it. If it doesn't, it will forward the message to its next responder. That's the responder chain at work. – Peter Hosey Jan 06 '12 at 01:43
  • Thanks. I am really glad with your answer. I'll update my code so it works. – Paul Peelen Jan 06 '12 at 13:03
  • The Selector method must be in the same scope as the target. If you have subMenuItems then setting the target in these items to self will enable you to have the selector method inside these items. – Sentry.co May 19 '16 at 10:32