将 Swift 中的属性绑定到 NSTextFields
Bind properties in Swift to NSTextFields
我正在开发一个用 Swift 编写的单位转换器,它会在适当的 NSTextField
秒内自动显示更新后的单位。对于此示例,如果用户在 minutesField
中输入分钟,secondsField
和 hoursField
应自动更新以显示属性的转换值。下面是我的视图控制器中的代码示例:
import Cocoa
class ViewController: NSViewController {
@IBOutlet weak var secondsField: NSTextField!
@IBOutlet weak var minutesField: NSTextField!
@IBOutlet weak var hoursField: NSTextField!
var sec: Double = 1
var min: Double = 1
var hr: Double = 1
let conv = [[1, 0.0166666666666667, 0.000277777777777778],
[60, 1, 0.0166666666666667],
[3600, 60, 1]]
func updateTextFields() {
secondsField.stringValue = "\(sec)"
minutesField.stringValue = "\(min)"
hoursField.stringValue = "\(hr)"
}
}
extension ViewController: NSTextFieldDelegate {
override func controlTextDidChange(obj: NSNotification) {
let tag = obj.object?.tag() ?? 0
let text = obj.object?.stringValue ?? "1"
let value = Double(text) ?? 1.0
switch tag {
case 0:
// base unit = seconds
sec = value
min = value * conv[0][1]
hr = value * conv[0][2]
case 1:
// base unit = minutes
sec = value * conv[1][0]
min = value
hr = value * conv[1][2]
case 2:
// base unit = hours
sec = value * conv[2][0]
min = value * conv[2][1]
hr = value
default:
"none"
}
updateTextFields()
}
}
上面的代码更新了文本字段,但输入的活动字段在第一次击键后冻结。例如,如果您尝试在秒字段中输入 60
,则下一次击键不会执行任何操作。数字 6.0
出现在第一次击键之后(见下图)。这可能是由于更新属性后调用的函数。属性根据活动文本字段的标签更新。
是否可以有一个功能来更新当前活动字段以外的所有其他文本字段?
您需要将文本字段值的设置从 viewDidLoad()
移到单独的方法中。从 viewDidLoad()
以及您 seconds
属性.
上的 didSet
属性 观察者调用该方法
您还需要为秒、分或小时字段更改时创建操作方法。在秒字段的操作方法中,将 seconds
属性 设置为 secondsField.floatValue
。其他两个字段也类似。在 NIB/storyboard 中,将文本字段的操作连接到视图控制器上相应的操作方法。
Is it possible to have a function that will update all the other text
fields other than the currently active field?
是的。您可以将所有文本字段连接到同一操作。
首先将所有文本字段相应地连接到视图控制器:
@IBOutlet weak var hourField: NSTextField!
@IBOutlet weak var minuteField: NSTextField!
@IBOutlet weak var secondField: NSTextField!
其次创建一个单独的变量来表示您的时间间隔。您还可以添加一个 setter / getter 以将其自动存储到 USerDefaults:
var timeInterval: TimeInterval {
get {
return UserDefaults.standard.double(forKey: "timeInterval")
}
set {
UserDefaults.standard.set(newValue, forKey: "timeInterval")
}
}
第三次创建一个 TimeInterval 扩展,将时间从秒转换为 hour/minute
extension TimeInterval {
var second: Double { return self }
var minute: Double { return self / 60 }
var hour: Double { return self / 3600 }
var hourToMinute: Double { return self * 60 }
var hourToSecond: Double { return self * 3600 }
var minuteToHour: Double { return self / 60 }
var minuteToSecond: Double { return self * 60 }
}
第四次创建将更新其他文本字段的操作:
@IBAction func timeAction(sender: NSTextField) {
// use guard to convert the field string to Double
guard let time = Double(sender.stringValue) else { return }
// switch the field
switch sender {
case hourField:
// convert / update secondary fields
minuteField.stringValue = time.hourToMinute.description
secondField.stringValue = time.hourToSecond.description
// make it persist through launches
timeInterval = time * 3600
case minuteField:
hourField.stringValue = time.minuteToHour.description
secondField.stringValue = time.minuteToSecond.description
timeInterval = time * 60
default:
hourField.stringValue = time.hour.description
minuteField.stringValue = time.minute.description
timeInterval = time
}
}
最后但并非最不重要的一点是确保在下次显示视图时加载这些值:
override func viewWillAppear() {
hourField.stringValue = timeInterval.hour.description
minuteField.stringValue = timeInterval.minute.description
secondField.stringValue = timeInterval.second.description
}
我正在开发一个用 Swift 编写的单位转换器,它会在适当的 NSTextField
秒内自动显示更新后的单位。对于此示例,如果用户在 minutesField
中输入分钟,secondsField
和 hoursField
应自动更新以显示属性的转换值。下面是我的视图控制器中的代码示例:
import Cocoa
class ViewController: NSViewController {
@IBOutlet weak var secondsField: NSTextField!
@IBOutlet weak var minutesField: NSTextField!
@IBOutlet weak var hoursField: NSTextField!
var sec: Double = 1
var min: Double = 1
var hr: Double = 1
let conv = [[1, 0.0166666666666667, 0.000277777777777778],
[60, 1, 0.0166666666666667],
[3600, 60, 1]]
func updateTextFields() {
secondsField.stringValue = "\(sec)"
minutesField.stringValue = "\(min)"
hoursField.stringValue = "\(hr)"
}
}
extension ViewController: NSTextFieldDelegate {
override func controlTextDidChange(obj: NSNotification) {
let tag = obj.object?.tag() ?? 0
let text = obj.object?.stringValue ?? "1"
let value = Double(text) ?? 1.0
switch tag {
case 0:
// base unit = seconds
sec = value
min = value * conv[0][1]
hr = value * conv[0][2]
case 1:
// base unit = minutes
sec = value * conv[1][0]
min = value
hr = value * conv[1][2]
case 2:
// base unit = hours
sec = value * conv[2][0]
min = value * conv[2][1]
hr = value
default:
"none"
}
updateTextFields()
}
}
上面的代码更新了文本字段,但输入的活动字段在第一次击键后冻结。例如,如果您尝试在秒字段中输入 60
,则下一次击键不会执行任何操作。数字 6.0
出现在第一次击键之后(见下图)。这可能是由于更新属性后调用的函数。属性根据活动文本字段的标签更新。
是否可以有一个功能来更新当前活动字段以外的所有其他文本字段?
您需要将文本字段值的设置从 viewDidLoad()
移到单独的方法中。从 viewDidLoad()
以及您 seconds
属性.
didSet
属性 观察者调用该方法
您还需要为秒、分或小时字段更改时创建操作方法。在秒字段的操作方法中,将 seconds
属性 设置为 secondsField.floatValue
。其他两个字段也类似。在 NIB/storyboard 中,将文本字段的操作连接到视图控制器上相应的操作方法。
Is it possible to have a function that will update all the other text fields other than the currently active field?
是的。您可以将所有文本字段连接到同一操作。
首先将所有文本字段相应地连接到视图控制器:
@IBOutlet weak var hourField: NSTextField!
@IBOutlet weak var minuteField: NSTextField!
@IBOutlet weak var secondField: NSTextField!
其次创建一个单独的变量来表示您的时间间隔。您还可以添加一个 setter / getter 以将其自动存储到 USerDefaults:
var timeInterval: TimeInterval {
get {
return UserDefaults.standard.double(forKey: "timeInterval")
}
set {
UserDefaults.standard.set(newValue, forKey: "timeInterval")
}
}
第三次创建一个 TimeInterval 扩展,将时间从秒转换为 hour/minute
extension TimeInterval {
var second: Double { return self }
var minute: Double { return self / 60 }
var hour: Double { return self / 3600 }
var hourToMinute: Double { return self * 60 }
var hourToSecond: Double { return self * 3600 }
var minuteToHour: Double { return self / 60 }
var minuteToSecond: Double { return self * 60 }
}
第四次创建将更新其他文本字段的操作:
@IBAction func timeAction(sender: NSTextField) {
// use guard to convert the field string to Double
guard let time = Double(sender.stringValue) else { return }
// switch the field
switch sender {
case hourField:
// convert / update secondary fields
minuteField.stringValue = time.hourToMinute.description
secondField.stringValue = time.hourToSecond.description
// make it persist through launches
timeInterval = time * 3600
case minuteField:
hourField.stringValue = time.minuteToHour.description
secondField.stringValue = time.minuteToSecond.description
timeInterval = time * 60
default:
hourField.stringValue = time.hour.description
minuteField.stringValue = time.minute.description
timeInterval = time
}
}
最后但并非最不重要的一点是确保在下次显示视图时加载这些值:
override func viewWillAppear() {
hourField.stringValue = timeInterval.hour.description
minuteField.stringValue = timeInterval.minute.description
secondField.stringValue = timeInterval.second.description
}