如何构建Kotlin中JavaFX组件的构建器模式

我正在试图在Kotlin中为javafx组件创建一个构建器模式。 模式如下所示

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

到目前为止我所做的是如下,但是child不暴露Child类中声明的labelbutton方法。 任何指针?

 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 } 

注意:我已经看了一下TornadoFX库,但是我想提出一个我自己的解决方案,主要是因为学习的目的。

我终于想出了使用@ zsmb13的建议的解决方案。

这里是供其他人参考的

 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 } 

用法如下:

 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") } } } } }