0

I have already created a status item for the menu bar but I would like to add a checkbox to make it able to be toggled on and off.

So when the check box is checked the status item is displayed and when the checkbox is not checked it is not displayed.

What code would i need to do this?

Joshua
  • 15,200
  • 21
  • 100
  • 172

2 Answers2

8

First in your controller class create an instance variable to hold the reference to this item:

NSStatusItem *item;

Then create a method to create this status item, when the box is checked:

- (BOOL)createStatusItem
{
NSStatusBar *bar = [NSStatusBar systemStatusBar];

//Replace NSVariableStatusItemLength with NSSquareStatusItemLength if you
//want the item to be square
item = [bar statusItemWithLength:NSVariableStatusItemLength];

if(!item)
  return NO;

//As noted in the docs, the item must be retained as the receiver does not 
//retain the item, so otherwise will be deallocated
[item retain];

//Set the properties of the item
[item setTitle:@"MenuItem"];
[item setHighlightMode:YES];

//If you want a menu to be shown when the user clicks on the item
[item setMenu:menu]; //Assuming 'menu' is a pointer to an NSMenu instance

return YES;
}

Then create a method to remove the item when it is unchecked:

- (void)removeStatusItem
{
NSStatusBar *bar = [NSStatusBar systemStatusBar];
[bar removeStatusItem:item];
[item release];
}

Now tie it all together by creating an action that is called when the checkbox is toggled:

- (IBAction)toggleStatusItem:(id)sender
{
BOOL checked = [sender state];

if(checked) {
  BOOL createItem = [self createStatusItem];
  if(!createItem) {
    //Throw an error
    [sender setState:NO];
  }
}
else
  [self removeStatusItem];
}

Then create the checkbox in IB and set the action to your toggleStatusItem: method; make sure that the checkbox is left unchecked.

Edit (In response to errors) As stated above, you need to declare the NSStatusItem in the interface of the class that you have placed the createStatusItem and removeStatusItem methods; the reason that this becomes an instance variable rather than one local to the createStatusItem method is that there is no way to retrieve a pointer to an item that has already been added to the status bar in the Apple menu, and in order to remove the item once the checkbox is unchecked, you must store a pointer to this item. This will also solve your third error.

In response to your second error, I was merely demonstrating that if you want to add a menu to your status item when it is clicked, you must add the code for that yourself, retrieving a pointer to an NSMenu; I was showing how you could then add this menu item to the status bar item, if your pointer was called menu, hence my comment next to the line of code.

Alex Rozanski
  • 37,815
  • 10
  • 68
  • 69
  • Should I enter the main code (not the action) in the place where I have set up the status item? – Joshua May 09 '09 at 15:44
  • Yes, ideally you'd put the pointer to the status item in the controller class, and place the methods to remove/add it to the bar in this class also, along with the action. – Alex Rozanski May 09 '09 at 16:00
  • Yes; creating a separate class to apply the changes would be unnecessary – Alex Rozanski May 09 '09 at 16:31
  • I've added the action to the controller but it's not seeing/noticing it in IB. – Joshua May 09 '09 at 16:31
  • 1
    You need to instantiate your controller class in IB; drag a blue "NSObject" object from the Library into the object window; then open up the inspector and in the Identity pane type your controller class name into the "Class" popup box. Then control+drag from your checkbox to the controller class, and select the toggleStatusItem: menu item from the popup menu to set its action. – Alex Rozanski May 09 '09 at 16:53
  • That's what i did thetoggleStatusItem: action wasn't in the list of actions. – Joshua May 09 '09 at 17:12
  • Check to see that you declared and implemented the method as - (IBAction)toggleStatusItem:(id)sender and that you declared it in the class interface. – Alex Rozanski May 09 '09 at 17:41
  • How would I declare the NSStatusItem? And would I delete the setMenu line if i didn't want a drop down menu? – Joshua May 10 '09 at 07:18
  • Simply with NSStatusItem *item; in your class's interface; and yes, I was just demonstrating that that's the line that you'd use if you did want a drop-down menu. – Alex Rozanski May 10 '09 at 07:34
  • I see, should I put NSStatusItem *item in the .m file or the .h file? – Joshua May 10 '09 at 08:02
  • In the .h file (where the class interface is defined) – Alex Rozanski May 10 '09 at 08:34
  • So I just paste in NSStatusItem *item into the .h file. Right? – Joshua May 10 '09 at 11:29
  • Yes, between the @interface and @end – Alex Rozanski May 10 '09 at 11:43
  • It works great now, thanks very much, just one last question, why can't the check box be checked as default, so it automatically display the status item? – Joshua May 10 '09 at 11:59
  • And also how would I make it display a image instead of text? – Joshua May 10 '09 at 12:02
  • Perhaps start a new question instead of simply commenting on this post; more people will be able to see your question and so you are more likely to get the specific answers that you want. – Alex Rozanski May 10 '09 at 12:17
  • Ok, although this question is based on your code, why doesn't the check box stay checked once you close the app, say you checked it when you opened it first when you open the app again it becomes unchecked. How could this be fixed? – Joshua May 10 '09 at 12:27
  • Why doesn't the check box stay checked once you close the app, say you checked it when you opened it first when you open the app again it becomes unchecked. How could this be fixed? – Joshua May 10 '09 at 13:24
  • That's a whole new venture entirely - you need to write the user's preference to the standard user defaults object in the NSUserDefaults class – Alex Rozanski May 10 '09 at 13:42
  • I've set up the NSUserDefaults class but if the check box is checked at opening it doesn't display the status item. How can I fix this? – Joshua May 10 '09 at 14:51
  • You need to determine whether the user wants the status item to be visible or not in your controller's awakeFromNib method, and add it to the menu bar if appropriate – Alex Rozanski May 10 '09 at 15:51
  • What code would I need to make the app determine whether the user wants the status item to be visible or not on launch? – Joshua May 10 '09 at 15:55
  • What code would I need to make the app determine whether the user wants the status item to be visible or not on launch? – Joshua May 10 '09 at 17:21
  • What code would I need to make the app determine whether the user wants the status item to be visible or not on launch? – Joshua May 11 '09 at 05:32
  • What code would I need to make the app determine whether the user wants the status item to be visible or not on launch? – Joshua May 12 '09 at 06:11
1

Get an outlet to your button you want to toggle and then create an action method that your checkbox points to that toggles the hidden property of the original button based on the check box status.

crackity_jones
  • 1,077
  • 2
  • 13
  • 16