كيفية تحديد طول نص NSTextField والاحتفاظ به دائمًا بأحرف كبيرة؟

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

سؤال

تحتاج إلى الحصول على NSTextField بحد أقصى للنص يبلغ 4 أحرف ويظهر دائمًا بأحرف كبيرة ولكن لا يمكنك اكتشاف طريقة جيدة لتحقيق ذلك.لقد حاولت القيام بذلك من خلال ربط بطريقة التحقق من الصحة ولكن يتم استدعاء التحقق فقط عندما يفقد عنصر التحكم المستجيب الأول وهذا ليس جيدًا.

لقد نجحت في العمل مؤقتًا من خلال ملاحظة الإشعار 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]];
  }
}

لكن هذه بالتأكيد ليست أفضل طريقة للقيام بذلك.أي اقتراح أفضل؟

هل كانت مفيدة؟

المحلول

وفعلت كما اقترح غراهام لي وأنه يعمل بشكل جيد، وهنا رمز المنسق مخصص:

ومحدث: الإصلاح واضاف ذكرت من قبل ديف غالاغر. شكرا!

@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) سيقوم المستخدم باللصق في TextField

2) سيقبل TextField سلسلة الأحرف

3) سيقوم TextField بتطبيق المنسق على الحرف "الأخير" في السلسلة المكونة من 25 طولًا

4) يقوم المنسق بإجراء أشياء على الحرف "الأخير" في السلسلة المكونة من 25 طولًا، متجاهلاً الباقي

5) سينتهي TextField بـ 25 حرفًا، على الرغم من أنه يقتصر على 10.

هذا لأنني أعتقد أن الطريقة الأولى تنطبق فقط على "الحرف الأخير" المكتوب في NSTextField.تنطبق الطريقة الثانية الموضحة أعلاه على "كافة الأحرف" المكتوبة في NSTextField.لذلك فهو محصن ضد استغلال "اللصق".

لقد اكتشفت هذا للتو أثناء محاولتي تعطيل طلبي، ولست خبيرًا في NSFormatter، لذا يرجى تصحيحي إذا كنت مخطئًا.ولكم جزيل الشكر com.carlosb لنشر هذا المثال.لقد ساعد كثيرا!:)

هل حاولت ربط فئة فرعية 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

وأنا في حاجة إلى المنسق لتحويل إلى أحرف كبيرة لسويفت 4. للاشارة لقد تضمنت هنا:

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

والعادة NSFormatter أن غراهام لي اقترح هو أفضل نهج.

وA حل مشكلة بسيطة سيكون لتعيين تحكم وجهة نظركم مندوبا مجال النص فقط ثم منع أي تعديل ينطوي على غير كبيرة أو يجعل طول أطول من 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