Amazon.com Widgets

shanecrawford.org Home Grown in Austin

Posted
20 February 2008 @ 1pm

Tagged
Development, Mac

Creating an Action PopUp Button in Leopard

lead action buttonIt seems that everywhere you look in OS X you see applications with popup action buttons. You know, that button with a gear on it. Click it and a menu full of goodies pops up for you to play with. Apple itself uses it pretty extensively in its apps; Mail and Finder are notable examples. With such a prevalent control you would think it was dirt simple to create on of these for your own application. You’d think, but prior to Leopard you’d be wrong (mostly). A quick search around the web shows that there has been much discussion on the topic with quite a few various implementations. In fact, you may have googled your way here in search of a solution. Read on and I think you’ll be pleasantly surprised.

The essence of most implementations for an action button rely on NSPopUpButton and this implementation is no different. Where things start to diverge is that this implementation can be completed entirely within Interface Builder – no subclassing or custom rendering needed. So let’s get started and we’ll crank out this puppy.

NSPopUpButton operates in two different major modes which are ‘Pop Up’ and ‘Pull Down’. For this implementation we’ll be relying on the ‘Pull Down’ behavior which gives us a button with the requisite down arrow. So, just drag an NSPopUpButton onto your application in the desired location, choose ‘Pull Down’ from the inspector, choose the arrow to be along the bottom edge, and ensure that the ‘Title’ attribute is empty. Following is a thumbnail of the full inspector for a properly configured NSPopUpButton (click to enlarge).

NSPopUpButton Attributes Inspector

You should now have a popup button with a blank title area and a down arrow. Sizing of the button is a hit-or-miss exercise and is probably the biggest drawback of this technique. As you will see even though ib action buttonwe will have the gear icon in the built application we will not see it rendered in Interface Builder. The next major step is hooking up the menu that we will use. By default NSPopUpButton comes with a menu that has three items in it. For whatever reason if you try to modify this menu by adding new items things start to get out of control. So, we just bypass the default provided menu and create our own. When in ‘Pull Down’ mode NSPopUpButton utilizes the first NSMenuItem in the menu as the title for the button. Herein lies the trick that makes the whole thing work.

To start off this phase of the button development drag an NSMenu from the Interface Builder pallet into your NIB file. Name it something exciting like ‘ActionMenu’ in order to distinguish it from other menus in your NIB (you can do this via the ‘Identity’ tab in the inspector – see the Interface Builder Identity ‘Name’ attribute). Next build up your menu as desired reserving the very first menu item for our popup button custom use. You can connect your menu items to Actions in your code as needed (the blank menu takes no action – its used only by NSPopUpButton). Now, in order to get our gear icon to show up on our popup button we need to configure the attributes of that very first menu item. The key is to configure the menu item to have a blank title and to set the ‘Image’ attribute to have the value ‘NSActionTemplate’ (you will need to type NSActionTemplate into the text field).

menu item attributes

The value NSActionTemplate sets the image of the menu item to be the gear icon. This comes from the new Media Library in Interface Builder 3. To see this for yourself bring up the media library, find the gear icon and click on it. You will see that its name is NSActionTemplate.

menuitem attribs
Now for the final connection. To bring the menu and the popup button together find your popup button and bring up its inspector. Connect its menu outlet to your NSMenu. That’s pretty much it. You’ll probably need to play with the actual size of the button (sans image) in order to get things to look right when you build and run the application. You can also play with some of the NSPopUpButton attributes to control the default location that the menu popups up at etc. However, you now have the often desired action popup button without any subclassing or custom rendering. Enjoy.

 


7 Comments

Posted by
Jason
29 March 2008 @ 3pm

I followed every step easily and it worked first go. Perfect—thanks!


Posted by
Pete Callaway
1 April 2008 @ 3am

A perfect solution. Thanks.


Posted by
Jon
20 July 2008 @ 1am

I love you.


Posted by
Andrew
13 January 2009 @ 10pm

Thanks for the tutorial.

Works as described, except IB v3.1.2 doesn’t allow me to disconnect the original menu (named OtherViews) from the popup button, and I had to connect the new menu by setting the connection in reverse from the menu to the button (referencing outlet).

I end up having multiple menu connections – seems to work, but doesn’t feel right. Any suggestions? Thanks again. The original menu was driving me mad.


Posted by
Warren
27 January 2009 @ 6am

Finally, a simple solution that actually works. Thanks a million, great article! I wish Apple would make that action button a standard control.


Posted by
Jeff Boulter
5 April 2010 @ 10pm

Thanks for the tips. With this information I was able to figure out how to create this programmatically:

toolbarItem = [[[NSToolbarItem alloc] initWithItemIdentifier: itemIdentifier] autorelease];

NSPopUpButton *button = [[[NSPopUpButton alloc] initWithFrame:NSMakeRect(0.0, 0.0, 38, 23) pullsDown:YES] autorelease];
[button setBezelStyle:NSTexturedRoundedBezelStyle];

NSImage *icon = [[[NSImage alloc] initWithContentsOfFile:@”image.tif”]] autorelease];
[[button cell] setArrowPosition:NSPopUpArrowAtBottom];
[button setPreferredEdge:NSMinYEdge];
[button setTitle:@""];

[toolbarItem setPaletteLabel:@"Foo"];
[toolbarItem setToolTip:@"Foo Tip"];
[toolbarItem setLabel:@"Foo Label"];

[toolbarItem setView:button];
[toolbarItem setEnabled:YES];

NSMenu *submenu = [[[NSMenu alloc] init] autorelease];

NSMenuItem * iconMenuItem = [[[NSMenuItem alloc] init] autorelease];

[iconMenuItem setTitle:@""];
[iconMenuItem setImage:icon];

NSMenuItem* menuItem1 = [[[NSMenuItem alloc] initWithTitle: @”Bar” action:@selector(doBar:)
keyEquivalent: @”"] autorelease];
NSMenuItem* menuItem2 = [[[NSMenuItem alloc] initWithTitle: @”Bar 2″ action:@selector(doBar2:)
keyEquivalent: @”"] autorelease];

[submenu addItem: iconMenuItem];
[submenu addItem: menuItem1];
[submenu addItem: menuItem2];

[button setMenu:submenu];


Posted by
Bernard Dischlu
2 April 2012 @ 1pm

Nice! I desperated to have my “Action Pop Menu” one day — now it’s done in five minutes.

If only you could supply such a good example for a NSOutlineView… I’m stuck with my NSDictionary which has no decent interface…

Regards,
Bernard


Leave a Comment