« How to Use Toolbars

Posted by Brad Miller on November 04, 2001 [Feedback (8) & TrackBack (0)]

// Introduction

Toolbars are the handy feature many programs use to add a small section that holds commonly used functions to the top of each window. A good example of one is the navigation toolbar in OmniWeb. Fortunately for us, toolbars are easy to implement like most things in Cocoa.

sample toolbar
Figure 1: Sample Toolbar with standard toolbar items

 

// Create the Interface

This project is one of Cocoa Application type. Start off by opening the MainMenu.nib resource file. For this example, the interface building is minimal. I'll assume you know the basics of using Interface Builder and already know how to add menu items and make connections for actions and outlets.

The only interface elements we need to add are two menu items under the Window menu. These will be used to give the user a way to show or hide the toolbar and a way to invoke the toolbar's customization sheet. Add a menu item called "Hide/Show Toolbar" and another called "Customize Toolbar..." (the ellipsis is produced by option-;).

Next create a controller class as a subclass of NSObject. Only one outlet needs to be added to it, window. The window outlet is used to give us a pointer to the main window and can be statically typed as an NSWindow outlet. Create this outlet and connect it to the main window's title bar. Two actions also need to be added, one for each of the menu items that we added. Create actions called customize: and showhide: and connect them to their corresponding menu items.

The final thing we need to do in IB is to set the File's Owner delegate so that the toolbar knows where to find the delegate methods it needs. To do this, simply make a connection from the File's Owner to the controller class. Do this bye control dragging from the File's Owner icon to the instance of the controller class. Then in the info pannel, select the delegate outlet and click on the "Connect" button.

sample toolbar
Figure 2: Connection between File's Owner and the controller class.

That's all we need to do in IB. Create the files for the controller and then switch back to Project Builder.

 

// The Delegates

When adding a Toolbar to a project, you have to implement NSToolbar's delegates methods. It has three required methods and two optional methods. The required methods are:

- (NSToolbarItem *)toolbar:(NSToolbar *)toolbar
itemForItemIdentifier:(NSString *)itemIdentifier
willBeInsertedIntoToolbar:(BOOL)flag

This method returns a NSToolbarItem for the identifier passed in. The toolbar item can be either created in the method or, as in our example below, taken from a data structure. It is used by the toolbar to obtain the toolbar items when it initially builds the toolbar or when an item is added to a toolbar. This delegate is also called in order to dispaly the toolbar items when the customization sheet is opened.

- (NSToolbarItem *)toolbar:(NSToolbar *)toolbar 
    itemForItemIdentifier:(NSString *)itemIdentifier
    willBeInsertedIntoToolbar:(BOOL)flag 
{
    return [items objectForKey:itemIdentifier];
}

Since we are holding all of our toolbar items in an NSDictionary and have set their key to be the item's identifier, all we have to do is return the toolbar item for the item in the dictonary that has the identifier as a key.

- (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar*)toolbar
This method returns an array that contains the identifier for each of all the items that are allowed to be displayed in the toolbar. This includes standard items like the separator and the space item.

- (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar*)toolbar
{
    return [items allKeys];
}

We only want to display the items in our dictionary that holds all of our toolbar items. To achieve that, we return an array of the keys for all of the dictionary items. That will make an item's key the identifier for displaying it in the toolbar or in the custimazation pane.

- (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar*)toolbar
This method returns an array of identifiers for the items that you want to use as the default set. The identifiers that are returned is what will be shown if the toolbar has not been customized and will be shown in the custimation pane as the default set.

- (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar*)toolbar
{
    return [[items allKeys] subarrayWithRange:NSMakeRange(0,6)];
}

For our example, we're using the first six elements of the key array as our default set.

NSToolbar's optional delegates are:

- (void)toolbarWillAddItem:(NSNotification *)notification
This delegate is called right before an item is added to a toolbar. Use this method to do any initilization of the toolbar item that it needs. For example, if you have a Print item, its target needs to be set. The @"item" key in the userInfo notification is used to find what item is being added. You can then do your set up if the item requires it.

- (void) toolbarWillAddItem: (NSNotification *) notification
{
    NSToolbarItem *addedItem = [[notification userInfo] objectForKey:@"item"];

    // set up the item here
}

- (void)toolbarDidRemoveItem:(NSNotification *)notification
This delegate is called right after an item is removed from a toolbar. Use it to clear any data that is no longer valid with the item removed. This could be something like a string that's attached to a search field. Use the @"item" key in the userInfo notification to find what item is being added.

