-
Notifications
You must be signed in to change notification settings - Fork 272
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