Restrict input on NSTextField

1.1k views Asked by At

I want to restrict character input on NSTextField, i.e. so that disallowed characters aren't even appearing. Most of what I found about this topic were solutions that only validate after text input finished or using NSFormatter which still allows the character to appear.

So far I came up with this solution, sub-classing NSTextField:

class RestrictedTextField : NSTextField
{
    static let VALID_CHARACTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'-.& ";

    override func textDidChange(notification:NSNotification)
    {
        for c in stringValue
        {
            if (RestrictedTextField.VALID_CHARACTERS.rangeOfString("\(c)") == nil)
            {
                stringValue = stringValue.stringByReplacingOccurrencesOfString("\(c)", withString: "", options: .LiteralSearch, range: nil);
                break;
            }
        }
    }
}

It works but isn't really optimal because the textcursor still moves by one space if an invalid character is tried to be entered. I also think the loop shouldn't be necessary so I wonder does somebody know a more elegant solution for this?

1

There are 1 answers

1
Ken Thomases On BEST ANSWER

You have complete control with a subclass of NSFormatter. I'm not sure why you think you don't.

Override isPartialStringValid(_:proposedSelectedRange:originalString:originalSelectedRange:errorDescription:) and implement the desired logic. From the docs (with some minor edits by me):

In a subclass implementation, evaluate [the string pointed to by *partialStringPtr] according to the context. Return YES if partialStringPtr is acceptable and NO if partialStringPtr is unacceptable. Assign a new string to partialStringPtr and a new range to proposedSelRangePtr and return NO if you want to replace the string and change the selection range.

So, if the user tries to insert disallowed characters, you can either reject their edit in its entirety or modify it to strip those disallowed characters. (Remember that user changes can include pasting, so it's not necessarily just a single typed character.) To reject the change entirely, assign origString to *partialStringPtr and origSelRange to *proposedSelRangePtr.