- (void)toolbarDidRemoveItem:(NSNotification *)notification
{
    NSToolbarItem *addedItem = [[notification userInfo] objectForKey:@"item"];

    // clear associated info here 
}

 

// Displaying the Toolbar

Now that we have the NSToolbar delegates implemented, all we have to do is attach an instance of NSToolbar to the window. This should be done in either awakeFromNib or windowControllerDidLoadNib if your program is a document-based program. Since we're working with a Cocoa application that isn't document based, we'll attach the toolbar in the awakeFromNib: method.

The first thing we do is create an instance of a NSToolbar. The toolbar's identifier needs to be unique because within the application, all toolbars with the same identifier are synchronized. So, when a toolbar is customized in one window, all toolbars that share its identifier will also be modified.

toolbar = [[NSToolbar alloc] initWithIdentifier:@"tooltest"];

Next, we set the toolbar's properties.

[toolbar setDelegate:self];
[toolbar setAllowsUserCustomization:YES];
[toolbar setAutosavesConfiguration:YES];

The first property we set is the setDelegate. This tells the toolbar that the delegate methods for it are located in the controller class. Next, we set whether the user can customize the toolbar or not. Since we want the user to be able to customize the toolbar, we set the flag to YES. Finally, we set the toolbar to automatically save its current configuration. With this set, the toolbar settings are written to the user defaults when the toolbar's configuration changes.

The last thing we have to do is attach the toolbar to the window.

[window setToolbar:toolbar];

The other property that can be set at this time is -(void)setDisplayMode:(NSToolbarDisplayMode)displayMode. We don't call it since we've opted to use the default mode. If you want your toolbar to display in a different mode, call this method and pass to it one of the following constants: NSToolbarDisplayModeIconAndLabel, NSToolbarDisplayModeIconOnly or NSToolbarDisplayModeLabelOnly. All of them set the toolbar to display exactly the way you'd guess them to from their names.

 

// Viewing the Toolbar

The only thing we have left to do now is implement the the actions we created in IB to show/hide the toolbar and to show the customization sheet.

To show the customization sheet, all you have to do is call the toolbar's runCustomizationPalette: method. Cocoa then handles all work of showing the sheet, displaying the available items, and modifing the toolbar.

- (IBAction)customize:(id)sender 
{ 
    [toolbar runCustomizationPalette:sender]; 
}

The final thing that we have to implement is our showhide: action. It uses the toolbar method setVisible:(BOOL)shown which takes a boolean value of YES to show the toolbar or NO to hide the toolbar. We also use the isVisible method to see whether or not the toolbar is currently visible. It returns YES if the toolbar is shown, NO otherwise. To show or hide the toolbar, we simply negate the value returned by isVisible and pass that value to setVisible:(BOOL)shown.

- (IBAction)showhide:(id)sender 
{ 
    [toolbar setVisible:![toolbar isVisible]]; 
}

 

// Conclusion

As you can see, adding a toolbar to a program is pretty easy. All you have to remember to do is set the delegate and plement the three required delegate methods, and tell the toolbar to show itself. Now go have fun with toolbars. You can download a copy of the sample project here.


Comments

Nice article - thanks.

Apple suggests a different method (and placement) for the "hide/show" and "customize" menu items:

"In Interface Builder, place the Hide Toolbar/Show Toolbar and Customize Toolbar menu items together in that order in the View menu and hook them up to First Responder. NSWindow validates both toolbar menu items and takes care of ensuring that the toggling between Hide Toolbar and Show Toolbar stays in sync with the actual state of the toolbar."

Posted by: Diggory on January 12, 2003 01:10 PM

Thanks for the tutorial, very helpful.

Now, how do you add toolbar items? I've followed the documentation, but i get a sigserv (11) run time error or something.

Thanks.

Posted by: Tom on February 15, 2003 12:16 PM

I'm new to this site... why dont you post a tarball/zip of a whole project? This would be muy helpful so people would futz with the source and IB files.

Posted by: zc on February 17, 2003 02:25 PM

Good article. I'd also like a tarball of the whole project.

Posted by: Karl Bartel on June 3, 2003 02:22 PM

please upload the project on a server. I've read the article but I don't know why I cannot build my app :,-(

Posted by: dr_malcom on June 10, 2003 02:53 PM

Added the sample project to the end of the article. It was lost when the site was reconstructed awhile back and I just got it set back up.

Posted by: Brad on June 11, 2003 11:13 PM

thanks a lot

Posted by: dr_malcom on June 13, 2003 03:12 PM

How do I get rid of unwanted toolbars?

Posted by: Paul on July 28, 2003 09:17 PM
Post a comment