Tabbed windows and NSToolbarItems

Published
23 August 2013
Tagged

Update: I've since published a better way to do this whole thing. So give this article a read-through if you want, but check the link once you're done here.


While tricky to explain, this sort of thing is all over the place in Cocoa applications:

Preferences in XCode. Tabbed using a toolbar.

Preferences in XCode. Tabbed using a toolbar.

You have a tabbed view that takes up the entire main window, controller by a toolbar with a series of icons. This sort of thing is so common in Cocoa applications that it's probably more common than the actual NSTabView:

A sample NSTabView

A sample NSTabView

When I wanted to split up my preferences window in Assign, I found myself wanting to make one of these tabbed views. Strangely enough, this sort of thing isn't default.

It's actually pretty easy - just not immediately obvious.

Setting up the .nib

This bit is pretty easy: add an NSToolbar to the window to start, and put whatever icons you want in it. I tend to make mine non-customisable, since the user shouldn't be screwing around with adding/subtracting icons from this toolbar:

Adding an NSToolbar in XCode

Adding an NSToolbar in XCode

Now add an NSTabView to the window. Change the style of the NSTabView so no tabs are visible up the top, and make the thing take up the whole window:

An NSTabView without visible tabs? Madness.

An NSTabView without visible tabs? Madness.

Make sure you have one subview per icon in your toolbar.

Writing the code

Now all we need is one controlling method to programmatically change the selected subview when the toolbar is clicked:

-(IBAction)toolbarButtonClicked:(id)sender {
  [tabView selectTabViewItemWithIdentifier:[sender itemIdentifier]];
}

That was relatively painless! It works by a little bit of magic which involves having matching identifiers for your toolbars and tab views. When you select a toolbar item in Xcode, you'll see that it has an "identifier" field:

Identifier field for NSToolbarItem

Identifier field for NSToolbarItem

Each of these should be a unique number. You get a similar identifier field for NSTabbedView subviews:

Identifier field for NSTabView

Identifier field for NSTabView

As long as the toolbar item matches up to a subview, you get incredibly easy switching.

Linking up

The only thing you need to do now is link up every NSToolbarItem's selector to the appropriate method in the nib's controller. Since the NSToolbar itself doesn't have a selector property, you do have to link up each item.