2009-02-09 111 views
5

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

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

我有“连续更新值”在界面生成器中检查。

(我也注意到,setter方法接受一个NSString,而不是一个NSNumber。那是正常的吗?)

什么是的NSTextField挂接到一个NSNumber的正确方法是什么? setter方法对于属性是什么样的?如何防止在文本字段中显示非数字值?

回答

0

我认为你需要设置一个数字格式到你的NSTextField

请阅读Apple网站上的格式化程序:Applying Formatters

+0

我掉到地上的文本字段添加了一个数字格式化为你指出的文档建议,但没有任何反应。我仍然可以键入非数字字符。除了将格式器连接到文本字段之外,我还需要做什么? – lajos 2009-02-09 17:23:18

1

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

如果您不喜欢模式对话框NSNumberFormatter在用户输入非数值时抛出,您可以继承NSNumberFormatter以实现不同的“更宽容”格式化行为。我认为重写 - numberFromString:在调用超级实现之前去除非数字字符应该做的伎俩。

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

More about value transformers

10

I send the willChangeValueForKey: and didChangeValueForKey:, but the UI doesn't update to the new values while that text field is still active.

有发送这些消息很少的原因。通常,通过实现和使用访问器(或更好的属性),您可以更好,更干净地完成同样的工作。 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; 
    } 
} 

(I've also noticed that the setter method receives an NSString, not an NSNumber. Is that normal?)

是的,除非你使用值转换器是转换字符串到数字,一个数字格式化连接到formatter出口,或替代验证方法中的NSString的NSNumber。

+0

验证方法似乎有以下签名: - (BOOL)validateNewValue:(id *)ioValue error:(NSError **)outError; 但即使我使用正确的签名实现方法并返回NO或更正值,文本字段仍显示非数字字符。 – lajos 2009-02-09 17:09:35

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]; 
} 
相关问题