Cómo build el patrón de constructor alnetworkingedor de los componentes de JavaFX en Kotlin

Estoy intentando crear un patrón de construcción en Kotlin para los componentes de javafx. El patrón se verá a continuación

fun main(args: Array<String>) { val vb = vbox { child { hbox { child { label { prefWidth = 20.0 } button { text = "Click" } } } label { prefHeight = 80.0 } } } } 

Lo que he hecho hasta ahora es el siguiente, pero el child no está exponiendo la label ni los methods de los button declarados en Child class Child . ¿Alguna sugerencia?

 fun Pane.child(init: (Pane.() -> Unit)? = null): Child { val ch = Child() init?.invoke(this) ch.parent = this return ch } class Child { var parent: Pane? = null fun <T : Node> initChildNode(styleClass: String? = null, tag: T, init: (T.() -> Unit)? = null): T { init?.invoke(tag) tag.styleClass.add(styleClass) parent?.children?.add(tag) return tag } fun region(styleClass: String? = null, init: (Region.() -> Unit)? = null) = initChildNode(styleClass, Region(), init) fun vbox(styleClass: String? = null, init: (VBox.() -> Unit)? = null) = initChildNode(styleClass, VBox(), init) fun hbox(styleClass: String? = null, init: (HBox.() -> Unit)? = null) = initChildNode(styleClass, HBox(), init) fun label(styleClass: String? = null, init: (Label.() -> Unit)? = null) = initChildNode(styleClass, Label(), init) fun button(styleClass: String? = null, init: (Button.() -> Unit)? = null) = initChildNode(styleClass, Button(), init) } fun vbox(styleClass: String? = null, init: (VBox.() -> Unit)? = null) = initNode(styleClass, VBox(), init) fun hbox(styleClass: String? = null, init: (HBox.() -> Unit)? = null) = initNode(styleClass, HBox(), init) fun <T : Node> initNode(styleClass: String? = null, tag: T, init: (T.() -> Unit)? = null): T { init?.invoke(tag) tag.styleClass.add(styleClass) return tag } 

NOTA: He investigado la biblioteca de TornadoFX, pero me gusta encontrar una solución propia debido principalmente al propósito de aprendizaje.

Finalmente he llegado a la solución usando el consejo de @ zsmb13.

Aquí está para reference de otros

 fun <T : Pane> T.children(init: (Children.() -> Unit)? = null): Children { val ch = Children() ch.parent = this init?.invoke(ch) return ch } class Children : Layout() { var parent: Pane? = null override fun <T : Node> initNode(styleClass: String?, tag: T, init: (T.() -> Unit)?): T { val node: T = super.initNode(styleClass, tag, init) parent?.children?.add(node) return node } } open class Layout { var pane: Pane? = null open fun <T : Node> initNode(styleClass: String? = null, tag: T, init: (T.() -> Unit)? = null): T { init?.invoke(tag) tag.styleClass.add(styleClass) return tag } fun region(styleClass: String? = null, init: (Region.() -> Unit)? = null) = initNode(styleClass, Region(), init) fun vbox(styleClass: String? = null, init: (VBox.() -> Unit)? = null) = initNode(styleClass, VBox(), init) fun hbox(styleClass: String? = null, init: (HBox.() -> Unit)? = null) = initNode(styleClass, HBox(), init) fun label(styleClass: String? = null, init: (Label.() -> Unit)? = null) = initNode(styleClass, Label(), init) fun button(styleClass: String? = null, init: (Button.() -> Unit)? = null) = initNode(styleClass, Button(), init) fun progressBar(styleClass: String? = null, init: (ProgressBar.() -> Unit)? = null) = initNode(styleClass, ProgressBar(), init) } fun <T : Pane> layout(styleSheet: String = "", init: Layout.() -> T): T { val layout = Layout() val pane = layout.init() layout.pane = pane pane.stylesheets.add(layout.javaClass.classLoader.getResource(styleSheet).toExternalForm()) return pane } 

Y el uso es como a continuación:

 private var loadProgress: ProgressBar? = null private var progressText: Label? = null val layout = layout("xyz.css") { vbox("screen") { prefWidth = 500 prefHeight = 450 children { region { minHeight = 250.0 } hbox { children { region { minWidth = 30.0 } label("large-label") { text = "Foo" } label("large-label") { text = "Bar" } region { minWidth = 20.0 } label("small-label") { text = "xyz" } } } region { minHeight = 10.0 } loadProgress = progressBar("progress") { minWidth = this@vbox.prefWidth } hbox { children { region { minWidth = 30.0 } progressText = label("progress-label") } } } } } 
  • Kotlin, JPA y @Transient
  • Diferencia entre el método takeWhile () y filter () en Kotlin
  • Android Espresso: cómo ejecutar la configuration solo una vez para todas las testings
  • ¿Cuál es el lugar en la jerarquía de types de types anulables?
  • ¿Qué es un "receptor" en Kotlin?
  • Instancia de class Kotlin assertEqual
  • ¿Cómo generar serialVersionUID para excepciones kotlin?
  • ¿Cómo configurar correctamente el complemento de Kotlin para Gradle?
  • Referencias cruzadas en parameters de tipo
  • Groovy no puede resolver classs de kotlin
  • Kotlin androidTest: las testings se terminaron. Suite de testing vacía