Ограничить ввод NSTextField только цифрами?NSNumberformatter - PullRequest
8 голосов
/ 11 января 2011

Я только начинаю с разработки приложений для Mac, и пока все хорошо, у меня просто проблемы, пытаясь заставить NSTextField принимать только цифры для ввода.

Пока что я добавил форматер в NSTextField и установил его так, чтобы он разрешал только десятичную дробь, теперь, когда я ввожу буквы в поле, он все еще позволяет мне, но не позволяет моему щелкнуть по ячейке, когда закончите.

В идеале я бы хотел, чтобы приложение не позволяло пользователю вводить какие-либо буквы, а просто пищит или ничего не делает.

Любые советы или указатели на это были бы замечательно

Ответы [ 5 ]

8 голосов
/ 11 января 2011

Подкласс NSNumberFormatter и реализовать этот метод:

- (BOOL)isPartialStringValid:(NSString **)partialStringPtr
       proposedSelectedRange:(NSRangePointer)proposedSelRangePtr
              originalString:(NSString *)origString
       originalSelectedRange:(NSRange)origSelRange
            errorDescription:(NSString **)error
3 голосов
/ 07 марта 2014

Вот шаги по его созданию:

Просто создайте ANYCLASS (называемый SAMPLE) подклассом NSNumberFormatter, и в файле .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;
}

Теперь в вашем Actual Class установите форматер для вашего объекта NSTextField следующим образом:

NSTextField *mySampleTxtFld;

И для этого установите форматтер:

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

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

Готово!

2 голосов
/ 08 марта 2012

Вот альтернативная реализация:

+ (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;
}

Затем в моем классе контроллера я реализую 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 = @"";
   }
}

Преимущество этого подхода состоит в том, что если вы вставляете текст в свой номерполе, это удалит все нечисловые символы от конца строки, пока у вас не останется только число.Плюс он поддерживает сколь угодно длинный ряд цифр.Некоторые из других подходов не поддерживают ввод ряда цифр, которые не могут быть сохранены в NSInteger.

Я знаю, что этот подход, безусловно, можно улучшить.

1 голос
/ 18 января 2012

Ответ 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: использование [self setIntValue: [self intValue]] ограничило длинувход.

1 голос
/ 13 января 2012

Вместо того, чтобы создавать подклассы, вы можете сделать это с помощью метода 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;
    }
}
...