如何从子类 NSTextField 设置 NSButton.isEnabled

How to set NSButton.isEnabled from subclassed NSTextField

我对 Swift MacOS 编程还很陌生,一直在通过编写小型测试应用程序来学习。

此应用程序的目的是在第二个文本字段获得焦点时启用按钮,并在未获得焦点时禁用它。

我发现通过对 NSTextField 进行子类化,我可以覆盖 becomeFirstResponder() 但是不知道如何设置要从子类中禁用的按钮。

ViewController:

class ViewController: NSViewController {

    @IBOutlet public weak var pushButton: NSButton!

    @IBOutlet weak var textField3: NSTextField!
    @IBOutlet weak var textField2: GSTextField!
    @IBOutlet weak var textField1: NSTextField!


    override func viewDidLoad() {
        super.viewDidLoad()

        textField2.delegate = self

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

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

    func chgButton(onoff: Bool){
        pushButton.isEnabled = onoff
    }

}

// When the field completes editing make the pushbutton disabled.
extension ViewController: NSTextFieldDelegate {
    override func controlTextDidEndEditing(_ obj: Notification) {
        print("did end")
        chgButton(onoff: false)

    }
}

GSTextField.Swift

class GSTextField: NSTextField {

    override func becomeFirstResponder() -> Bool {
        print("GSTextField Firstresponder")
 ////*** I need to set the button to be enabled here
        return super.becomeFirstResponder()
    }
 }   

您的 NSTextField 子类需要能够与按钮通信。最简单的方法是将对 pushButton 的引用传递给您的文本字段,然后从那里更新按钮。

像这样更新您的 ViewController:

override func viewDidLoad() {
    super.viewDidLoad()

    textField2.delegate = self
    textField2.pushButton = pushButton

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

你的 GSTextField 是这样的:

class GSTextField: NSTextField {

    weak var pushButton: NSButton?

    override func becomeFirstResponder() -> Bool {
        print("GSTextField Firstresponder")
        pushButton?.isEnabled = true
        return super.becomeFirstResponder()
    }

    override func resignFirstResponder() -> Bool {
        pushButton?.isEnabled = false
        return super.resignFirstResponder()
    }
}

应该注意的是,虽然这在这个玩具示例中运行良好,但这是解决此问题的次优解决方案,因为它紧密耦合了 pushButton 和 GSTextField。更好的解决方案是使用委托将焦点更改传达给 ViewController,并让 ViewController 处理更新。

您的 GSTextField 将如下所示:

protocol FocusObservable: class {
    func didGainFocus(sender: Any)
    func didLoseFocus(sender: Any)
}

class GSTextField: NSTextField {

    weak var focusDelegate: FocusObservable?

    override func becomeFirstResponder() -> Bool {
        print("GSTextField Firstresponder")
        focusDelegate?.didGainFocus(sender: self)
        return super.becomeFirstResponder()
    }

    override func resignFirstResponder() -> Bool {
        focusDelegate?.didLoseFocus(sender: self)
        return super.resignFirstResponder()
    }
}

然后你会添加协议一致性到 ViewController:

extension ViewController: FocusObservable {
    func didGainFocus(sender: Any) {
        pushButton.isEnabled = true
    }

    func didLoseFocus(sender: Any) {
        pushButton.isEnabled = false
    }
}

并设置文本域的focusDelegate:

override func viewDidLoad() {
    super.viewDidLoad()

    textField2.delegate = self
    textField2.focusDelegate = self
    // Do any additional setup after loading the view.
}