-
Notifications
You must be signed in to change notification settings - Fork 273
Type Safe Builders
Wiki ▸ Documentation ▸ Type Safe Builders
Builders are extension functions to the Java FX Pane class which enables you to create a new node, set some properties and add it to the children of the parent Pane with very little code. The hierarchical nature of the builders makes it easy to understand the ui composition with a simple glance.
There are builders for complex Node components as well, like TableView.
Builders also support automatic property binding for input type components like TextField, ComboBox etc.
###Example 1 ####A VBox containing two HBox components
Each HBox contains a Label and a TextField, both which utilize a margin constraint within the HBox. The TextField components are also set to use the maximum allowable width.
class MyView : View() {
override val root = VBox()
init {
with(root) {
hbox {
label("First Name") {
hboxConstraints { margin = Insets(5.0) }
}
textfield {
hboxConstraints { margin = Insets(5.0) }
useMaxWidth = true
}
}
hbox {
label("Last Name") {
hboxConstraints { margin = Insets(5.0) }
}
textfield {
hboxConstraints { margin = Insets(5.0) }
useMaxWidth = true
}
}
}
}
}Rendered UI
Note also you can add Node instances to a builder without using builders for them. This is helpful if you have Node components existing outside your builder or are working with Node items that don't have builder support. You can then call the Kotlin stdlib function apply() to then maintain the "builder flow".
class MyView : View() {
override val root = VBox()
init {
with(root) {
hbox {
this += Label("First Name").apply {
hboxConstraints { margin = Insets(5.0) }
}
this += TextField().apply {
hboxConstraints { margin = Insets(5.0) }
useMaxWidth = true
}
}
hbox {
this += Label("Last Name").apply {
hboxConstraints { margin = Insets(5.0) }
}
this += TextField().apply {
hboxConstraints { margin = Insets(5.0) }
useMaxWidth = true
}
}
}
}
}##Example 2
You can build an entire TableView, complete with custom cell renderers and column value mappings, with a succinct builder structure.
class MyView : View() {
override val root = GridPane()
init {
with(root) {
tableview<String> {
gridpaneConstraints {
vhGrow = Priority.ALWAYS
}
items = FXCollections.observableArrayList("Alpha", "Beta", "Gamma", "Delta", "Epsilon", "Zeta", "Eta")
column<String>("String") { ReadOnlyStringWrapper(it.value) }
column<Int>("Length", String::length)
.cellFormat {
if (it == 4) {
style = "-fx-background-color:#8b0000; -fx-text-fill:white"
text = it.toString()
} else {
text = it.toString()
}
}
}
}
}
}RENDERED UI
Note that values for columns can be mapped in two ways.
column<String>("String") { ReadOnlyStringWrapper(it.value) }
column<Int>("Length", String::length)The first is a lambda that specifies an ObservableValue off your domain object in some form, which in this case is a ReadOnlyStringWrapper. The second uses non-observable fields with getters (and setters if they are mutable) in your domain object (this approach uses reflection).
The cellFormat() function can be called on a TableColumn and accepts a lambda specifying how to render a cell based on the provided value. In this case, the "Length" column will format cells red if the value of the String's length is 4.
.cellFormat {
if (it == 4) {
style = "-fx-background-color:#8b0000; -fx-text-fill:white"
text = it.toString()
} else {
text = it.toString()
}
}###Example 3 ####A TabPane with tabs containing GridPane layouts as well as a TableView
class MyView : View() {
override val root = GridPane()
init {
with(root) {
tabpane {
gridpaneConstraints {
vhGrow = Priority.ALWAYS
}
tab("Report", HBox()) {
label("Report goes here")
}
tab("Data", GridPane()) {
tableview<String> {
gridpaneConstraints {
vhGrow = Priority.ALWAYS
}
items = FXCollections.observableArrayList("Alpha","Beta","Gamma","Delta","Epsilon","Zeta","Eta")
column<String>("String") { ReadOnlyStringWrapper(it.value) }
column<Int>("Length", String::length )
.cellFormat {
if (it ==4) {
style = "-fx-background-color:#8b0000; -fx-text-fill:white"
text = it.toString()
}
else {
text = it.toString()
}
}
}
}
}
}
}
}RENDERED UI

The full list of available functions can be seen in the Builders.kt source file. If you miss a feature, send us a pull request, and we'll be happy to include it.
Next: Async Task Execution


