Any kind of user oriented application whether it’s a web application, a mobile application or a desktop application, there will be interaction with the user. That interaction is usually some kind of “fill in these fields please, so something can happen”.
KeepassFX has several such interactions. And of course they are implemented with tornadoFX builders. The nice thing about developing keepassFX while constantly talking in the Slack tornadoFX channel means that usecases I encounter will very often result in updates in the builders.
The form builder
A Form in TornadoFX basically looks like this:
class MainView : View("Basic form") {
val model = ViewModel()
val username = model.bind { SimpleStringProperty() }
val password = model.bind { SimpleStringProperty() }
override val root = form {
fieldset {
field("username") {
textfield(username).required()
}
field("password") {
passwordfield(password).required()
}
buttonbar {
button("Cancel", ButtonBar.ButtonData.CANCEL_CLOSE).setOnAction {
println("do nothing")
}
button("OK", ButtonBar.ButtonData.OK_DONE).setOnAction {
model.commit {
println("do something")
}
}
}
}
}
}
The result looks like this:
Several things to note about this code
the model
Normally a ViewModel()
whould be used to create a class that contains properties and is linked to a class like a data class. We found out that for several usecases you don’t actually need them all the time. The code
val model = ViewModel()
val username = model.bind { SimpleStringProperty() }
val password = model.bind { SimpleStringProperty() }
creates an unlinked model that binds 2 SimpleStringProperties together.
validators
textfield(username).required()
has the validator required()
. Validators can only be used on properties that are part of a ViewModel(). Because of the validators, the code for the OK button can contain the model.commit
function. This ensures that the code inside the model.commit
block will only be executed when all the validators are happy. If you press OK button the validators will decorate the fields that do not pass validation:
Since this afternoon there is another way of doing this. button
has the function enableWhen
and disableWhen
. Now you can link this to the validation state.
With this the OK button will only be enabled if all the validators are happy. Now the code looks like this:
class EnabledView : View("Basic form") {
val model = ViewModel()
val username = model.bind { SimpleStringProperty() }
val password = model.bind { SimpleStringProperty() }
override val root = form {
fieldset {
field("username") {
textfield(username).required()
}
field("password") {
passwordfield(password).required()
}
buttonbar {
button("Cancel", ButtonBar.ButtonData.CANCEL_CLOSE).setOnAction {
println("do nothing")
}
button("OK", ButtonBar.ButtonData.OK_DONE) {
enableWhen { model.valid }
setOnAction {
println("do something")
}
}
}
}
model.validate(decorateErrors = false)
}
}
For more information about tornadoFX read the excellent guide at TornadoFX guide. To read more about the validators see Editing models and validation