-
Notifications
You must be signed in to change notification settings - Fork 2
Ktfx Layouts
Ktfx Layouts provides support to write JavaFX layouts (Node, MenuItem, PathElement, etc.) with Kotlin DSL. The aim here is to avoid the long code that are usually associated with FXML which is the standard way to produce JavaFX layouts.
While you can create UI programmatically, it's hardly done because it's somewhat ugly and hard to maintain. Here's a plain Kotlin version (one in Java is even longer):
val box = VBox()
val name = TextField()
val button = Button()
button.text = "Say Hello"
button.setOnClickListener {
Alert(AlertType.NONE, "Hello").showAndWait()
}
layout.addView(name)
layout.addView(button)
A DSL makes the same logic easy to read, easy to write and there is no runtime overhead. Here it is again:
vbox {
val name = textField()
val button = button("Say Hello") {
alert("Hello")
}
}
Layouts addition is not limited to JavaFX-provided controls. To add custom controls, simply call addNode
(or addMenuItem
, addElement
, etc.) within the parent dsl.
pane {
label("Here's my custom control")
addNode(AwesomeControl()) {
awesomeProperty().set(true)
}
}
class AwesomeControl : Node {
fun awesomeProperty(): BooleanProperty
}
Some node containers have abilities to modify their child nodes behavior within the container. Naturally, the functions to modify these behaviors are embedded within the layout class. For example, consider this AnchorPane
with Node.anchorBottom
property.
anchorPane {
val sendButton = button("Send")
button.anchorBottom = 10.0
}
This would work just fine. However, due to the existence of dynamic layout dsl marker, it is impossible to call Node.anchorAll
within button
dsl.
anchorPane {
val sendButton = button("Send") {
anchorBottom = 10.0 // compile-time error
}
}
To avoid this issue, applying constraints could be done with infix operators.
anchorPane {
val sendButton = button("Send") anchorBottom 10.0
}
Only seen in AnchorPane
.
It allows the edges of child nodes to be anchored to an offset from the anchor pane's edges.
anchorPane {
val topRightLabel = label() anchorTop 0.0 anchorRight 0.0
}
Seen in BorderPane
, GridPane
, StackPane
and TilePane
.
It allows the position of child nodes to be aligned within the area.
stackPane {
val webView = webView() align Pos.CENTER_LEFT
}
Seen in BorderPane
, FlowPane
, GridPane
, HBox
, StackPane
, TilePane
and VBox
.
It sets distance between child nodes.
hbox {
label("Password")
val field = passwordField { promptText = "Password" } marginLeft 10.0
}
Seen in GridPane
, HBox
, and VBox
.
It determines whether child nodes should take over the remaining area of this layout.
vbox {
label("Your friends")
val list = listView<Friend>(myFriends.toObservableList()) vgrow true
}
Only seen in GridPane
.
It specifies child nodes position in row & column.
gridPane {
label("Email") row 0 col 0
val emailField = textField() row 0 col 1
label("Confirm email") row 1 col 0
val confirmEmailField = textField() row 1 col 1
val confirmButton = button("Confirm") row 2 col (0 to 2)
}
Notice that confirmButton col (0 to 2)
accepts kotlin.Pair
, in which case the first value is column index, followed by column span. This would mean the button would take the whole width.
- Introduction
- Download
- Commons
- Layouts
- Listeners
- Coroutines
- ControlsFX extensions
- JFoenix extensions
- Development