os x nstextfield validation
Generic solution (work with or without bindings) One way of dealing with this is based on the response here
Basically you use the controlTextDidChange(notification:)
delegate method of NSTextField
and you implement your validation code in it.
override func controlTextDidChange (notification: NSNotification) {
guard let textField = notification.object as? NSTextField else { return }
// test here, replace the dummy test below with something useful
if textField.stringValue != "expected value" {
myTextFieldOutlet.backgroundColor = NSColor.red
myErrorLabelOutlet.stringValue = "Error !!!"
} else {
// everything OK, reset the background color and error label to the normal state
....
}
}
Obviously myTextFieldOutlet
is an outlet linked to your text field and myErrorLabelOutlet
is an outlet to a conveniently placed label used to show errors (blank if no error should be presented)
Bindings oriented solution Be sure Validates immediately
is selected in Interface Builder and implement the following method in the class where the binding is made (Tuning View Controller
in your example)
override func validateValue(_ ioValue: AutoreleasingUnsafeMutablePointer<AnyObject?>, forKey inKey: String) throws {
// test here, replace the dummy test below with something useful
if roll_rate > 10.0 {
throw NSError(domain: "your-domain", code: 100, userInfo: [NSLocalizedDescriptionKey: "Error, roll rate too high"])
}
}
When the error is thrown, the user will be presented with the standard sheet announcing the error and the option to cancel the change or correct it.
If Continuously updates value
is selected in Interface Builder the method above will be called for each keystroke in the text field, otherwise only after pressing Enter
or loosing focus.
Note: For a full understanding on how updating values through bindings work, including what Validates immediately
does, see the docs here.
How to live check a NSTextField - Swift OS X
- Conforms
ViewController
to protocolNSTextDelegate
. - Assign
ViewController
as Delegate forTextField
. Implement
controlTextDidChange
method.import Cocoa
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate, NSTextFieldDelegate {
@IBOutlet weak var window: NSWindow!
@IBOutlet weak var textField: NSTextField!
@IBOutlet weak var label: NSTextField!
func applicationDidFinishLaunching(aNotification: NSNotification)
{
textField.delegate = self
}
override func controlTextDidChange(notification: NSNotification)
{
let object = notification.object as! NSTextField
self.label.stringValue = object.stringValue
}
func applicationWillTerminate(aNotification: NSNotification) {
// Insert code here to tear down your application
}
}
in ViewController:
import Cocoa
class ViewController: NSViewController, NSTextDelegate {
@IBOutlet weak var label: NSTextField!
@IBOutlet weak var label2: NSTextField!
@IBOutlet weak var textField: NSTextField!
@IBOutlet weak var textField2: NSTextField!
override func viewDidLoad() {
super.viewDidLoad()
}
override func controlTextDidChange(notification: NSNotification) {
if let txtFld = notification.object as? NSTextField {
switch txtFld.tag {
case 201:
self.label.stringValue = txtFld.stringValue
case 202:
self.label2.stringValue = txtFld.stringValue
default:
break
}
}
}
}
How to validate NSTextField content in a modal dialog
clicking the OK button does not trigger the field's formatting and thus the alert does not show.
Call makeFirstResponder(nil)
to force formatting of the contents. makeFirstResponder
returns false
if the text field refuses to resign its first responder status.
@IBAction func okAction(_ sender: Any) {
if let window = view.window,
window.makeFirstResponder(nil) {
dismiss(self)
}
}
How can I make a NSTextfield with left or right indicator for validation?
A text field control is a view where the drawing is all done with an NSTextFieldCell. What you'd need to do is subclass NSTextFieldCell, and customize the drawing. Look at NSCell
's API and you'll see there's a drawWithFrame:inView:
method which is what does all of the drawing for the entire field. Various other methods of NSCell are used in this process.
Unfortunately some of how the drawing is done is a bit private and not eeeasily fiddled with, but the main thing is drawWithFrame:inView:
will draw the background and then call drawInteriorWithFrame:inView:
to draw the text. Off the top of my head, I can't remember if NSTextFieldCell uses titleRectForBounds:
to determine what the text's bounds are, but I'm pretty sure it is. So you could override that to return a narrower rectangle, leaving room to either draw the validation icon with the cell itself, or use a subview.
Additionally, you'll need to adjust the bounds in which the NSTextView field editor draws and edits the text, otherwise when you view the field while it is not first responder it will look fine, but when you edit the field's text it will overlap the icon. For that you may need to adjust the frame given to editWithFrame:inView:editor:delegate:event:
.
It's always a bit finicky to tweak text fields because it takes a while to find all the methods and code paths involved, but that's the gist of what you need to do.
ViewController + Storyboard setting up validation with controlTextDidChange
I think the samples you're following are a bit out-of-date.
Try...
override func controlTextDidChange(_ notification: Notification) {
...as the function definition for your method in your NSTextFieldDelegate
.
Force a NStextField to only accept Hex values
See this answer for a much better explanation, but it would be something like:
- (void)controlTextDidChange:(NSNotification *)aNotification {
NSError *outError;
NSControl *textField = [aNotification object];
NSString *myText = [textField stringValue];
// check if myText is 0-9 or a-f, do something with it if its not hex.
// update the NSNextField with the validated text
[postingObject setStringValue:myText];
}
Form validation issue in macOS app
You can have NSTextField
and NSSecureTextField
in the same array. This is indeed an easy way to find the empty ones.
let tf = NSTextField()
let stf = NSSecureTextField()
let tf2 = NSTextField()
tf2.stringValue = "some text"
let all = [tf, stf, tf2]
let emptyTextFields = all.filter { $0.stringValue.isEmpty }
Also in your example you can't use commas to group conditions in if
, you have to use &&
:
if tf.stringValue.isEmpty && stf.stringValue.isEmpty && tf2.stringValue.isEmpty {
// do something
}
but this is not a good solution, better use the array and filter.
Related Topics
How to Set a Known Position and Orientation as a Starting Point of Arkit
Closure Identity in Swift: Unregister Observing Closure
Inmemory Realm Threading in Swift
Secidentity + Force Cast Violation: Force Casts Should Be Avoided. (Force_Cast)
Urlcomponents Queryitems Losing Percent Encoding When Mutated
Swift 4: How to Asynchronously Use Urlsessiondatatask But Have The Requests Be in a Timed Queue
How to Pass Data from Using Post/Form Leaf Template
Uitableviewcell Subclass Wrong Image in Cell or Old Image Bug
Swiftui Map Overlays Without UIviewrepresentable
How to Change The Default Skscene That Displays on Startup
<Unknown>:0: Error: Opening Import File for Module 'swift': Not a Directory
Addperiodictimeobserver Is Not Called Every Millisecond
Way to Check If Up or Down Button Is Pressed with Nsstepper
Swiftui Published Updates Not Refreshing
How to Convert String to Date Without Time in Swift 3
#If Canimport(Coreimage) Not Working in Swift Package Manager