Car*_*osa 25 user-interface cocoa objective-c nstextfield
需要一个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]];
}
}
Run Code Online (Sandbox Code Playgroud)
但这肯定不是最好的方法.还有更好的建议吗?
Car*_*osa 46
我按照Graham Lee的建议做了,它工作正常,这是自定义格式化代码:
更新:添加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
Run Code Online (Sandbox Code Playgroud)
Dav*_*her 12
在我评论的上述示例中,这很糟糕:
// Don't use:
- (BOOL)isPartialStringValid:(NSString *)partialString
newEditingString:(NSString **)newString
errorDescription:(NSString **)error
{
if ((int)[partialString length] > maxLength)
{
*newString = nil;
return NO;
}
}
Run Code Online (Sandbox Code Playgroud)
使用此(或类似的东西)代替:
// 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;
}
Run Code Online (Sandbox Code Playgroud)
两者都是NSFormatter方法.第一个有问题.假设您将文本输入限制为10个字符.如果您将字符逐个键入NSTextField,它将正常工作并防止用户超过10个字符.
但是,如果用户要将一个字符串(例如25个字符)粘贴到文本字段中,那么会发生以下情况:
1)用户将粘贴到TextField中
2)TextField将接受字符串
3)TextField将格式化程序应用于25长度字符串中的"last"字符
4)Formatter对25长度字符串中的"last"字符进行填充,忽略其余字符
5)TextField最终将包含25个字符,即使它限制为10个字符.
这是因为,我认为,第一种方法仅适用于键入NSTextField的"最后一个字符".上面显示的第二种方法适用于键入NSTextField的"所有字符".所以它不受"粘贴"攻击的影响.
我刚刚发现这个试图破坏我的应用程序,并且不是NSFormatter的专家,所以如果我错了请纠正我.非常感谢carlosb发布这个例子.它帮了很多!:)
该实现采用了上面提到的几个建议.值得注意的是,它可以正常连续更新绑定.
此外:
它正确实现了粘贴.
它包含一些关于如何在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
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
19709 次 |
| 最近记录: |