edvin / tornadofx

Lightweight JavaFX Framework for Kotlin

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Accessing nodes with less code

croissant676 opened this issue · comments

This issue isn't an actual issue, it's just a question I have about tornadofx.
When coding something like

        hbox {
            vbox {
                textfield("Things")
            }
            button ("Print value") {
                action {
                    println("Something") // Wants to print textfield text
                }
            }
        }

Is there an easy way to access the textfield? (Or nodes in general?)
Typically, I do something like this:

        hbox {
            var textfield: TextField by Delegates.notNull()
            vbox {
                textfield = textfield("Some more things")
            }
            button ("Print value") {
                action {
                    println(textfield.text)
                }
            }
        }

This feels more complex than it needs to be.
Is there a solution like this

        hbox {
            vbox {
                textfield("Even more things") {
                    link = 0
                }
            }
            button ("Print value") {
                action {
                    println((nodes[0] as TextField).text)
                    println(nodes<TextField>(0).text) // Or this
                }
            }
        }

inside of tornadofx already?
And is there already an easier way to access nodes that I don't know about? (Which is very likely, since I'm not that experienced with kotlin or tornadofx)

This is for all nodes in general.

Thanks in advance!

You can if you absolutely need to assign the ui elements to a var like you do above, but almost every time I see someone do this, what they really want access to is the data. If you just use data binding you have no need to access the UI element directly, you'd just listen to changes to your model or access the model property directly. You can also fire events to get around the tight coupling to ui elements, which is an anti pattern you should avoid. Perhaps if you can show what you're trying to do, we can show you the correct solution.

My code looks something like this:

    var daysSpinner: Spinner<Int> by Delegates.notNull()
    // UI Section
    borderpane {
        center {
            vbox {
                hbox {
                    // Other UI Elements
                    daysSpinner = spinner(1, 100, 5, 1, false)
                }
              // Other UI Elements
             }
        }
        bottom {
            hbox {
                // Other UI Elements
                button("Next > ") {
                    action {
                        days = daysSpinner.value
                        nextView()
                    }
                }
                paddingBottom = 30.0
                alignment = Pos.CENTER
                spacing = 30.0
            }
        }
    }

This is exactly the situation I was talking about :) Here is a version of your code which binds the spinner to a Property and accesses the property value in the action, without having a tight coupling to the UI element:

val dayProperty = SimpleIntegerProperty(42)

override val root = borderpane {
    center {
        vbox {
            hbox {
                spinner(1, 100, 5, 1, false, dayProperty)
            }
        }
    }
    bottom {
        hbox {
            button("Next > ") {
                action {
                    println("You have access to ${dayProperty.value} here")
                }
            }
        }
    }
}

It worked for me :) Thanks!