1

我已经创建了一个子类,NSControl它是格式化数字NSTextFieldNSStepper. 这是基本代码:

class StepperWithNumberField: NSControl, NSTextFieldDelegate {

    let numberField: NSTextField
    let stepper: NSStepper

    override var intValue: Int32 {

        get {
            return stepper.intValue
        }
        set {
            stepper.intValue = newValue
            numberField.intValue = newValue
        }
    }

    init(frame: NSRect, numberFieldWidth: CGFloat, minValue: Int32, maxValue: Int32) {
    
        let numberFieldFrame = NSRect(x: 0, y: 0, width: numberFieldWidth, height: frame.height)
    
        let numberField = NSTextField(frame: numberFieldFrame)
        numberField.isEditable = true
        numberField.alignment = .right
    
        let formatter = NumberFormatter()
        formatter.allowsFloats = false
        formatter.minimum = minValue as NSNumber
        formatter.maximum = maxValue as NSNumber

        numberField.formatter = formatter
    
        self.numberField = numberField
    
        let stepper = NSStepper(frame: NSRect(x: numberFieldWidth, y: 0, width: 15, height: frame.height))
        stepper.minValue = Double(minValue)
        stepper.maxValue = Double(maxValue)
        stepper.increment = 1
        stepper.valueWraps = false
    
        self.stepper = stepper
    
        super.init(frame: frame)
        self.numberField.delegate = self
        self.stepper.target = self
        self.stepper.action = #selector(self.stepperClicked)
        self.addSubview(numberField)
        self.addSubview(stepper)
        intValue = minValue
    }

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

    func controlTextDidEndEditing(_ notification: Notification) {
    
        if let nobj = notification.object as? NSTextField {
            stepper.intValue = nobj.intValue
        }
    }

    @objc func stepperClicked(sender: NSStepper) {
        numberField.intValue = stepper.intValue
    }
}

如果我创建一个实例并将其作为子视图添加到我的主视图中,这将按预期工作:我可以单击步进按钮来更改值,我可以直接输入一个数字。

但是,我不知道如何定义将通知我的目标(超级视图)任何更改的操作。

我创建了一个这样的实例:

let stepper = StepperWithNumberField(....)
stepper.target = self
stepper.action = #selector(self.stepperChanged)

并定义这样的方法:

@objc func stepperChanged(sender: StepperWithNumberField) {
    ...
}

但是该方法永远不会被调用,因为 StepperWithNumberField 不知道何时将任何操作发送到目标。

我希望每当 intValue 发生变化时,通过使用步进按钮或直接用户输入将操作发送到目标。

我在哪里——如果可能的话——告诉班级发送动作的条件?我已经搜索了 Apple 的文档以及这个社区,但是关于该主题的大多数问题和示例代码都已有 10 多年的历史,并且无法快速处理。

在这个线程...

具有多个操作的 NSControl

...建议使用委托,这当然是一种解决方案,但我仍然对如何在自定义 NSControl 中实现目标动作模式感兴趣。

4

2 回答 2

1
public typealias Handler = (StepperWithNumberField) -> Void
private var handler: Handler?


@objc func stepperClicked(sender: NSStepper) {
    numberField.intValue = stepper.intValue
    self.handler?(self)
}

利用

let stepper = StepperWithNumberField(....)
stepper.target = self
stepper.handler = stepperChanged(sender:)

func stepperChanged(sender: StepperWithNumberField) {
    
}
于 2022-01-20T01:38:32.707 回答
0

受 Leo Chen 回答的启发,我做了更多的实验,得出以下结论: 只需添加:

self.sendAction(action, to: target)

到我班的stepperClicked和方法。controlTextDidEndEditingStepperWithNumberField

那么用法:

let stepper = StepperWithNumberField(...)
stepper.target = self
stepper.action = #selector(self.stepperChanged)

@objc func stepperChanged(sender: StepperWithNumberField) {

} 
于 2022-01-20T12:54:00.020 回答