CamelBones

An Objective-C/Perl bridge framework

 
 
Home / Documentation / Getting Started / Menu Events
 
 

Getting Started - Menu Events

Introduction

For this tutorial, I'll assume you've been following along with the whole "Getting Started" series. In that case, you'll have already have created a Hello project in Project Builder or Xcode. I'll also assume that you've created "Say Hello" and "Say Goodbye" buttons, and connected them to sayHello() and sayGoodbye() methods in your window controller class.

This page describes how to add "Say Hello" and "Say Goodbye" menu items to the MainMenu.nib using Interface Builder and how to connect it to the Responder Chain so that they're handled by the existing methods. It also touches briefly on how to respond to menu events at the application level by defining a method to handle them in the application responder.

Adding a submenu

 
Menu Palette Interface Builder
The Menu palette in Interface Builder
click to enlarge
 
 
Dropping a submenu into place
Dropping the submenu into place.
click to enlarge
 

Open MainMenu.nib in Interface Builder, and select the "Cocoa Menus" pane in the Palette panel. Drag a "Submenu" item to the menu and drop it into place.

You might want to experiment with this a little bit, as the static screen shots shown here can only do so much to give you the feel of it. One important thing to note is that when you drop the new submenu, its position will be determined by where it was dropped within the menu that is selected when you drop it.

This is illustrated by one of the screen shots: The cursor is pointing to the left half of the "Window" menu. So, after that drop is completed, the new menu will appear after the "Edit" menu and before the "Window" menu, which is shown in its expanded state.

Renaming the submenu and its item

When first dropped into place, the submenu is titled "Submenu", and it has a single item under it named "Item". Naturally you'll want to change these titles to something more appropriate.

 
Retitling the submenu in Interface Builder
Editing the submenu title
click to enlarge
 
 
Retitling the menu item in Interface Builder
Editing the menu item title.
click to enlarge
 

To retitle the submenu, double-click its title text to make it editable, and simply enter the new title text. I suggest giving the new submenu a title something like "Speak". To retitle a menu item, expand the parent menu first, then double-click the menu item and edit the title text. Let's call this one "Say Hello".

As an alternative, you can also retitle a submenu or menu item by selecting it, choosing the "Attributes" pane in Interface Builder's "Info" panel, and editing the "Title" box that appears in that.

Adding menu items

 
Adding a item in Interface Builder
Adding a menu item.
click to enlarge
 

Adding a new menu item is similar to adding a submenu. Just drag a "Item" item from the "Cocoa Menus" pane, and drop it where you want it to appear. A thin blue line will be shown while you're dragging it over an existing menu, to show will it will appear when dropped.

Go ahead and add a new item to your "Speak" menu now, and retitle it to "Say Goodbye".

Assigning keyboard shortcuts

 
Creating a keyboard shortcut in Interface Builder
Creating a keyboard shortcut.
click to enlarge
 

Many, or perhaps most menu items have keyboard shortcuts. I've known power users who use these to the extent that referring to them as "shortcuts" isn't really all that accurate; to some, they are the primary interface to menu menu items. To assign a shortcut to your new menu items, first select the menu item. Then, define the shortcut key and modifiers it should use in the "Attributes" panel of Interface Builder's "Info" panel.

Try it out - set keyboard shortcuts for your new menu items. I suggest cmd-shift-H for "Say Hello", and cmd-shift-G for "Say Goodbye".

Making the connection

 
Drawing the connection in Interface Builder
Connecting to First Responder.
click to enlarge
 

First you'll need to create the actions to which you'll connect your menu items. This is nearly identical to the actions you created in the earlier "Responding to Events" tutorial, so I'll leave out most of the detail. The difference is, where you added those actions to the "File's Owner", you need to add these actions to the "First Responder" instead. Double-click the "First Responder" icon, and add an action named "saySomething" in the Info panel.

Connecting them is virtually the same, as well. Expand the menu holding the menu item you wish to connect, so that it's visible. Then, control-drag the connection from the menu item to the "First Responder" icon, and double-click the action you wish to connect it to in Interface Builder's "Info" panel.

You should connect both "Say Hello" and "Say Goodbye" menu items to the "saySomething:" action. If you've been following along through these tutorials, you should have already implemented the Perl method to handle this action in HelloWindowController.pm, in step seven of the earlier " Outlets" tutorial, so there's no more code to write.

Setting the delegate

 
The delegate outlet in Interface Builder
The delegate outlet.
click to enlarge
 

If you build and run your application at this point, you'll notice something odd - the menu items you just created are present, but they're disabled. Why is that? Remember, actions that are connected to the First Responder are sent to the The Responder Chain, which means that a number of objects are checked to see if they respond to the specified action. The Responder Chain is also examined when menus are expanded, and if none of the objects in the chain respond to the action that's defined for a menu item, that item is automatically disabled.

 
Drawing the delegate connection in Interface Builder
Drawing the delegate connection.
click to enlarge
 

So, we need to add the window controller object to the Responder Chain. As you might recall, the Key and Main Windows' delegates are part of the chain. So, what you want to do is tell the Window object to treat your window controller object as its delegate. The easiest way to do that is to use Interface Builder. Open MainWindow.nib, and control-drag a connection from the Window icon to the File's Owner icon, and double-click the "delegate" outlet in the "Info" panel.