Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to change NSMenuItem Title (Login to Logout)

Im surprised that this hasn't already been asked:

But how does one go about changing the NSMenuItem title in a NSStatusBar menu. When a user logs in I want the menu item to say logout. I have tried creating an outlet to modify my NSMenuItem as a would a label or something.

AppDelegate.h

@property (retain) IBOutlet NSMenuItem *loginItem;

AppDelegate.m

[loginItem setTitle:@"Logout"];

But that didnt work.

The only thing that I was able to do was delete the old NSMenuItem, then add a new one, but it would just add it to the bottom. Is the only way to do this to remove every menu item then re-add them?? That seems very inefficient.

like image 650
urbanrider Avatar asked Jan 17 '13 03:01

urbanrider


2 Answers

The method you describe should work, though, in general, keeping IBOutlets for all your menu items can be tedious. (If your solution isn't working, make sure the IBOutlet is actually connected in the nib file, and make sure that you're setting the title at an appropriate time. If you're trying to set it in your controller's init method, for example, that's too early on, and the outlets haven't yet been connected up: move the method to awakeFromNib or similar.

A better approach in the long run is to use the <NSMenuDelegate> protocol and NSMenuValidation (informal) protocol to update menu items dynamically (and lazily).

For example, define your controller class like the following:

@interface MDAppDelegate : NSObject <NSApplicationDelegate, NSMenuDelegate>


@property (strong) NSStatusItem *statusItem;

@property (weak) IBOutlet NSWindow *window;

@property (weak) IBOutlet NSMenu *statusItemMenu;
@property (weak) IBOutlet NSMenuItem *toggleLoginLogoutMenuItem;

@property (weak) IBOutlet NSTextField *statusField;
@property (weak) IBOutlet NSTextField *progressField;
@property (weak) IBOutlet NSProgressIndicator *progressIndicator;

@property (assign) BOOL loggedIn;

- (IBAction)toggleLoginLogout:(id)sender;

@end

In the nib file, the delegate outlet of the statusItemMenu is set to the MDAppDelegate controller class. That assures that the MDAppDelegate class is in the responder chain and allow it to work with validating the menu items.

Then you could implement your .m like the following:

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
    _statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength];
    _statusItem.menu = _statusItemMenu;
    _statusItem.title = NSLocalizedString(@"NSStatusItem", @"");
    [self updateLoggedInStatus];
}
- (void)updateLoggedInStatus {
    [self.statusField setStringValue:(self.loggedIn ? @"Logged in" : @"Logged out")];
}
- (IBAction)toggleLoginLogout:(id)sender {
    [self performSelector:@selector(finishFakeLoginLogout:)
                         withObject:nil afterDelay:2.0];
}
- (void)finishFakeLoginLogout:(id)sender {
    self.loggedIn = !self.loggedIn;
    [self updateLoggedInStatus];
}
- (void)menuNeedsUpdate:(NSMenu *)menu {
#if MD_DEBUG
    NSLog(@"[%@ %@]", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
#endif
}
- (BOOL)validateMenuItem:(NSMenuItem *)menuItem {
#if MD_DEBUG
    NSLog(@"[%@ %@]", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
#endif
    SEL action = menuItem.action;
    if (action == @selector(toggleLoginLogout:)) {
        [menuItem setTitle:(self.loggedIn ? @"Logout" :@"Login")];
    }
    return YES;
}

Sample project: http://github.com/NSGod/NSStatusBarFinagler

like image 142
NSGod Avatar answered Sep 25 '22 13:09

NSGod


You don't need to connect your menu item just try this..

NSMenuItem *menuItem = (NSMenuItem*) sender;
    NSString *menuString = menuItem.title;

    if ([menuString isEqualToString:@"Login"]) 
{

            [menuItem setTitle:@"LogOut"];
}

NSMenuItem menuItem = (NSMenuItem) sender;

     this line automatically collect the menu items in your app. 
like image 34
NewStack Avatar answered Sep 23 '22 13:09

NewStack