Taming NSTextField with bindings and formatter to behave properly
I want to have a window that needs to accept some user input, for this I have the following:
NSWindow
loaded from nib with NSWindowController
, which is also its delegate NSTextField
's with NSNumberFormatter
NSTextField
's are bound to a integer properties in the NSWindowController
(I didn't used NSObjectController
for simplicity but can add it if needed) NSButton
which the user clicks when finished to accept the changes and close the window windowShouldClose:
method do a final validation and decide whether I can close the window What I want to achieve is pretty simple, yet Cocoa insists on making this challenging:
NSTextField
should accept only a number for it final value, which is also greater than zero Simple enough. The NSNumberFormatter should already cover most of the task and together with the bindings, this should be pretty easy to achieve.
Problem #1:
I couldn't find a way to change the error message that is displayed to the user in the alert when NSTextField
loses focus and the value is incorrect to something more descriptive. Is there any way to do this? Or I need to implement my own NSFormatter somehow?
Problem #2:
When user changes a value in the NSTextField
and clicks on the 'done' button, Cocoa doesn't consider this as a trigger to update the value of the model NSTextField
is bound to. This may be the standard OSX behavior but is something that doesn't make any sense.
I was able to work around this by calling [window makeFirstResponder:nil]
in the action of the 'done' button to force the NSTextField
lose focus and update the value but I wonder if this is the right way to achieve this.
Problem #3:
And here is where I really scratch my head. If the user enters an incorrect value (like non integers) in the NSTextField
and click 'done' button, the validation doesn't kick in and the NSTextField
will continue to have the incorrect values while the model is not updated.
I'd expect that the "invalid" alert will still be displayed and I have some place to insert code to make a decision whether to close the window or not but I couldn't find any way to override this behavior.
What should be the standard practices to achieve these requirements? Should I abandon the formatter and/or bindings and just do it all manually using actions?
For problem 1, try setting a delegate for the text fields and implementing -control:didFailToFormatString:errorDescription:
and possibly -control:didFailToValidatePartialString:errorDescription:
. Present any UI you want, making use of the error description or not.
Alternatively, you can implement a custom subclass of NSNumberFormatter
and override -getObjectValue:forString:errorDescription:
and -isPartialStringValid:proposedSelectedRange:originalString:originalSelectedRange:errorDescription:
. You can call through to super for most of the implementation. If it fails, you can replace the error description that super supplied with a different one. You would use this approach if you need the context of the formatter object (its properties, etc.) to figure out a better error description.
The correct solution to problem 2 is to not programmatically change the first responder. Rather, you should indeed use an NSObjectController
to mediate between the text fields and the window controller. In the action method for the Done button, call either -commitEditing
or -commitEditingWithDelegate:didCommitSelector:contextInfo:
. NSObjectController
inherits those methods from NSController
, which adopts the NSEditor
protocol. When you get the result (synchronously for the former, asynchronously for the latter), you either proceed or do nothing depending on whether the commit succeeded or failed.
I suspect that problem 3 is also a result of programmatically changing the window's first responder. It is often the case that programmatic changes are not subject to the same checks as the corresponding change made due to user action. The frameworks assume you, the programmer know what you're doing, and so it would be "wrong" to subject a programmatic change of focus to validation by the formatter, for example.
链接地址: http://www.djcxy.com/p/14930.html上一篇: 处理控件的输入,并更新所有伴随控件?