Learn Objective-C on the Mac - Mark Dalrymple [108]
Enabling/Disabling With First Responder
Now we’re going to show you a more common way of automatically enabling and disabling menu items, which gives you more fine-grained control, so that the enabled state of each menu item can be updated automatically depending on which window is selected, which text field or other control in a window is selected, and so on. This method works using the responder chain, somewhat similar to how the color panel finds an object to pass a selected color to, as described earlier in this chapter. In this case, the method that’s searched for along the responder chain is validateUserInterfaceItem:, whose declaration looks like this:
If it’s implemented in the responder chain’s objects, this method is called at the appropriate time to see if the user interface item (in this case, a menu item) should be enabled or not. In implementing this method, you can use anItem to get some information about the object that’s going to be enabled or disabled; you can ask it for its action (so you can compare with one of your own methods) and for its tag (in case you’d rather compare against a control tag you’ve established in IB). Usually you’ll just want to use the action. We’ll show you how this works in just a bit, but first we should probably clarify just when this method is called.
Here’s the basic idea: any time Cocoa is about to draw the menu, generally in response to the user clicking on the menu bar, some checks are made for each menu item to determine whether it should be enabled or disabled. The flowchart in Figure 10-8 gives a rough outline of the sequence of events.
Figure 10-8. How the menu system decides whether a menu item should be enabled or not
The upshot of all this is that the menu item’s target object, whether configured explicitly or found in the responder chain, is the one that decides whether the menu item should be enabled (at the current time) or not. This means that you have complete dynamic control over each menu item. By implementing validateUserInterfaceItem: in each of your classes containing methods that are called by menu items, whether directly or through the responder chain, you can define some logic that the menu system calls at the right time, and automatically enables or disables each menu item based on what you return.
Let’s illustrate this with an example. We’ll create a new window in our nib file, matched by a new delegate class just for that window, which will implement validateUserInterfaceItem: to handle the state of a menu item. In a real application, you would probably base it on the content of a model object, but for simplicity’s sake, we’ll enable or disable a menu item based on what’s selected in the window.
Start by creating a new class in Xcode, just a plain NSObject subclass called ListWindowDelegate. In its header, define an integer property called selectedTag, which we’ll later bind to a GUI object (add the lines that are shown in bold):
In the matching .m file, we’re going to synthesize the accessors for the selectedTag property, implement the specialAction: method that a menu item will be connected to with target/action via the First Responder proxy, and implement the validateUserInterfaceItem: method.
We should point out a thing or two about the validateUserInterfaceItem: method. First, you’ll see that we’re using the item’s action to determine what method it would call if clicked. In code, an action (or any kind of method for that matter) can be referred to by the Objective-C SEL type. Technically, a SEL is not a method, but a “selector”: a