Set Maximum Characters (To One) in a Nstextfield in Swift

Set maximum characters (to one) in a NSTextfield in Swift

You don't need to limit the characters a user will enter just only look at the first character entered. In fact, it is probably better since you will always have to handle possible user errors. If you want to you can issue an alert that they entered too many by getting the characters.count. You might want an alert if they don't answer at all. The code below will work as is if you set up a storyboard with 1 NSTextField and one button and connect them. If you have more than one textfield, i.e. like a multiple choice test, just set up all the text fields the same way.

import Cocoa

class ViewController: NSViewController {

@IBOutlet weak var firstLetter: NSTextField!

Add as many text fields as you need:

@IBOutlet weak var secondLetter: NSTextField!

@IBOutlet weak var thirdLetter: NSTextField!

etc.

    @IBAction func button(sender: AnyObject) {

var firstEntry = firstLetter!.stringValue

var index1 = firstEntry.startIndex

if firstEntry.characters.count > 1 {

runMyAlert("Bad USER! ONLY ONE Character!")
}

if firstEntry == "" { //left it blank

runMyAlert("You need to enter at least one character!")
exit(0) //or you'll crash on next line
}

var nameLetter1:Character = firstEntry[index1]

print( "First Letter == \(nameLetter1) ")

}
override func viewDidLoad() {
super.viewDidLoad()

// Do any additional setup after loading the view.
}

override var representedObject: AnyObject? {
didSet {
// Update the view, if already loaded.
}
}

func runMyAlert( alertMessage: String){

var myWindow = NSWindow.self
let alert = NSAlert()
alert.messageText = "ERROR ERROR ERROR"
alert.addButtonWithTitle("OK")
alert.informativeText = alertMessage
alert.runModal()
}
}

How to limit NSTextField text length and keep it always upper case?

I did as Graham Lee suggested and it works fine, here's the custom formatter code:

UPDATED: Added fix reported by Dave Gallagher. Thanks!

@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

SWIFT: Nstextfield allow only specified characters

First add a NSTextFieldDelegate to your class... and then

add this :

 override func controlTextDidChange(obj: NSNotification) {
let characterSet: NSCharacterSet = NSCharacterSet(charactersInString: " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLKMNOPQRSTUVWXYZ0123456789-_").invertedSet
self.textField.stringValue = (self.textField.stringValue.componentsSeparatedByCharactersInSet(characterSet) as NSArray).componentsJoinedByString("")
}

you have to replace self.textfield with your own textfield which you want to control.

SWIFT 4 Edit

 override func controlTextDidChange(_ obj: Notification) {
let characterSet: NSCharacterSet = NSCharacterSet(charactersIn: " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLKMNOPQRSTUVWXYZ0123456789-_").inverted as NSCharacterSet
self.textField.stringValue = (self.textField.stringValue.components(separatedBy: characterSet as CharacterSet) as NSArray).componentsJoined(by: "")
}

COCOA - How to make textfield doesn't allow text entry when max length is reached in NSTextfield?

At its simplest, all you need is to subclass Formatter and override 3 methods:

class MyFormatter: Formatter {
var maxLength = Int.max

override func string(for obj: Any?) -> String? {
return obj as? String
}

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

override func isPartialStringValid(_ partialString: String, newEditingString newString: AutoreleasingUnsafeMutablePointer<NSString?>?, errorDescription error: AutoreleasingUnsafeMutablePointer<NSString?>?) -> Bool {
return partialString.count <= maxLength
}
}

Then set the formatter for your textfield:

let formatter = MyFormatter()
formatter.maxLength = 10

textField.formatter = formatter

This is enough to guard against users typing in more than 10 characters or paste in strings that are long than 10 characters. If you want more advanced features like taking the first 10 characters when pasting in a long string, you should override isPartialStringValid(_:proposedSelectedRange:originalString:originalSelectedRange:errorDescription:).

Restrict NSTextField to only allow numbers

Try to make your own NSNumberFormatter subclass and check the input value in -isPartialStringValid:newEditingString:errorDescription: method.

@interface OnlyIntegerValueFormatter : NSNumberFormatter

@end

@implementation OnlyIntegerValueFormatter

