nstextfield 텍스트 길이를 제한하고 항상 대문자를 유지하는 방법은 무엇입니까?

StackOverflow https://stackoverflow.com/questions/827014

문제

텍스트 제한이 최대 4 자의 Nstextfield가 있어야하며 항상 대문자로 표시되지만이를 달성하는 좋은 방법을 찾을 수는 없습니다. 검증 방법을 사용한 바인딩을 통해 시도했지만 컨트롤이 첫 번째 응답자를 잃을 때만 검증이 호출됩니다.

일시적으로 나는 텍스트 필드에서 NSControltextDidchangenotification을 관찰하고 메소드를 호출함으로써 작동하게 만들었습니다.

- (void)textDidChange:(NSNotification*)notification {
  NSTextField* textField = [notification object];
  NSString* value = [textField stringValue];
  if ([value length] > 4) {
    [textField setStringValue:[[value uppercaseString] substringWithRange:NSMakeRange(0, 4)]];
  } else {
    [textField setStringValue:[value uppercaseString]];
  }
}

그러나 이것은 확실히 그것을하는 가장 좋은 방법이 아닙니다. 더 나은 제안이 있습니까?

도움이 되었습니까?

해결책

나는 Graham Lee가 제안한대로했으며 잘 작동합니다. 여기에 맞춤형 Formatter 코드가 있습니다.

업데이트 : Dave Gallagher 가보고 한 추가 수정. 감사!

@interface CustomTextFieldFormatter : NSFormatter {
  int maxLength;
}
- (void)setMaximumLength:(int)len;
- (int)maximumLength;

@end

@implementation CustomTextFieldFormatter

- (id)init {

   if(self = [super init]){

      maxLength = INT_MAX;
   }

  return self;
}

- (void)setMaximumLength:(int)len {
  maxLength = len;
}

- (int)maximumLength {
  return maxLength;
}

- (NSString *)stringForObjectValue:(id)object {
  return (NSString *)object;
}

- (BOOL)getObjectValue:(id *)object forString:(NSString *)string errorDescription:(NSString **)error {
  *object = string;
  return YES;
}

- (BOOL)isPartialStringValid:(NSString **)partialStringPtr
   proposedSelectedRange:(NSRangePointer)proposedSelRangePtr
          originalString:(NSString *)origString
   originalSelectedRange:(NSRange)origSelRange
        errorDescription:(NSString **)error {
    if ([*partialStringPtr length] > maxLength) {
        return NO;
    }

    if (![*partialStringPtr isEqual:[*partialStringPtr uppercaseString]]) {
      *partialStringPtr = [*partialStringPtr uppercaseString];
      return NO;
    }

    return YES;
}

- (NSAttributedString *)attributedStringForObjectValue:(id)anObject withDefaultAttributes:(NSDictionary *)attributes {
  return nil;
}

@end

다른 팁

내가 댓글을 달린 위의 예에서 이것은 나쁘다.

// Don't use:
- (BOOL)isPartialStringValid:(NSString *)partialString
            newEditingString:(NSString **)newString
            errorDescription:(NSString **)error
{
    if ((int)[partialString length] > maxLength)
    {
        *newString = nil;
        return NO;
    }
}

대신 이것 (또는 그와 비슷한 점)을 사용하십시오.

// Good to use:
- (BOOL)isPartialStringValid:(NSString **)partialStringPtr
       proposedSelectedRange:(NSRangePointer)proposedSelRangePtr
              originalString:(NSString *)origString
       originalSelectedRange:(NSRange)origSelRange
            errorDescription:(NSString **)error
{
    int size = [*partialStringPtr length];
    if ( size > maxLength )
    {
        return NO;
    }
    return YES;
}

둘 다 nsformatter 방법입니다. 첫 번째는 문제가 있습니다. 텍스트 입력을 10 자로 제한한다고 가정 해보십시오. NSTEXTFIELD에 일대일로 캐릭터를 입력하면 잘 작동하고 사용자가 10 자 이상을 넘지 못하게됩니다.

그러나 사용자가 할 경우 반죽 텍스트 필드에 25 자의 문자열은 다음과 같습니다.

1) 사용자는 텍스트 필드에 붙여 넣습니다

2) Textfield는 문자를 수락합니다

3) Textfield는 25 길이의 "마지막"문자에 Formatter를 적용합니다.

4) Formatter는 25 길이의 "마지막"캐릭터에 대한 작업을 수행하여 나머지를 무시합니다.

5) Textfield는 10으로 제한되어 있지만 25 자로 끝납니다.

첫 번째 방법은 Nstextfield에 입력 한 "매우 마지막 캐릭터"에만 적용되기 때문입니다. 위에 표시된 두 번째 방법은 Nstextfield에 입력 한 "모든 문자"에 적용됩니다. 따라서 "페이스트"익스플로잇에 면역이됩니다.

나는 이것을 방금 내 응용 프로그램을 깨뜨리려고 노력했고 NSFormatter의 전문가가 아니 었으므로 내가 틀렸다면 수정 해주세요. 그리고 당신 덕분에 대단히 감사합니다 카를로스 그 예를 게시하기 위해. 그것은 많은 도움이되었습니다! :)

관습을 첨부하려고 했습니까? NSFormatter 아강?

이 구현은 위에서 언급 한 몇 가지 제안을 채택합니다. 특히 바인딩을 지속적으로 업데이트하면서 올바르게 작동합니다.

게다가:

  1. 페이스트를 올바르게 구현합니다.

  2. 여기에는 추가 서브 클래싱없이 클래스를 NIB에서 효과적으로 사용하는 방법에 대한 메모가 포함되어 있습니다.

