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") } } } } } 
  • Complemento Kotlin-allopen + @JvmField en un val no suficientemente final
  • ¿Cómo se comstack el proyecto Java + Kotlin con Maven?
  • Anotación JvmOverloads para constructor primario de class
  • Descompression del comstackdor de la function de mayor order de Kotlin (references invocables)
  • kotlin dagger - falla la segunda inyección
  • ¿Referencia sin resolver con respecto a una dependencia de Gradle?
  • Kotlin - ¿Cómo "lateinit" una var anulada de una interfaz?
  • Kotlin y generics, implementando class genérica abstracta con matriz genérica
  • Se esperaba una combinación de bean pero se encontraron 3: objectMapper, halObjectMapper, _halObjectMapper en junitTest
  • ¿Por qué AtomicInteger es abstracto en Kotlin? (funciona bien en Java)
  • ¿Debo usar la class de datos incluso si implemento todo hashCode (), equals () y toString ()?