5

I have a NSTextField bound to my model. If I change the content of the text field programmatically, the model isn't updated. I know that you're supposed to update the model instead.

But I'm trying to implement an NSTextField subclass that recognizes a scroll while the mouse is hovering over it to change it's numerical value. Obviously I don't have access to the model from this subclass. So you have any suggestions how I could do this?

SOLUTION (thanks to noa):

- (void)scrollWheel:(NSEvent *)theEvent {
    [self setFloatValue:[self floatValue] - [theEvent deltaY]];
    NSDictionary *bindingInfo = [self infoForBinding: NSValueBinding];
    NSObject *boundObject = [bindingInfo valueForKey:NSObservedObjectKey];
    NSString *keyPath = [bindingInfo valueForKey:NSObservedKeyPathKey];
    [boundObject setValue:[NSNumber numberWithFloat:[self floatValue]]
               forKeyPath:keyPath];
}
DrummerB
  • 39,814
  • 12
  • 105
  • 142

1 Answers1

6

You could either use target–action or Cocoa Bindings:

  1. Target–action: connect the text field's action selector to some updateValue action of the controller. Then, in the text field, invoke the selector after you change the text field's value. The action should fetch the text field's value and propagate it to the model.

  2. Cocoa Bindings: Set the text field's Value binding to a KVO-compliant property of a model object. Then you can update the cell's value and the binder will update the model object for you.

The advantage of these particular designs is that the coupling between the text field and the model property is handled either with the binding or the target. If you wanted to use a text field for a different property, you could just use a different action or a different binding, without modifying the custom text field code.

I'd probably use bindings, myself, which I consider to be less work, but target–action is perfectly fine too, and a little more straightforward.


Indeed, you did say "bound." I thought programmatic changes to the text field triggered an update, but since that's not the case, you can update the bound value yourself. Here's some code you can try:

NSDictionary *bindingInfo = [self infoForBinding:NSValueBinding];
[[bindingInfo valueForKey:NSObservedObjectKey] setValue:self.integerValue
                                             forKeyPath:[bindingInfo valueForKey:NSObservedKeyPathKey]];
paulmelnikow
  • 16,895
  • 8
  • 63
  • 114
  • As I said, I'm using bindings. My text field's value is bound to a KVO-compliant property of my model object. My problem is, that the binding only updates the model object's property when I change the text field's value by hand, but not when it's changed programmatically. – DrummerB May 15 '12 at 17:13
  • My mistake, I thought programmatic updates to bound controls did update the model. I'll look for some code to post. – paulmelnikow May 15 '12 at 17:14
  • Unfortunately that's not the case. Thanks for trying to help! – DrummerB May 15 '12 at 17:17
  • Thanks a lot, that did the trick! I had to wrap the value in a NSNumber object, but it works now. I updated my question with what I ended up using. I placed a bounty on an older, same question. If you answer there, I can award it to you. Otherwise I'll link to this question as an answer. http://stackoverflow.com/questions/8310236/how-to-overload-a-nstextfield-to-react-on-scrolling – DrummerB May 15 '12 at 17:39
  • Thanks! I just did so. Also, I remembered Cocoa has constants for the binding names and updated my code to reflect that. – paulmelnikow May 15 '12 at 17:47