코드:

@interface BPPlainTextFormatter : NSFormatter {
    NSInteger _maxLength;
}


/*

 Set the maximum string length. 

 Note that to use this class within a Nib:
 1. Add an NSFormatter as a Custom Formatter.
 2. In the Identity inspector set the Class to BPPlainTextFormatter
 3. In user defined attributes add Key Path: maxLength Type: Number Value: 30

 Note that rather than attaching formatter instances to individual cells they
 can be positioned in the nib Objects section and referenced by numerous controls.
 A name, such as Plain Text Formatter 100, can  be used to identify the formatters max length.

 */
@property NSInteger maxLength;

@end


@implementation BPPlainTextFormatter
@synthesize maxLength = _maxLength;

- (id)init
{
    if(self = [super init]){
        self.maxLength = INT_MAX;
    }

    return self;
}

- (id)initWithCoder:(NSCoder *)aDecoder
{
    // support Nib based initialisation
    self = [super initWithCoder:aDecoder];
    if (self) {
        self.maxLength = INT_MAX;
    }

    return self;
}

#pragma mark -
#pragma mark Textual Representation of Cell Content

- (NSString *)stringForObjectValue:(id)object
{
    NSString *stringValue = nil;
    if ([object isKindOfClass:[NSString class]]) {

        // A new NSString is perhaps not required here
        // but generically a new object would be generated
        stringValue = [NSString stringWithString:object];
    }

    return stringValue;
}

#pragma mark -
#pragma mark Object Equivalent to Textual Representation

- (BOOL)getObjectValue:(id *)object forString:(NSString *)string errorDescription:(NSString **)error
{
    BOOL valid = YES;

    // Be sure to generate a new object here or binding woe ensues
    // when continuously updating bindings are enabled.
    *object = [NSString stringWithString:string];

    return valid;
}

#pragma mark -
#pragma mark Dynamic Cell Editing

- (BOOL)isPartialStringValid:(NSString **)partialStringPtr
       proposedSelectedRange:(NSRangePointer)proposedSelRangePtr
              originalString:(NSString *)origString
       originalSelectedRange:(NSRange)origSelRange
            errorDescription:(NSString **)error
{
    BOOL valid = YES;

    NSString *proposedString = *partialStringPtr;
    if ([proposedString length] > self.maxLength) {

        // The original string has been modified by one or more characters (via pasting).
        // Either way compute how much of the proposed string can be accommodated.
        NSInteger origLength = origString.length;
        NSInteger insertLength = self.maxLength - origLength;

        // If a range is selected then characters in that range will be removed
        // so adjust the insert length accordingly
        insertLength += origSelRange.length;

        // Get the string components
        NSString *prefix = [origString substringToIndex:origSelRange.location];
        NSString *suffix = [origString substringFromIndex:origSelRange.location + origSelRange.length];
        NSString *insert = [proposedString substringWithRange:NSMakeRange(origSelRange.location, insertLength)];

#ifdef _TRACE

        NSLog(@"Original string: %@", origString);
        NSLog(@"Original selection location: %u length %u", origSelRange.location, origSelRange.length);

        NSLog(@"Proposed string: %@", proposedString);
        NSLog(@"Proposed selection location: %u length %u", proposedSelRangePtr->location, proposedSelRangePtr->length);

        NSLog(@"Prefix: %@", prefix);
        NSLog(@"Suffix: %@", suffix);
        NSLog(@"Insert: %@", insert);
#endif

        // Assemble the final string
        *partialStringPtr = [[NSString stringWithFormat:@"%@%@%@", prefix, insert, suffix] uppercaseString];

        // Fix-up the proposed selection range
        proposedSelRangePtr->location = origSelRange.location + insertLength;
        proposedSelRangePtr->length = 0;

#ifdef _TRACE

        NSLog(@"Final string: %@", *partialStringPtr);
        NSLog(@"Final selection location: %u length %u", proposedSelRangePtr->location, proposedSelRangePtr->length);

#endif
        valid = NO;
    }

    return valid;
}

@end

Swift 4를 위해 대문자로 변환하기 위해서는 Formatter가 필요했습니다. 참조를 위해 여기에 포함 시켰습니다.

import Foundation

class UppercaseFormatter : Formatter {

    override func string(for obj: Any?) -> String? {
        if let stringValue = obj as? String {
            return stringValue.uppercased()
        }
        return nil
    }

    override func getObjectValue(_ obj: AutoreleasingUnsafeMutablePointer<AnyObject?>?, for string: String, errorDescription error: AutoreleasingUnsafeMutablePointer<NSString?>?) -> Bool {
        obj?.pointee = string as AnyObject
        return true
    }
}

Graham Lee가 제안한 Custom Nsformatter는 최선의 방법입니다.

간단한 kludge는 텍스트 필드의 대의원으로보기 컨트롤러를 설정 한 다음 비 업 퍼 케이스와 관련된 편집을 차단하거나 길이를 4보다 길게 만드는 것입니다.

- (BOOL)textField:(UITextField *)textField
    shouldChangeCharactersInRange:(NSRange)range
    replacementString:(NSString *)string
{
    NSMutableString *newValue = [[textField.text mutableCopy] autorelease];
    [newValue replaceCharactersInRange:range withString:string];

    NSCharacterSet *nonUppercase =
        [[NSCharacterSet uppercaseLetterCharacterSet] invertedSet];
    if ([newValue length] > 4 ||
        [newValue rangeOfCharacterFromSet:nonUppercase].location !=
            NSNotFound)
    {
       return NO;
    }

    return YES;
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top