Views
3 months ago

tornadofx-guide

Property Delegates

Property Delegates Property Delegates Kotlin is packed with great language features, and delegated properties are a powerful way to specify how a property works and create re-usable policies for those properties. On top of the ones that exist in Kotlin's standard library, TornadoFX provides a few more property delegates that are particularly helpful for JavaFX development. Single Assign It is often ideal to initialize properties immediately upon construction. But inevitably there are times when this simply is not feasible. When a property needs to delay its initialization until it is first called, a lazy delegate is typically used. You specify a lambda instructing how the property value is initialized when its getter is called the first time. val fooValue by lazy { buildExpensiveFoo() } But there are situations where the property needs to be assigned later not by a valuesupplying lambda, but rather some external entity at a later time. When we leverage typesafe builders we may want to save a Button to a class-level property so we can reference it later. If we do not want myButton to be nullable, we need to use the lateinit modifier. class MyView: View() { lateinit var myButton: Button } override val root = vbox { } myButton = button("New Entry") The problem with lateinit is it can be assigned multiple times by accident, and it is not necessarily thread safe. This can lead to classic bugs associated with mutability, and you really should strive for immutability as much as possible ( Effective Java by Bloch, Item #13). By leveraging the singleAssign() delegate, you can guarantee that property is only assigned once. Any subsequent assignment attempts will throw a runtime error, and so will accessing it before a value is assigned. This effectively gives us the guarantee of immutability, although it is enforced at runtime rather than compile time. 190

Property Delegates class MyView: View() { var myButton: Button by singleAssign() } override val root = vbox { } myButton = button("New Entry") Even though this single assignment is not enforced at compile time, infractions can be captured early in the development process. Especially as complex builder designs evolve and variable assignments move around, singleAssign() is an effective tool to mitigate mutability problems and allow flexible timing for property assignments. By default, singleAssign() synchronizes access to its internal value. You should leave it this way especially if your application is multithreaded. If you wish to disable synchronization for whatever reason, you can pass a SingleAssignThreadSafetyMode.NONE value for the policy. var myButton: Button by singleAssign(SingleAssignThreadSafetyMode.NONE) JavaFX Property Delegate Do not confuse the JavaFX Property with a standard Java/Kotlin "property". The Property is a special type in JavaFX that maintains a value internally and notifies listeners of its changes. It is proprietary to JavaFX because it supports binding operations, and will notify the UI when it changes. The Property is a core feature of JavaFX and has its own JavaBeans-like pattern. This pattern is pretty verbose however, and even with Kotlin's syntax efficiencies it still is pretty verbose. You have to declare the traditional getter/setter as well as the Property item itself. class Bar { private val fooProperty by lazy { SimpleObjectProperty() } fun fooProperty() = fooProperty var foo: T get() = fooProperty.get() set(value) = fooProperty.set(value) } Fortunately, TornadoFX can abstract most of this away. By delegating a Kotlin property to a JavaFX property() , TornadoFX will get/set that value against a new Property instance. To follow JavaFX's convention and provide the Property object to UI components, you can 191

Guide
Guide
GUIDE
Guide
Guide
GUIDE
Guide
GUIDE
Guide
GUIDE
GUIDE
GUIDE