使用绑定和格式化程序来驯服NSTextField以使其正常运行

时间:2013-12-05 16:40:48

标签: objective-c macos cocoa

我想要一个需要接受一些用户输入的窗口,为此我有以下内容:

  • NSWindow从带有NSWindowController的nib加载,也是其委托
  • NSTextField的一对NSNumberFormatter
  • 使用绑定,NSTextField绑定到NSWindowController中的整数属性(为简单起见,我没有使用NSObjectController,但可以根据需要添加它)
  • 用户点击完成后接受更改并关闭窗口的“完成”NSButton
  • 在控制器的windowShouldClose:方法中进行最终验证并决定是否可以关闭窗口

我想要实现的目标非常简单,但Cocoa坚持要做到这一点具有挑战性:

  • NSTextField只接受一个数字作为最终值,也就是大于零
  • 如果用户尝试插入非数字值或零,则应该有提示用户修改其条目的提醒
  • 当用户点击完成时:
    • 进行其他自定义验证(例如,比较一个数字是否比另一个更好)
    • 如果值正确,请接受更改并关闭窗口(“模型”应该已经通过绑定更新了值)
    • 如果值不正确,系统会提示用户选择是修复条目(保持窗口打开)还是关闭窗口并放弃更改

足够简单。 NSNumberFormatter应该已经涵盖了大部分任务,并且与绑定一起,这应该很容易实现。

问题#1:

我无法找到一种方法来更改在NSTextField失去焦点时更改警告中向用户显示的错误消息,并且该值对于更具描述性的内容不正确。有没有办法做到这一点?或者我需要以某种方式实现我自己的NSFormatter?

问题#2:

当用户更改NSTextField中的值并单击“完成”按钮时,Cocoa不会将此视为更新模型NSTextField绑定的值的触发器。这可能是标准的OSX行为,但是没有任何意义。

我能够通过在“完成”按钮的操作中调用[window makeFirstResponder:nil]来强制NSTextField失去焦点并更新值,但我想知道这是否是正确的方法实现这一目标。

问题#3:

这就是我真正挠头的地方。如果用户在NSTextField中输入了错误的值(如非整数)并单击“完成”按钮,则验证不会启动,NSTextField将继续使用不正确的值没有更新。

我希望仍会显示“无效”警告,并且我有一些地方可以插入代码来决定是否关闭窗口,但我找不到任何方法来覆盖此行为。< / p>

达到这些要求的标准做法应该是什么?我是否应该放弃格式化程序和/或绑定,并使用操作手动完成所有操作?

1 个答案:

答案 0 :(得分:1)

对于问题1,请尝试为文本字段设置委托并实施-control:didFailToFormatString:errorDescription:-control:didFailToValidatePartialString:errorDescription:。提供您想要的任何UI,或者使用错误描述。

或者,您可以实现NSNumberFormatter的自定义子类并覆盖-getObjectValue:forString:errorDescription:-isPartialStringValid:proposedSelectedRange:originalString:originalSelectedRange:errorDescription:。您可以通过super调用大部分实现。如果失败,您可以替换超级提供的错误描述。如果您需要格式化程序对象的上下文(其属性等)以找出更好的错误描述,则可以使用此方法。

问题2的正确解决方案是不以编程方式更改第一响应者。相反,您确实应该使用NSObjectController在文本字段和窗口控制器之间进行调解。在“完成”按钮的操作方法中,调用-commitEditing-commitEditingWithDelegate:didCommitSelector:contextInfo:NSObjectControllerNSController继承了那些采用NSEditor协议的方法。当您获得结果(同步为前者,后者为异步)时,您可以继续执行或不执行任何操作,具体取决于提交是成功还是失败。

我怀疑问题3也是以编程方式更改窗口的第一响应者的结果。通常情况下,程序化更改不会受到与用户操作所做的相应更改相同的检查。框架假设您,程序员知道您正在做什么,因此将编程更改重点放在格式化程序的验证上是“错误的”,例如。