5

我正在尝试使用 NSTextField 进行整数用户输入。文本字段绑定到 NSNumber 属性,在 setter 方法中我清理输入值(确保它是 int)并在必要时设置属性。我发送 willChangeValueForKey: 和 didChangeValueForKey:,但是当该文本字段仍处于活动状态时,UI 不会更新为新值。

因此,例如,我可以在 setter 方法清理到“12”的文本字段中键入“12abc”,但文本字段仍显示“12abc”。

我在界面生成器中选中了“持续更新值”。

(我还注意到 setter 方法接收的是 NSString,而不是 NSNumber。这正常吗?)

将 NSTextField 连接到 NSNumber 的正确方法是什么?属性的 setter 方法是什么样的?如何防止非数值出现在文本字段中?

4

4 回答 4

10

我发送 willChangeValueForKey: 和 didChangeValueForKey:,但是当该文本字段仍处于活动状态时,UI 不会更新为新值。

发送这些消息的理由很少。通常,您可以通过实现和使用访问器(或者更好的是属性)来更好、更干净地完成相同的工作。当您这样做时,KVO 会为您发送通知。

在您的情况下,您想要拒绝或过滤虚假输入(如“12abc”)。此任务的正确工具是键值验证。

要启用此功能,请选中 IB 中绑定上的“立即验证”框,并实施验证方法。

过滤:

- (BOOL) validateMyValue:(inout NSString **)newValue error:(out NSError **)outError {
    NSString *salvagedNumericPart;
    //Determine whether you can salvage a numeric part from the string; in your example, that would be “12”, chopping off the “abc”.
    *newValue = salvagedNumericPart; //@"12"
    return (salvagedNumericPart != nil);
}

拒绝:

- (BOOL) validateMyValue:(inout NSString **)newValue error:(out NSError **)outError {
    BOOL isEntirelyNumeric;
    //Determine whether the whole string (perhaps after stripping whitespace) is a number. If not, reject it outright.
    if (isEntirelyNumeric) {
        //The input was @"12", or it was @" 12 " or something and you stripped the whitespace from it, so *newValue is @"12".
        return YES;
    } else {
        if (outError) {
            *outError = [NSError errorWithDomain:NSCocoaErrorDomain code: NSKeyValueValidationError userInfo:nil];
        }
        //Note: No need to set *newValue here.
        return NO;
    }
}

(我还注意到 setter 方法接收的是 NSString,而不是 NSNumber。这正常吗?)

是的,除非您使用将字符串转换为数字的值转换器,将数字格式化程序连接到formatter插座,或在验证方法中用 NSNumber 替换 NSString。

于 2009-02-09T09:03:23.623 回答
2

关于彼得·霍西(Peter Hosey)的出色回答有一个重要的评论,我想将其提升到最高水平(因为我在第一次通过时错过了它)。

如果您想在每次输入字符时验证/修改 NSTextField,而不是仅在用户提交字段时验证/修改,那么您无法仅从绑定中获得所需的内容。您需要为文本字段分配一个委托,然后- (void)controlTextDidChange:(NSNotification *)aNotification在委托中实现。每次文本更改时都会调用它。如果需要,您可以在 中调用值验证器controlTextDidChange

例如:

- (void)controlTextDidChange:(NSNotification *)aNotification
{
    NSError *outError;
    NSControl *textField = [aNotification object];
    NSString *myText = [textField stringValue];

    // myObject is the model object that owns the text in question
    // the validator can modify myText by reference
    [myObject validateValue:&myText error:&outError]];

    // update the NSNextField with the validated text
    [postingObject setStringValue:myText];
}
于 2009-05-07T19:44:48.327 回答
1

就像 Ben 提到的那样,一种方法是将 NSNumberFormatter 附加到您的文本字段,这在界面构建器中设置非常简单,并且很可能是 Just Work™。

如果您不喜欢 NSNumberFormatter 在用户输入非数字值时向他们抛出的模态对话框,您可以将 NSNumberFormatter 子类化以实现不同的“更宽容”的格式化行为。我认为覆盖 - numberFromString: 在调用 super 的实现之前去除非数字字符应该可以解决问题。

另一种方法是创建并注册您自己的 NSValueTransformer 子类以将字符串解析为 NSNumbers 并返回,但我会先尝试使用 NSNumberFormatter,因为它很明显是为此目的而设计的类。

有关价值转换器的更多信息

于 2009-02-09T08:31:42.810 回答
0

我认为您需要为您的NSTextField.

在 Apple 的网站上阅读有关格式化程序的信息:应用格式化程序。

于 2009-02-09T07:23:56.637 回答