(Swift)How to dectect a "fieldEditor" resignFirstResponder() (Mac/Cocoa)

114 Views Asked by At

What I intend to do is validate four NSTextFields, I will try to make sure that all of them are filled correctly, and completely.

textField and alert

As the picture shows: if a user types anything in the 1st NSTextField, types something wrong or leaves it blank in the 2nd NSTextField, press Enter or click outside the boundary, it should show an alert, and try to stop the user from resigning from the 2nd NSTextField, and he should confirm his input in 2nd NSTextField.

What I have tried and the problems I faced:

  1. Use textFieldShouldEndEditing(_:)

When I type something. Wrong, show an alert and return false. It runs well.

But if I type nothing, textFieldShouldEndEditing(_:) will not invoke. (Because it won't be triggered without typing)

 func control(_ control: NSControl, textShouldEndEditing fieldEditor: NSText) -> Bool {
    if control.stringValue != validInput{
       showAlert()
       return false
    }else{
       return true
    }        
}// plz ignore the delegation
  1. CustomNSTextField & resignFirstResponder()

When the user clicked NSTextField, NSTextField would becomeFirstResponder(), followed by ResignFirstResponder() because the FieldEditor would enter. So it is invalid to monitor resignFirstResponder().

  1. Use textFieldShouldEndEditing(_:)

When I type something wrong or type nothing, press Enter or click outside the boundary, show an alert, but it is difficult to stop the following functions: for example, if I click the button "open", it may show an alert and an openFile dialog in the meantime.

What may solve my problems:

  1. Whether there is a trick that invokes textFieldDidBeginEditing (_:) when NSTextField resignFirstResponder() ?

  2. Whether there is a function that monitors the window's current fieldEditor resignFirstResponder(), and it can return false while I want the user to confirm his input.

1

There are 1 best solutions below

0
Tilseam On

I found it NOT as difficult as I thought to write a custom fieldEditor. Follow the tutorial here. I post the essential part of my code here for anyone who is facing similar problems.

class CustomFieldCell: NSTextFieldCell {
    static var durationFieldEditor: CustomFieldEditor = {
        let customFieldEditor = CustomFieldEditor()
        return fieldEditor
    }()

    override func fieldEditor(for controlView: NSView) -> NSTextView? {
        return Self.customFieldEditor
    }
}

class CustomFieldEditor: NSTextView {

    override init(frame frameRect: NSRect) {
        super.init(frame: frameRect)
        commonInit()
    }

    override init(frame frameRect: NSRect, textContainer container: NSTextContainer?) {
        super.init(frame: frameRect, textContainer: container)
        commonInit()
    }

    override func becomeFirstResponder() -> Bool {
        // condition
        return super.becomeFirstResponder()
    }

    override func resignFirstResponder() -> Bool {
        // condition
        return super.resignFirstResponder()
    }

    private func commonInit() {
        isFieldEditor = true
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}