- (BOOL)isPartialStringValid:(NSString*)partialString newEditingString:(NSString**)newString errorDescription:(NSString**)error
{
if([partialString length] == 0) {
return YES;
}

NSScanner* scanner = [NSScanner scannerWithString:partialString];

if(!([scanner scanInt:0] && [scanner isAtEnd])) {
NSBeep();
return NO;
}

return YES;
}

@end

And then set this formatter to your NSTextField:

OnlyIntegerValueFormatter *formatter = [[[OnlyIntegerValueFormatter alloc] init] autorelease];
[textField setFormatter:formatter];

How do I programatically move the cursor from one NSTextField to another after a character count has been reached?

The answer to part of this this question was posted here by @cheesey

here is the complete code to create a window that takes the license key for a product from a user (This is using swift 4).

First set the Text Fields as the delegates and first responders in the viewDidLoad Function and then change the first responder once the string limit is hit

class CommercialActivationView: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
@IBOutlet weak var firsttextfield: NSTextField!
@IBOutlet weak var secondtextfield: NSTextField!
@IBOutlet weak var thirdtextfield: NSTextField!

firsttextfield.window?.makeFirstResponder(firsttextfield)
firsttextfield.delegate = self
}

func makeFirstResponder() {

if firsttextfield.stringValue.count == 5 {
firsttextfield.window?.makeFirstResponder(secondtextfield)
}
if secondtextfield.stringValue.count == 5 {
secondtextfield.window?.makeFirstResponder(thirdtextfield)
}
}
}

Now to create the extension that creates the character limit or the text field every time the user edits the TextField (Here i'm limiting the number of characters per text field to 5).

extension CommercialActivationView: NSTextFieldDelegate {
func controlTextDidChange(_ obj: Notification) {

let object = obj.object as! NSTextField
if object.stringValue.count > 5{
object.stringValue = String(object.stringValue.dropLast())
makeFirstResponder()
}
}

This works such that once 5 characters are reached in 1 TextField it switches to the next one automatically. Also the code I've posted is for 3 TextFields more text fields can be add if needed.

Set the maximum character length of a UITextField

While the UITextField class has no max length property, it's relatively simple to get this functionality by setting the text field's delegate and implementing the following delegate method:

Objective-C

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
// Prevent crashing undo bug – see note below.
if(range.length + range.location > textField.text.length)
{
return NO;
}

NSUInteger newLength = [textField.text length] + [string length] - range.length;
return newLength <= 25;
}

Swift

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

let currentCharacterCount = textField.text?.count ?? 0
if range.length + range.location > currentCharacterCount {
return false
}
let newLength = currentCharacterCount + string.count - range.length
return newLength <= 25
}

Before the text field changes, the UITextField asks the delegate if the specified text should be changed. The text field has not changed at this point, so we grab it's current length and the string length we're inserting (either through pasting copied text or typing a single character using the keyboard), minus the range length. If this value is too long (more than 25 characters in this example), return NO to prohibit the change.

When typing in a single character at the end of a text field, the range.location will be the current field's length, and range.length will be 0 because we're not replacing/deleting anything. Inserting into the middle of a text field just means a different range.location, and pasting multiple characters just means string has more than one character in it.

Deleting single characters or cutting multiple characters is specified by a range with a non-zero length, and an empty string. Replacement is just a range deletion with a non-empty string.

A note on the crashing "undo" bug

As is mentioned in the comments, there is a bug with UITextField that can lead to a crash.

If you paste in to the field, but the paste is prevented by your validation implementation, the paste operation is still recorded in the application's undo buffer. If you then fire an undo (by shaking the device and confirming an Undo), the UITextField will attempt to replace the string it thinks it pasted in to itself with an empty string. This will crash because it never actually pasted the string in to itself. It will try to replace a part of the string that doesn't exist.

Fortunately you can protect the UITextField from killing itself like this. You just need to ensure that the range it proposes to replace does exist within its current string. This is what the initial sanity check above does.

swift 3.0 with copy and paste working fine.

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
let str = (textView.text + text)
if str.characters.count <= 10 {
return true
}
textView.text = str.substring(to: str.index(str.startIndex, offsetBy: 10))
return false
}

Hope it's helpful to you.



Related Topics



Leave a reply



Submit