我试图在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
未公开label
类中声明的button
或Child
方法。有什么指针吗?
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库,但我想提出一个我自己的解决方案,主要是出于学习目的。
答案 0 :(得分:0)
我终于使用@ 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")
}
}
}
}
}