Axa Assurance Maroc - Insurer Innovation Award 2024
JavaFX 2.0 With Alternative Languages - JavaOne 2011
1. JavaFX 2.0 With Alternative Languages Stephen Chin Chief Agile Methodologist, GXS steveonjava@gmail.com tweet: @steveonjava Dean Iverson VTTI deanriverson@gmail.com tweet: @deanriverson
2. Meet the Presenters Stephen Chin Dean Iverson Family Man Family Man Motorcyclist Geek
3. Disclaimer: This is Code-Heavy THE FOLLOWING IS INTENDED TO STIMULATE CREATIVE USE OF JVM LANGUAGES. AFTER WATCHING THIS PRESENTATION YOU MAY FEEL COMPELLED TO START LEARNING A NEW JVM LANGUAGE. THE PRESENTERS ARE NOT LIABLE FOR ANY INNOVATION, BREAKTHROUGHS, OR NP-COMPLETE SOLUTIONS THAT MAY RESULT.
5. Programming Languages JavaFX 2.0 APIs are now in Java Pure Java APIs for all of JavaFX Bindingand Sequences exposed as Java APIs FXML Markup for tooling Embrace all JVM languages Groovy, Scala, Clojure, JRuby Fantom, Mira, Gosu, Jython, etc. JavaFX Script is no longer supported by Oracle Existing JavaFX Script based applications will continue to run Visageis the open-source successor to the JavaFX Script language
6. JavaFX in Java JavaFX API uses an enhanced JavaBeans pattern Similar in feel to other UI toolkits (Swing, Apache Pivot, etc.) Uses builder pattern to minimize boilerplate
7. Example Application public class HelloStage extends Application { @Override public void start(Stage stage) { stage.setTitle("Hello Stage"); stage.setWidth(600); stage.setHeight(450); Group root = new Group(); Scene scene = new Scene(root); scene.setFill(Color.LIGHTGREEN); stage.setScene(scene); stage.show(); } public static void main(String[] args) { launch(HelloStage.class, args); } }
8. Example Application Using Builders public class HelloStage extends Application { @Override public void start(Stage stage) { stage.setTitle("Hello Stage"); stage.setScene(SceneBuilder.create() .fill(Color.LIGHTGREEN) .width(600) .height(450) .build()); stage.show(); } public static void main(String[] args) { launch(HelloStage.class, args); } }
9. Binding Unquestionably the biggest JavaFX Script innovation Supported via a PropertyBindingclass Lazy invocation for high performance Static construction syntax for simple cases e.g.: bind(<property>), bindBiDirectional(<property>)
10. Observable Pseudo-Properties Supports watching for changes to properties Implemented via anonymous inner classes Will take advantage of closures in the future
11. Observable Pseudo-Properties final Rectangle rect = new Rectangle(); rect.setX(40); rect.setY(40); rect.setWidth(100); rect.setHeight(200); rect.hoverProperty().addListener(new ChangeListener<Boolean>() { });
12. Observable Pseudo-Properties final Rectangle rect = new Rectangle(); rect.setX(40); rect.setY(40); rect.setWidth(100); rect.setHeight(200); rect.hoverProperty().addListener(new ChangeListener<Boolean>() { }); The property we want to watch
13. Observable Pseudo-Properties final Rectangle rect = new Rectangle(); rect.setX(40); rect.setY(40); rect.setWidth(100); rect.setHeight(200); rect.hoverProperty().addListener(new ChangeListener<Boolean>() { }); Only one listener used with generics to specify the data type
14. Observable Pseudo-Properties final Rectangle rect = new Rectangle(); rect.setX(40); rect.setY(40); rect.setWidth(100); rect.setHeight(200); rect.hoverProperty().addListener(new ChangeListener<Boolean>() { public void changed(ObservableValue<? extends Boolean> property, Boolean oldValue, Boolean value) { } }); Refers to the Rectangle.hoverProperty()
15. Observable Pseudo-Properties final Rectangle rect = new Rectangle(); rect.setX(40); rect.setY(40); rect.setWidth(100); rect.setHeight(200); rect.hoverProperty().addListener(new ChangeListener<Boolean>() { public void changed(ObservableValue<? extends Boolean> property, Boolean oldValue, Boolean value) { rect.setFill(rect.isHover() ? Color.GREEN : Color.RED); } });
16. Sequences in Java Replaced with an Observable List Public API is based on JavaFX sequences Internal code can use lighter collections API JavaFX 2.0 also has an Observable Map
18. Features of Groovy Modern language Closures AST Transforms Strongly typed dynamic language Tight integration with Java Very easy to port from Java to Groovy Declarative syntax with GroovyFX Builders Familiar to Groovy and JavaFX Script developers
19. Java vs. GroovyFX DSL public class HelloStage extends Application { public void start(Stage stage) { stage.setTitle("Hello Stage"); stage.setWidth(600); stage.setHeight(450); Scene scene = new Scene(); scene.setFill(Color.LIGHTGREEN); Rectangle rect = new Rectangle(); rect.setX(25); rect.setY(40); rect.setWidth(100); rect.setHeight(50); rect.setFill(Color.RED); scene.setRoot(new Group(rect)); stage.setScene(scene); stage.show(); } public static void main(String[] args) { launch(HelloStage.class, args); } } GroovyFX.start { stage -> def sg = new SceneGraphBuilder(stage) sg.stage(title: “Hello Stage”, width: 600, height: 450) { scene(fill: groovyblue) { rectangle(x: 25, y: 40, width: 100, height: 50, fill: red) } } } 19 8 Lines 180 Characters 21 Lines 430 Characters
26. Properties in Java public class Person { private StringPropertyfirstName; public void setFirstName(Stringval) { firstNameProperty().set(val); } public String getFirstName() { return firstNameProperty().get(); } public StringPropertyfirstNameProperty() { if (firstName == null) firstName = new SimpleStringProperty(this, "firstName"); return firstName; } private StringPropertylastName; public void setLastName(String value) { lastNameProperty().set(value); } public String getLastName() { return lastNameProperty().get(); } public StringPropertylastNameProperty() { if (lastName == null) // etc. } } 26
27. Properties in GroovyFX public class Person { @FXBindable String firstName; @FXBindable String lastName; } 27
28. public class Person { @FXBindable String firstName; @FXBindable String lastName= “Smith”; } Properties in GroovyFX 28 Optional initializers
29. public class Person { @FXBindable String firstName; @FXBindable String lastName = “Smith”; } def p = new Person() def last = p.lastName p.firstName = “Agent” Properties in GroovyFX 29 Get and set values
30. public class Person { @FXBindable String firstName; @FXBindable String lastName = “Smith”; } def p = new Person() def last = p.lastName p.firstName = “Agent” textField(text: bind(p.lastNameProperty())) Properties in GroovyFX 30 Access underlying property for binding
31. Binding in GroovyFX @FXBindable class Time { Integer hours Integer minutes Integer seconds Double hourAngle Double minuteAngle Double secondAngle public Time() { // bind the angle properties to the clock time hourAngleProperty().bind((hoursProperty() * 30.0) + (minutesProperty() * 0.5)) minuteAngleProperty().bind(minutesProperty() * 6.0) secondAngleProperty().bind(secondsProperty() * 6.0) } } 31
32. Animation in GroovyFX timeline(cycleCount: Timeline.INDEFINITE, autoReverse: true) { at (1000.ms) { change(rect1, 'x') to 200 tweenease_both change rect2.yProperty() to 200 tween linear } }.play() 32
33. timeline(cycleCount: Timeline.INDEFINITE, autoReverse: true) { at (1000.ms) { change(rect1, 'x') to 200 tweenease_both change rect2.yProperty() to 200 tween linear } }.play() Animation in GroovyFX 33 Easy animation syntax: at (duration) {keyframes}
48. 48 JavaFX With Clojure Artwork by Augusto Sellhorn http://sellmic.com/
49. A Little About Clojure Started in 2007 by Rich Hickey Functional Programming Language Derived from LISP Optimized for High Concurrency … and looks nothing like Java! 49 (def hello (fn [] "Hello world")) (hello)
50. Clojure Syntax in One Slide Symbols numbers – 2.178 ratios – 355/113 strings – “clojure”, “rocks” characters – symbols – a b c d keywords – :alpha :beta boolean – true, false null - nil Collections (commas optional) Lists (1, 2, 3, 4, 5) Vectors [1, 2, 3, 4, 5] Maps {:a 1, :b 2, :c 3, :d 4} Sets #{:a :b :c :d :e} 50 (plus macros that are syntactic sugar wrapping the above)
51. Clojure GUI Example (defnjavafxapp [] (let [stage (Stage. "JavaFX Stage") scene (Scene.)] (.setFill scene Color/LIGHTGREEN) (.setWidth stage 600) (.setHeight stage 450) (.setScene stage scene) (.setVisible stage true))) (javafxapp) 51
54. Closures in Clojure 54 Inner classes can be created using proxy (.addListenerhoverProperty (proxy [ChangeListener] [] (handle [p, o, v] (.setFillrect (if (.isHoverrect) Color/GREEN Color/RED)))))
55. Closures in Clojure Inner classes can be created using proxy 55 Proxy form: (proxy [class] [args] fs+) f => (name [params*] body) (.addListenerhoverProperty (proxy[ChangeListener][] (handle [p, o, v] (.setFillrect (if (.isHoverrect) Color/GREEN Color/RED)))))
57. What is Scala Started in 2001 by Martin Odersky Compiles to Java bytecodes Pure object-oriented language Also a functional programming language 57
58. Why Scala? Shares many language features with JavaFX Script that make GUI programming easier: Static Type Checking – Catch your errors at compile time Closures – Wrap behavior and pass it by reference Declarative – Express the UI by describing what it should look like Scala also supports Type Safe DSLs! Implicit Conversions – type safe class extension Operator Overloading – with standard precedence rules DelayedInit / @specialized – advanced language features 58
59. Java vs. Scala DSL public class HelloStage extends Application { public void start(Stage stage) { stage.setTitle("Hello Stage"); stage.setWidth(600); stage.setHeight(450); Scene scene = new Scene(); scene.setFill(Color.LIGHTGREEN); Rectangle rect = new Rectangle(); rect.setX(25); rect.setY(40); rect.setWidth(100); rect.setHeight(50); rect.setFill(Color.RED); scene.setRoot(new Group(rect)); stage.setScene(scene); stage.show(); } public static void main(String[] args) { launch(HelloStage.class, args); } } object HelloJavaFX extends JFXApp { stage = new Stage { title = "Hello Stage" width = 600 height = 450 scene = new Scene { fill = LIGHTGREEN content = Seq(new Rectangle { x = 25 y = 40 width = 100 height = 50 fill = RED }) } } } 59 21 Lines 430 Characters 17 Lines 177 Characters
60. object DisappearingCirclesextends JFXApp { stage = new Stage { title = "Disappearing Circles" width = 800 height = 600 scene = new Scene { fill = BLACK content = for (i <- 0 until 50) yield new Circle { centerX = random * 800 centerY = random * 600 radius = 150 fill = color(random, random, random, 0.2) effect = new BoxBlur(10, 10, 3) } } } } 60
61. 61 object DisappearingCirclesextends JFXApp{ stage = new Stage { title = "Disappearing Circles" width = 800 height = 600 scene = new Scene { fill = BLACK content = for (i <- 0 until 50) yield new Circle { centerX = random * 800 centerY = random * 600 radius = 150 fill = color(random, random, random, 0.2) effect = new BoxBlur(10, 10, 3) } } } } Base class for JavaFX applications
62. 62 object DisappearingCirclesextends JFXApp { stage = new Stage { title = "Disappearing Circles" width = 800 height = 600 scene = new Scene { fill = BLACK content = for (i <- 0 until 50) yield new Circle { centerX = random * 800 centerY = random * 600 radius = 150 fill = color(random, random, random, 0.2) effect = new BoxBlur(10, 10, 3) } } } } Declarative Stage definition
63. 63 object DisappearingCirclesextends JFXApp { stage = new Stage { title = "Disappearing Circles" width = 800 height = 600 scene = new Scene { fill = BLACK content = for (i <- 0 until 50) yield new Circle { centerX = random * 800 centerY = random * 600 radius = 150 fill = color(random, random, random, 0.2) effect = new BoxBlur(10, 10, 3) } } } } Inline property definitions
64. 64 object DisappearingCirclesextends JFXApp { stage = new Stage { title = "Disappearing Circles" width = 800 height = 600 scene = new Scene { fill = BLACK content = for (i <- 0 until 50) yield new Circle { centerX = random * 800 centerY = random * 600 radius = 150 fill = color(random, random, random, 0.2) effect = new BoxBlur(10, 10, 3) } } } } Sequence Creation Via Loop
65. Binding in Scala Infix Addition/Subtraction/Multiplication/Division: height <== rect1.height + rect2.height Aggregate Operators: width <== max(rect1.width, rect2.width, rect3.width) Conditional Expressions: strokeWidth <== when (hover) then 4 otherwise 0 Compound Expressions: text <== when (rect.hover || circle.hover && !disabled) then textField.text + " is enabled" otherwise "disabled" 65
66. Animation in Scala valtimeline = new Timeline { cycleCount = INDEFINITE autoReverse = true keyFrames = for (circle <- circles) yield at (40 s) { Set( circle.centerX -> random * stage.width, circle.centerY -> random * stage.height ) } } timeline.play(); 66
67. valtimeline = new Timeline { cycleCount = INDEFINITE autoReverse = true keyFrames = for (circle <- circles) yield at (40 s) { Set( circle.centerX -> random * stage.width, circle.centerY -> random * stage.height ) } } timeline.play(); Animation in Scala 67 JavaFX Script-like animation syntax: at (duration) {keyframes}
68. valtimeline = new Timeline { cycleCount = INDEFINITE autoReverse = true keyFrames = for (circle <- circles) yield at (40 s) { Set( circle.centerX -> random * stage.width, circle.centerY -> random * stage.height ) } } timeline.play(); Animation in Scala 68 Operator overloading for animation syntax
69. valtimeline = new Timeline { cycleCount = INDEFINITE autoReverse = true keyFrames = for (circle <- circles) yield at (40 s) { Set( circle.centerX-> random * stage.widthtween EASE_BOTH, circle.centerY-> random * stage.heighttween EASE_IN ) } } timeline.play(); Animation in Scala 69 Optional tween syntax
70. Event Listeners in Scala 70 Supported using the built-in Closure syntax Optional arguments for event objects 100% type-safe onMouseClicked= { Timeline(at(3 s){radius->0}).play() }
71. Event Listeners in Scala Supported using the built-in Closure syntax Optional arguments for event objects 100% type-safe 71 onMouseClicked= { Timeline(at(3 s){radius->0}).play() } Compact syntax {body}
72. Event Listeners in Scala Supported using the built-in Closure syntax Optional arguments for event objects 100% type-safe 72 Optional event parameter {(event) => body} onMouseClicked= { (e: MouseEvent) => Timeline(at(3 s){radius->0}).play() }
73. Other JVM Languages to Try JRuby Faithful to Ruby language with the power of the JVM Gosu Up and coming language created at GuideWire Easy to enhance libraries and create DSLs Mirah Invented by Charles Nutter Local Type Inference, Static and Dynamic Typing Fantom Created by Brian and Andy Frank Portable to Java and .NET Local Type Inference, Static and Dynamic Typing 73
80. Visage is JavaFX Script++ Default Parameters New Literal Syntax For: Angles – 35deg, 4rad, 1turn Colors –#DDCCBB, #AA33AA|CC Lengths – 5px, 2pt, 3in, 4sp Null-check Dereference var width = rect.!width Built-in Bindable Maps (coming soon!) varfruitMap = ["red" : apple, "yellow" : banana] var fruit = bind fruitMap["red"] 80
81. Visage and JavaFX 2.0 are made for each other… Enhanced Binding Retains lazy evaluation properties with additional expressive power Integrated Collections Sequences and Maps automatically convert between JavaFX Observable Lists/Maps Built-in Animation Syntax Ties into JavaFX animation subsystem Provides consistent, clean APIs 81
82. Conclusion You can write JavaFX applications in pure Java JavaFX is also usable in alternate languages You can get improved support using DSL libraries GroovyFX ScalaFX Or a dedicated UI JVM Language Visage
83. Pro JavaFX 2 Platform Coming Soon! Coming 4th quarter this year All examples rewritten in Java Covers the new JavaFX 2.0 APIs Will includes ScalaFX, GroovyFX, and Visage 83
84. 84 Stephen Chin steveonjava@gmail.com tweet: @steveonjava Dean Iverson dean@pleasingsoftware.com tweet: @deanriverson