macos 将 NSTextField 输入限制为仅数字?NSNumberformatter

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4652689/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 07:35:18  来源:igfitidea点击:

Restrict NSTextField input to numeric only? NSNumberformatter

objective-ccocoamacosnstextfield

提问by MonkeyBlue

I'm just getting started up with Mac App Development and so far everything is good well, I'm just having problems trying to get a NSTextField to only accept numbers for the input.

我刚刚开始使用 Mac 应用程序开发,到目前为止一切都很好,我只是在尝试让 NSTextField 只接受输入数字时遇到问题。

So far I have added a formatter to the NSTextField and set it to only allow decimal now when I enter letters in the field it still allows me but does not allow my to click out of the cell when done.

到目前为止,我已经向 NSTextField 添加了一个格式化程序并将其设置为现在只允许十进制,当我在字段中输入字母时它仍然允许我但不允许我在完成后单击单元格。

Ideally I would like the app not to let the user type in any letters and just beep or do nothing.

理想情况下,我希望应用程序不要让用户输入任何字母,然后只发出哔哔声或什么都不做。

Any tips or pointers on this would be great

任何关于此的提示或指示都会很棒

采纳答案by Mike Abdullah

Subclass NSNumberFormatterand implement this method:

子类化NSNumberFormatter并实现此方法:

- (BOOL)isPartialStringValid:(NSString **)partialStringPtr
       proposedSelectedRange:(NSRangePointer)proposedSelRangePtr
              originalString:(NSString *)origString
       originalSelectedRange:(NSRange)origSelRange
            errorDescription:(NSString **)error

回答by VSN

Here are the steps to create the same:

以下是创建相同内容的步骤:

Just create the ANYCLASS (called SAMPLE) subclassing the NSNumberFormatter, and in the .m file write the following code...

只需创建子类 NSNumberFormatter 的 ANYCLASS(称为 SAMPLE),并在 .m 文件中编写以下代码...

-(BOOL)isPartialStringValid:(NSString *)partialString newEditingString:(NSString **)newString errorDescription:(NSString **) error {
    // Make sure we clear newString and error to ensure old values aren't being used
    if (newString) { *newString = nil;}
    if (error)     {*error = nil;}

    static NSCharacterSet *nonDecimalCharacters = nil;
    if (nonDecimalCharacters == nil) {
        nonDecimalCharacters = [[NSCharacterSet decimalDigitCharacterSet] invertedSet] ;
    }

    if ([partialString length] == 0) {
        return YES; // The empty string is okay (the user might just be deleting everything and starting over)
    } else if ([partialString rangeOfCharacterFromSet:nonDecimalCharacters].location != NSNotFound) {
        return NO; // Non-decimal characters aren't cool!
    }

    return YES;
}

Now in your Actual Class set the formatter to your NSTextField object like this:

现在在您的实际类中将格式化程序设置为您的 NSTextField 对象,如下所示:

NSTextField *mySampleTxtFld;

And for this set the Formatter:

并为此设置格式化程序:

SAMPLE* formatter=[[SAMPLE alloc]init]; // create SAMPLE FORMATTER OBJECT 

self.mySampleTxtFld.delegate=self;
[self.mySampleTxtFld setFormatter:formatter];

You're done!

你完成了!

回答by Tap Forms

Here's an alternative implementation:

这是一个替代实现:

+ (BOOL)stringIsNumber:(NSString *)str {
   BOOL valid;
   double holder;
   NSScanner *scan = [NSScanner scannerWithString: str];
   valid = [scan scanDouble:&holder] && [scan isAtEnd];
  return valid;
}

+ (NSString *)numericStringFromString:(NSString *)string {
    NSString *digitsString = string;
    if (![YOURCLASSNAME stringIsNumber:string]) {
        NSUInteger length = [string length];
        if (length > 0) {
            digitsString = [string substringToIndex:length - 1];
            if (![YOURCLASSNAME stringIsNumber:digitsString]) {
                digitsString = [YOURCLASSNAME numericStringFromString:digitsString];
            }
        }
    }
    return digitsString;
}

Then in my controller class, I implement controlTextDidChange:

然后在我的控制器类中,我实现了 controlTextDidChange:

- (void)controlTextDidChange:(NSNotification *)obj {
   NSString *digitsString = [YOURCLASSNAME numericStringFromString:self.currentCellView.textField.stringValue];
   if (digitsString) {
    self.currentCellView.textField.stringValue = digitsString;
   } else {
    self.currentCellView.textField.stringValue = @"";
   }
}

The benefit of this approach is that if you paste text into your number field, this will strip out all the non numeric characters from the end of the string until you're left with just a number. Plus it supports an arbitrarily long series of digits. Some of the other approaches would not support putting in a series of digits that couldn't be held in an NSInteger.

这种方法的好处是,如果您将文本粘贴到您的数字字段中,这将去除字符串末尾的所有非数字字符,直到只剩下一个数字。此外,它还支持任意长的数字序列。其他一些方法不支持放入不能保存在 NSInteger 中的一系列数字。

I know this approach could certainly be improved though.

我知道这种方法当然可以改进。

回答by NPAssoc

Rather than subclassing anything, you can do it with an NSControlTextEditingDelegatemethod in your view controller. Set the delegatefield of the NSTextFieldyou want to check and then do something like the following in a controlTextDidChange:function which gets called on each character typed. Don't forget to initialize self.lastValidTimestampCountin this case. This function uses RegExLiteto check the value, which may include commas.

您可以使用NSControlTextEditingDelegate视图控制器中的方法来实现,而不是继承任何东西。设置您要检查的delegate字段,NSTextField然后在一个controlTextDidChange:函数中执行类似以下操作,该函数在输入的每个字符上调用。self.lastValidTimestampCount在这种情况下不要忘记初始化。此函数用于RegExLite检查值,其中可能包含逗号。

// Make sure the user has typed a valid number so far.
- (void)controlTextDidChange:(NSNotification *)obj
{
    if (obj.object == self.timestampsCount)
    {
        NSString *countValue = timestampsCount.stringValue;
        if (! [countValue isMatchedByRegex:@"^[\d\,]{1,6}$"])
        {
            timestampsCount.stringValue = self.lastValidTimestampCount;
            NSBeep();
        }
        else
            self.lastValidTimestampCount = timestampsCount.stringValue;
    }
}

回答by jeswang

NPAssoc's Answer did help me and I did a little change to the code which did not use isMatchedByRegex function.

NPAssoc 的回答确实帮助了我,我对没有使用 isMatchedByRegex 函数的代码做了一些改动。

// Make sure the user has typed a valid number so far.
- (void)controlTextDidChange:(NSNotification *)obj
{
    if (obj.object == self->number)
    {
        NSString *countValue = number.stringValue;        
        if ([countValue length] > 0) {
            if ([[countValue substringFromIndex:[countValue length]-1] integerValue] > 0 ||
                [[countValue substringFromIndex:[countValue length]-1] isEqualToString:@"0"])
            {
                self.lastNumber = number.stringValue;
            }
            else
            {
                number.stringValue = self.lastNumber;
                NSBeep();
            }
        }
    }
}

PS:Use the [self setIntValue:[self intValue]] limited the length of the input.

PS:使用[self setIntValue:[self intValue]]限制输入的长度。