-
Notifications
You must be signed in to change notification settings - Fork 108
FXML
Binding.scala 11 supports FXML and JavaFX.
You can create JavaFX GUI or any other JavaBeans, in FXML syntax, along with embedded Scala code with data-binding abilitiy.
import javafx.application.Application
import javafx.stage._
import javafx.scene._
import javafx.scene.control._
import com.thoughtworks.binding._
final class FxmlSample extends Application {
@fxml override def start(primaryStage: Stage): Unit = {
val scene: Binding[Scene] = <Scene><Label>Hello, World!</Label></Scene>
fxml.show(primaryStage, scene)
}
}
object FxmlSample {
def main(args: Array[String]): Unit = {
Application.launch(classOf[FxmlSample], args: _*)
}
}
Very simple!
Unlike FXML dynamically loaded from FXMLLoader
, Binding.scala compiles FXML into monadic expressions, which is statically type checked, which means you can get rid of implicit conversion between XML text and other types, and use Scala expression instead.
@fxml val gridPane = {
<GridPane>
<Label text="My Label">
<!-- OK, as 2 is an Int -->
<GridPane.rowIndex>{2}</GridPane.rowIndex>
<!-- Compile error because "not a number" is a string, not an Int -->
<GridPane.columnIndex>not a number</GridPane.columnIndex>
</Label>
</GridPane>
}
FXML loaded from FXMLLoader
support very limited data-binding expressions via ${...}
syntax. On the other hand, Binding.scala supports arbitrary Scala code as data-binding expressions.
@fxml def vbox(buttonText: BindingSeq[String]) = {
<VBox>
<Button text="first button"/>{
for (t <- buttonTexts) yield {
<Button text={t}/>
}
}<Button text="last button"/>
</VBox>
}
You can even create repeated UI elements in a for
/yield
block, whereby Button
s will be added and removed automatically whenever buttonTexts
changes.
@fxml
support any JavaBean on both JVM and Scala.js. For example you can create custom JavaBeans in Scala.js:
@fxml val date = {
<?import scala.scalajs.js.Date?>
<Date date={2}>
<milliseconds>{42}</milliseconds>
</Date>
}
If you have use Binding.scala with Scala.js, you may already very familiar with @dom
.
@dom
creates a data-binding expressions with XHTML support. For example:
@dom val i: Binding[Int] = 1
@dom def plusI(n: Binding[Int]): Binding[Int] = n.bind + i.bind
@dom val myDiv: Binding[HTMLDivElement] = {
val node: HTMLDivElement = <div></div>
myDiv
}
@dom val myDivs: Binding[BindingSeq[HTMLDivElement]] = {
val nodes: BindingSeq[HTMLDivElement] = <div></div><div></div>
}
Unlike @dom
, @fxml
itself does not create data-binding expressions, it merely convert FXML literals into Binding
or BindingSeq
.
@fxml val i: Int = 1 // No magic here, i is not bindable
// Compile error because n.bind is not in a data-binding expression
// @fxml def plusI(n: Binding[Int]): Int = n.bind + i
// Manually create a Binding block in order to use `.bind` syntax.
@fxml def plusI(n: Binding[Int]): Int = Binding { n.bind + i }
@fxml val myButton: Binding[Button] = {
val node: Binding[Button] = <Button/>
node
}
@fxml val myButton: BindingSeq[Button] = {
val nodes: BindingSeq[Button] = <Button/><Button/>
nodes
}