tornadofx
tornadofx copied to clipboard
How to swap fragments?
What is the best way to swap fragments based on properties?
I discovered you can use the managedWhen and visibleWhen together. However it doesnt work on a Fragment; need to wrap in a Pane. Is that by design, or are we missing something for Fragment.
Is there a better way to do this?
pane {
add(XXXFragment::class, mapOf(XXXFragment::message to "Connect an NFC device...", XXXFragment::graphic to Styles.noNfcDeviceIcon)) {
managedWhen(visibleProperty())
visibleWhen(controller.noDevice)
}
add(XXXFragment::class, mapOf(XXXFragment::message to "Touch an NFC tag to the device...", XXXFragment::graphic to Styles.noNfcTagIcon)) {
managedWhen(visibleProperty())
visibleWhen(controller.noTag)
}
}
This just seems janky...
pane {
pane {
add(XXXFragment::class, mapOf(XXXFragment::message to "Connect an NFC device...", XXXFragment::graphic to Styles.noNfcDeviceIcon))
managedWhen(visibleProperty())
visibleWhen(controller.noDevice)
}
pane {
add(XXXFragment::class, mapOf(XXXFragment::message to "Touch an NFC tag to the device...", XXXFragment::graphic to Styles.noNfcTagIcon))
managedWhen(visibleProperty())
visibleWhen(controller.noTag)
}
}
@edvin thoughts here?
I'll use the following two simple fragments in my discussion below:
class F1 : Fragment("F1") {
override val root = label(title)
}
class F2 : Fragment("F2") {
override val root = label(title)
}
managedWhen and visibleWhen operates on Node, and since the Fragment itself isn't a Node, you must either wrap it or control the root node of the Fragments. Here is a simple example where I use removeWhen for simplicity:
val state = SimpleBooleanProperty(false)
override val root = hbox {
button("Swap state").action {
state.value = !state.value
}
add<F1> {
root.removeWhen(state)
}
add<F2> {
root.removeWhen(state.not())
}
}
The removeWhen expression will operate on the closest node it can find in the hierarchy, so wrapping in a Pane or any other Node is an effective way of making a container which only purpose is to act as a placeholder to control visibility:
pane {
add<F1> {
removeWhen(state)
}
}
pane {
add<F2> {
removeWhen(state.not())
}
}
I don't think this is janky, and it is very well defined and understood what actually happens. Be sure to use the sexy syntax version of add though :)
@edvin can add an extension function to stdlib?
fun UCcomponent.removeWhen(state: BooleanProperty) { root.removeWhen(state) }
if you do not mind, then I will do PR
Absolutely, that will remove some confusion I guess, as one would most probably assume that the function was available on the UIComponent itself.
Thanks. It took me a while to realize the extension method was for nodes and fragments are not nodes. I was getting crazy behavior.
I've often tried to hide that fact, by making UIComponents integrate just like they would if they were actual Nodes, so that's my fault :) It's convenient to be able to think of them as Nodes, so adding extension functions like the one above makes sense. We have plenty of them already also.