/dev/trouble
Eric Roller's Development Blog

Using a popup menu to allow the user to select the (integer) value of an object can be easily done through binding the selectionIndex. However, what if you wanted to launch an update method when the selection changes, you have two options:

  • Assign a target to each menu item
  • Assign a target to the menu itself

I made the mistake of trying the first option, assigning the same target to each of the menu items. This effectively disabled the selectionIndex binding, rendering the popup menu completely useless.

It appears as if the only solution is to assign a target to the menu, not its items!

If you ask me, this is a bug: binding "enabled" of an NSMenuItem to anything does not make any difference. It seems that the target of the menu item needs to tackle the issue in the conventional manner, i.e. through the method:

- (BOOL) validateMenuItem:(NSMenuItem*)item
{
    if (itemShouldBeEnabled)
        return YES;

    return NO;
}

The downside of this is that the target may need access to other objects that would have beeen simple to achieve through the binding mechanism, sigh.

Two issues today: A simple mini-dialog box with a text field and an ok button. Editing the text field and pressing "ok" did not change the value in the target that is bound to the text field. It turns out, the editing is not finished when we press the button (unless the user presses "tab" or possibly "return"). We can force editing to end through this construct in the action of the ok button:

- (IBAction) ok:(id)sender
{
    // ask the window to take the focus away from the edit field,
    // thus stop editing and take over the value.
    if ([[sender window] makeFirstResponder:sender])
    {
        [NSApp endSheet:[sender window]
             returnCode:NSAlertDefaultReturn];
        [[sender window] orderOut:self];
    }
}

When the value was updated, I got this error in the console:

2006-03-16 23:41:50.940 MyApp[547] ***
-[NSCFString unsignedLongValue]: selector not recognized

This is because the object in the dictionary has been set to a string, not a number:

(gdb) print-object [[data objectForKey:@"teve"] class]
NSCFNumber
...
(gdb) print-object [[data objectForKey:@"teve"] class]
NSCFString

... and the string does not support "unsignedLongValue". This could easily be solved by attaching a NSNumberFormatter to the NSTextField, by which means it is also ensured that one only gets legal numbers (e.g. no floating point values and minimum set to 0).