Restrict NSTextField input to numeric only? NSNumberformatter

后端 未结 5 1547
心在旅途
心在旅途 2020-12-06 02:44

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 th

相关标签:
5条回答
  • 2020-12-06 03:06

    Rather than subclassing anything, you can do it with an NSControlTextEditingDelegate method in your view controller. Set the delegate field of the NSTextField you 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.lastValidTimestampCount in this case. This function uses RegExLite to check the value, which may include commas.

    // 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;
        }
    }
    
    0 讨论(0)
  • 2020-12-06 03:13

    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:

    - (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.

    I know this approach could certainly be improved though.

    0 讨论(0)
  • 2020-12-06 03:15

    Subclass NSNumberFormatter and implement this method:

    - (BOOL)isPartialStringValid:(NSString **)partialStringPtr
           proposedSelectedRange:(NSRangePointer)proposedSelRangePtr
                  originalString:(NSString *)origString
           originalSelectedRange:(NSRange)origSelRange
                errorDescription:(NSString **)error
    
    0 讨论(0)
  • 2020-12-06 03:17

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

    // 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.

    0 讨论(0)
  • 2020-12-06 03:29

    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...

    -(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 *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!

    0 讨论(0)
提交回复
热议问题