JavaFX Your Way Building JavaFX Applications with Alternative Languages Stephen Chin Jonathan Giles GXS Oracle steve@widgetfx.org Jonathan.giles@oracle.com tweet: @steveonjava tweet: @jonathangiles
JavaFX Your Way Building JavaFX Applications with Alternative Languages Stephen Chin Jonathan Giles GXS Oracle steve@widgetfx.org Jonathan.giles@oracle.com tweet: @steveonjava tweet: @jonathangiles
Meet the Presenters… Steve Jonathan Family Man Motorcyclist 3
Disclaimer: This is proof of concept
THE FOLLOWING IS INTENDED TO OUTLINE OUR GENERAL PRODUCT DIRECTION. IT IS INTENDED FOR INFORMATION PURPOSES ONLY, AND MAY NOT BE INCORPORATED INTO ANY CONTRACT. IT IS NOT A COMMITMENT TO DELIVER ANY MATERIAL, CODE, OR FUNCTIONALITY, AND SHOULD NOT BE RELIED UPON IN MAKING PURCHASING DECISION. THE DEVELOPMENT, RELEASE, AND TIMING OF ANY FEATURES OR FUNCTIONALITY DESCRIBED FOR ORACLE'S PRODUCTS REMAINS AT THE SOLE DISCRETION OF ORACLE.
Disclaimer #2: This is code-heavy
Overall Presentation Goal Demonstrate the future potential of the JavaFX platform.
Agenda > Catch up on latest news > JavaFX in Java > Explore alternative languages  JRuby  Clojure  Groovy  Scala
Todays News • JavaFX Script no longer required to write JavaFX applications • Benefits: – Easier integration with business logic on JVM – Access to generics, annotations, (closures), etc – Java has great IDE support • Downsides: – JavaFX Script was kind to us
JavaFX With Java
JavaFX in Java > JavaFX API follows JavaBeans approach > Similar in feel to other UI toolkits (Swing, etc) > Researching approaches to minimize boilerplate
Binding > Unquestionably the biggest JavaFX Script innovation > Researching ways to incorporate into Java > Will not be as succinct as JavaFX Script > Genius‟ are deployed in underground labs pondering this right now
Observable Pseudo-Properties > Supports watching for changes to properties > Implemented via anonymous inner classes > Maybe closures in the future
Observable Pseudo-Properties Rectangle rect = new Rectangle(); rect.setX(40); rect.setY(40); rect.setWidth(100); rect.setHeight(200); rect.addChangedListener(Rectangle.HOVER, new BooleanListener() { });
Observable Pseudo-Properties Rectangle rect = new Rectangle(); rect.setX(40); rect.setY(40); rect.setWidth(100); Before: „addChangingListener‟ rect.setHeight(200); After: „addChangedListener‟ rect.addChangedListener(Rectangle.HOVER, new BooleanListener() { });
Observable Pseudo-Properties Rectangle rect = new Rectangle(); rect.setX(40); The property we are wanting to rect.setY(40); watch rect.setWidth(100); rect.setHeight(200); rect.addChangedListener(Rectangle.HOVER, new BooleanListener() { });
Observable Pseudo-Properties Rectangle rect = new Rectangle(); rect.setX(40); Listener for each primitive type, rect.setY(40); and Objects in general rect.setWidth(100); rect.setHeight(200); rect.addChangedListener(Rectangle.HOVER, new BooleanListener() { });
Observable Pseudo-Properties Rectangle rect = new Rectangle(); rect.setX(40); rect.setY(40); rect.setWidth(100); rect.setHeight(200); rect.addChangedListener(Rectangle.HOVER, new BooleanListener() { public void handle(Bean bean, PropertyReference pr, boolean oldHover) { } }); Rectangle is a Bean
Observable Pseudo-Properties Rectangle rect = new Rectangle(); rect.setX(40); rect.setY(40); rect.setWidth(100); rect.setHeight(200); rect.addChangedListener(Rectangle.HOVER, new BooleanListener() { public void handle(Bean bean, PropertyReference pr, boolean oldHover) { } }); Refers to the Rectangle.hover „property‟
Observable Pseudo-Properties Rectangle rect = new Rectangle(); rect.setX(40); rect.setY(40); rect.setWidth(100); rect.setHeight(200); rect.addChangedListener(Rectangle.HOVER, new BooleanListener() { public void handle(Bean bean, PropertyReference pr, boolean oldHover) { } }); For performance reasons, this is the old value.
Observable Pseudo-Properties Rectangle rect = new Rectangle(); rect.setX(40); rect.setY(40); rect.setWidth(100); rect.setHeight(200); rect.addChangedListener(Rectangle.HOVER, new BooleanListener() { public void handle(Bean bean, PropertyReference pr, boolean oldHover) { rect.setFill(rect.isHover() ? Color.GREEN : Color.RED); } });
Sequences in Java > Sequence class available  Essentially an observable List > Public API is still sequence-based > Internal code can use lighter collections API
Example Application public class HelloStage implements Runnable { public void run() { Stage stage = new Stage(); stage.setTitle("Hello Stage"); stage.setWidth(600); stage.setHeight(450); Scene scene = new Scene(); scene.setFill(Color.LIGHTGREEN); stage.setScene(scene); stage.setVisible(true); } public static void main(String[] args) { FX.start(new HelloStage()); } }
Summary > The JVM has a modern UI toolkit coming to it > Total port to Java – no hacks or kludges > Many languages to choose from > Alternate languages == exciting possibilities > Choose the best language for your needs
Major Question How can alternative languages make developing JavaFX user interfaces easier & more productive? 28
JavaFX With JRuby
Why JRuby? > Direct access to Java APIs > Dynamic Typing > Closures > „Closure conversion‟ for interfaces
Java in JRuby - Accessing Properties timeline.setAutoReverse(true) timeline.autoReverse = true timeline.auto_reverse = true timeline.getKeyFrames().add(kf) timeline.key_frames.add(kf) timeline.key_frames.add kf
JRuby Example 1: Simple Stage require 'java' FX = Java::javafx.lang.FX Stage = Java::javafx.stage.Stage Scene = Java::javafx.scene.Scene Color = Java::javafx.scene.paint.Color class HelloStage stage = Stage.new include java.lang.Runnable stage.title = 'Hello Stage (JRuby)' stage.width = 600 stage.height = 450 def run ..... scene = Scene.new end scene.fill = Color::LIGHTGREEN end stage.scene = scene FX.start(HelloStage.new); stage.visible = true;
JRuby Example 2 rect = Rectangle.new rect.x = 25 rect.y = 40 rect.width = 100 rect.height = 50 rect.fill = Color::RED scene.content.add(rect) timeline = Timeline.new timeline.repeat_count = Timeline::INDEFINITE timeline.auto_reverse = true kv = KeyValue.new(rect, Rectangle::X, 200); kf = KeyFrame.new(Duration.valueOf(500), kv); timeline.key_frames.add kf; timeline.play();
JRuby Closure Conversion rect.add_changed_listener(Rectangle::HOVER) do |bean, pr, bln| rect.fill = rect.hover ? Color::GREEN : Color::RED; end 34
JRuby Swiby require 'swiby' class HelloWorldModel attr_accessor :saying end model = HelloWorldModel.new model.saying = "Hello World" Frame { title "Hello World“ width 200 content { Label { text bind(model,:saying) } } visible true } 35
JavaFX With Clojure Artwork by Augusto Sellhorn http://sellmic.com/ 36
A Little About Clojure > Started in 2007 by Rich Hickey > Functional Programming Language > Derived from LISP > Optimized for High Concurrency (def hello (fn [] "Hello world")) (hello) > … and looks nothing like Java! 37
Clojure Syntax in One Slide Symbols Collections (commas optional) > numbers – 2.178 > Lists > ratios – 355/113 (1, 2, 3, 4, 5) > strings – “clojure”, “rocks” > Vectors > characters – a b c d [1, 2, 3, 4, 5] > symbols – a b c d > Maps > keywords – :alpha :beta {:a 1, :b 2, :c 3, :d 4} > boolean – true, false > Sets > null - nil #{:a :b :c :d :e} (plus macros that are syntactic sugar wrapping the above) 38
Clojure GUI Example (defn javafxapp [] (let [stage (Stage. "JavaFX Stage") scene (Scene.)] (.setFill scene Color/LIGHTGREEN) (.setWidth stage 600) (.setHeight stage 450) (.setScene stage scene) (.setVisible stage true))) (javafxapp) 39
Clojure GUI Example Create a Function for the Application (defn javafxapp [] (let [stage (Stage. "JavaFX Stage") scene (Scene.)] (.setFill scene Color/LIGHTGREEN) (.setWidth stage 600) (.setHeight stage 450) (.setScene stage scene) (.setVisible stage true))) (javafxapp) 40
Clojure GUI Example (defn javafxapp [] (let [stage (Stage. "JavaFX Stage") scene (Scene.)] (.setFill scene Color/LIGHTGREEN) Initialize the Stage and (.setWidth stage 600) Scene Variables (.setHeight stage 450) (.setScene stage scene) (.setVisible stage true))) (javafxapp) 41
Clojure GUI Example (defn javafxapp [] Call Setter Methods (let [stage (Stage. "JavaFX Stage") on Scene and Stage scene (Scene.)] (.setFill scene Color/LIGHTGREEN) (.setWidth stage 600) (.setHeight stage 450) (.setScene stage scene) (.setVisible stage true))) (javafxapp) 42
Clojure GUI Example (defn javafxapp [] (let [stage (Stage. "JavaFX Stage") Java Constant Syntax scene (Scene.)] (.setFill scene Color/LIGHTGREEN) (.setWidth stage 600) (.setHeight stage 450) (.setScene stage scene) (.setVisible stage true))) (javafxapp) Java Method Syntax 43
Simpler Code Using doto (defn javafxapp [] (let [stage (Stage. "JavaFX Stage") scene (Scene.)] (doto scene (.setFill Color/LIGHTGREEN)) (doto stage (.setWidth 600) (.setHeight 450) (.setScene scene) (.setVisible true)))) (javafxapp) 44
Simpler Code Using doto (defn javafxapp [] (let [stage (Stage. "JavaFX Stage") scene (Scene.)] (doto scene (.setFill Color/LIGHTGREEN)) (doto stage doto form: (.setWidth 600) (doto symbol (.setHeight 450) (.method params)) (.setScene scene) equals: (.setVisible true)))) (.method symbol params) (javafxapp) 45
Refined Clojure GUI Example (defn javafxapp [] (doto (Stage. "JavaFX Stage") (.setWidth 600) (.setHeight 450) (.setScene (doto (Scene.) (.setFill Color/LIGHTGREEN) (.setContent (list (doto (Rectangle.) (.setX 25) (.setY 40) (.setWidth 100) (.setHeight 50) (.setFill Color/RED)))))) (.setVisible true))) (javafxapp) 46
Refined Clojure GUI Example (defn javafxapp [] Let replaced with (doto (Stage. "JavaFX Stage") inline declarations (.setWidth 600) (.setHeight 450) (.setScene (doto (Scene.) (.setFill Color/LIGHTGREEN) (.setContent (list (doto (Rectangle.) (.setX 25) (.setY 40) (.setWidth 100) (.setHeight 50) (.setFill Color/RED)))))) (.setVisible true))) (javafxapp) 47
Refined Clojure GUI Example (defn javafxapp [] (doto (Stage. "JavaFX Stage") (.setWidth 600) Doto allows nested (.setHeight 450) (.setScene (doto (Scene.) data structures (.setFill Color/LIGHTGREEN) (.setContent (list (doto (Rectangle.) (.setX 25) (.setY 40) (.setWidth 100) (.setHeight 50) (.setFill Color/RED)))))) (.setVisible true))) (javafxapp) 48
Refined Clojure GUI Example (defn javafxapp [] (doto (Stage. "JavaFX Stage") (.setWidth 600) (.setHeight 450) (.setScene (doto (Scene.) (.setFill Color/LIGHTGREEN) (.setContent (list (doto (Rectangle.) (.setX 25) (.setY 40) Now a nested (.setWidth 100) (.setHeight 50) Rectangle fits! (.setFill Color/RED)))))) (.setVisible true))) (javafxapp) 49
Closures in Clojure > Inner classes can be created using proxy (.addChangeListener rect Rectangle/HOVER (proxy [BooleanListener] [] (handle [b, p, o] (.setFill rect (if (.isHover rect) Color/GREEN Color/RED))))) 50
Closures in Clojure > Inner classes can be created using proxy Proxy form: (proxy [class] [args] fs+) f => (name [params*] body) (.addChangeListener rect Rectangle/HOVER (proxy [BooleanListener] [] (handle [b, p, o] (.setFill rect (if (.isHover rect) Color/GREEN Color/RED))))) 51
JavaFX With Groovy
Features of Groovy > Tight integration with Java  Very easy to port from Java to Groovy > Declarative syntax  Familiar to JavaFX Script developers > Builders
Example 1: Simple FX Script to Groovy
Step 1: Lazy conversion to Groovy class HelloStage implements Runnable { void run() { Stage stage = new Stage(); stage.setTitle("Hello Stage (Groovy)“); stage.setWidth(600); stage.setHeight(450); Scene scene = new Scene(); scene.setFill(Color.LIGHTSKYBLUE); stage.setScene(scene); stage.setVisible(true); } static void main(args) { FX.start(new HelloStage()); } }
Step 2: Slightly More Groovy class HelloStage implements Runnable { void run() { new Stage( title: "Hello Stage (Groovy)", width: 600, height: 450, visible: true, scene: new Scene( fill: Color.LIGHTSKYBLUE, ) ); } static void main(args) { FX.start(new HelloStage()); } }
Slight Aside: Groovy Builders > Groovy builders make writing custom DSLs easy > For the next slide, I am using a builder I defined > Hopefully the community will improve upon this
Step 3: Using a Groovy Builder FxBuilder.build { stage = stage( title: "Hello World", width: 600, height: 450, scene: scene(fill: Color.LIGHTSKYBLUE) { ... } ) stage.visible = true; }
Step 4: With Content FxBuilder.build { stage = stage( title: "Hello Rectangle (Groovy FxBuilder 2)", width: 600, height: 450, scene: scene(fill: Color.LIGHTSKYBLUE) { rectangle( x: 25, y: 40, width: 100, height: 50, fill: Color.RED ) } ) stage.visible = true; }
Example 2: FX Script Animation in Groovy
Step 1: JavaFX Script def timeline = Timeline { repeatCount: Timeline.INDEFINITE autoReverse: true keyFrames: [ KeyFrame { time: 750ms values : [ rect1.x => 200.0 tween Interpolator.LINEAR, rect2.y => 200.0 tween Interpolator.LINEAR, circle1.radius => 200.0 tween Interpolator.LINEAR ] } ]; } timeline.play();
Step 1a: JavaFX Script Simplification def timeline = Timeline { repeatCount: Timeline.INDEFINITE autoReverse: true keyFrames: [ at (750ms) { rect1.x => 200.0 tween Interpolator.LINEAR; rect2.y => 200.0 tween Interpolator.LINEAR; circle1.radius => 200.0 tween Interpolator.LINEAR; } ]; } timeline.play();
Step 2: Java-ish Groovy Animations final Timeline timeline = new Timeline( repeatCount: Timeline.INDEFINITE, autoReverse: true ) final KeyValue kv1 = new KeyValue (rect1, Rectangle.X, 200); final KeyValue kv2 = new KeyValue (rect2, Rectangle.Y, 200); final KeyValue kv3 = new KeyValue (circle1, Circle.RADIUS, 200); final KeyFrame kf = new KeyFrame(Duration.valueOf(750), kv1, kv2, kv3); timeline.getKeyFrames().add(kf); timeline.play();
Step 3: JavaFX Animation in Groovy (Using Builders) timeline = timeline(repeatCount: Timeline.INDEFINITE, autoReverse: true) { keyframes { keyframe(time: 750) { keyvalue(target: rect1, property: Rectangle.Y, endValue: 200); keyvalue(target: rect2, property: Rectangle.X, endValue: 200); keyvalue(target: circle1, property: Circle.RADIUS, endValue: 200); } } } timeline.play();
Groovy Closures - With interface coercion def f = { bean, pr, bln -> rect.setFill(rect.isHover() ? Color.GREEN : Color.RED); } as BooleanListener; rect.addChangedListener(Rectangle.HOVER, f);
Groovy Closures - Interfaces with multiple methods def keyValueTarget = [ getType: { Type.FLOAT }, unwrap: { this }, getValue: { Float.valueOf(rect.getX()) }, setValue: { Object value -> rect.setX((Float)value) } ] as KeyValueTarget;
JavaFX With Scala 67
What is Scala 2001 2006 • Scala Started • Scala v2.0 2003/2004 2010 • Scala v1.0 • Scala 2.8.0 (latest) > Started in 2001 by Martin Odersky > Compiles to Java bytecodes > Pure object-oriented language > Also a functional programming language 68
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 DSLs! 69
Java vs. Scala DSL public class HelloStage implements Runnable { object HelloJavaFX extends JavaFXApplication { def stage = new Stage { public void run() { title = "Hello Stage" Stage stage = new Stage(); width = 600 stage.setTitle("Hello Stage"); height = 450 stage.setWidth(600); scene = new Scene { stage.setHeight(450); fill = Color.LIGHTGREEN Scene scene = new Scene(); content = List(new Rectangle { 22 Lines scene.setFill(Color.LIGHTGREEN); Rectangle rect = new Rectangle(); 17 Lines x = 25 y = 40 rect.setX(25); width = 100 545 Characters rect.setY(40); rect.setWidth(100); 324 Characters height = 50 fill = Color.RED rect.setHeight(50); }) rect.setFill(Color.RED); } stage.add(rect); } stage.setScene(scene); } stage.setVisible(true); } public static void main(String[] args) { FX.start(new HelloStage()); } } 70
object HelloJavaFX extends JavaFXApplication { def stage = new Stage { title = "Hello Stage" width = 600 height = 450 scene = new Scene { fill = Color.LIGHTGREEN content = List(new Rectangle { x = 25 y = 40 width = 100 height = 50 fill = Color.RED }) } } } 71
object HelloJavaFX extends JavaFXApplication { def stage = new Stage { title = "Hello Stage" width = 600 height = 450 for JavaFX Base class applications scene = new Scene { fill = Color.LIGHTGREEN content = List(new Rectangle { x = 25 y = 40 width = 100 height = 50 fill = Color.RED }) } } } 72
object HelloJavaFX extends JavaFXApplication { def stage = new Stage { title = "Hello Stage" width = 600 height = 450 scene = new Scene { Declarative Stage fill = Color.LIGHTGREEN definition content = List(new Rectangle { x = 25 y = 40 width = 100 height = 50 fill = Color.RED }) } } } 73
object HelloJavaFX extends JavaFXApplication { def stage = new Stage { title = "Hello Stage" width = 600 Inline property height = 450 definitions scene = new Scene { fill = Color.LIGHTGREEN content = List(new Rectangle { x = 25 y = 40 width = 100 height = 50 fill = Color.RED }) } } } 74
object HelloJavaFX extends JavaFXApplication { def stage = new Stage { title = "Hello Stage" width = 600 height = 450 scene = new Scene { fill = Color.LIGHTGREEN content = List(new Rectangle { x = 25 y = 40 width = 100 height = 50 List Construction fill = Color.RED Syntax }) } } } 75
Animation in Scala def timeline = new Timeline { repeatCount = INDEFINITE autoReverse = true keyFrames = List( new KeyFrame(50) { values = List( new KeyValue(rect1, Rectangle.X -> 300), new KeyValue(rect2, Rectangle.Y -> 500), new KeyValue(rect2, Rectangle.Width -> 150) ) } ) } 76
Animation in Scala def timeline = new Timeline { repeatCount = INDEFINITE autoReverse = true Duration set by keyFrames = List( Constructor Parameter new KeyFrame(50) { values = List( new KeyValue(rect1, Rectangle.X -> 300), new KeyValue(rect2, Rectangle.Y -> 500), new KeyValue(rect2, Rectangle.WIDTH -> 150) ) } ) } 77
Animation in Scala def timeline = new Timeline { repeatCount = INDEFINITE autoReverse = true keyFrames = List( new KeyFrame(50) { values = List( new KeyValue(rect1, Rectangle.X -> 300), new KeyValue(rect2, Rectangle.Y -> 500), new KeyValue(rect2, Rectangle.WIDTH -> 150) ) } ) } Operator overloading for animation syntax 78
Closures in Scala > Closures are also supported in Scala > And they are 100% type-safe rect.addChangedListener(Node.HOVER, (b, p, o) => { rect.fill = if (rect.hover) Color.GREEN else Color.RED }) 79
Closures in Scala > Closures are also supported in Scala > And they are 100% type-safe rect.addChangedListener(Node.HOVER, (b, p, o) => { rect.fill = if (rect.hover) Color.GREEN else Color.RED }) Compact syntax (params) => {body} 80
Conclusion > JavaFX as Java APIs is great > Usable in alternate languages > Over time improved support is possible  E.g. Groovy builders, Scala DSL Remember: This is a proof of concept only – you can not leave this session and do this today.
Stephen Chin Jonathan Giles steve@widgetfx.org Jonathan.giles@oracle.com tweet: @steveonjava tweet: @jonathangiles 83

JavaFX Your Way: Building JavaFX Applications with Alternative Languages

  • 1.
    JavaFX Your Way BuildingJavaFX Applications with Alternative Languages Stephen Chin Jonathan Giles GXS Oracle steve@widgetfx.org Jonathan.giles@oracle.com tweet: @steveonjava tweet: @jonathangiles
  • 2.
    JavaFX Your Way BuildingJavaFX Applications with Alternative Languages Stephen Chin Jonathan Giles GXS Oracle steve@widgetfx.org Jonathan.giles@oracle.com tweet: @steveonjava tweet: @jonathangiles
  • 3.
    Meet the Presenters… Steve Jonathan Family Man Motorcyclist 3
  • 4.
  • 5.
    THE FOLLOWING ISINTENDED TO OUTLINE OUR GENERAL PRODUCT DIRECTION. IT IS INTENDED FOR INFORMATION PURPOSES ONLY, AND MAY NOT BE INCORPORATED INTO ANY CONTRACT. IT IS NOT A COMMITMENT TO DELIVER ANY MATERIAL, CODE, OR FUNCTIONALITY, AND SHOULD NOT BE RELIED UPON IN MAKING PURCHASING DECISION. THE DEVELOPMENT, RELEASE, AND TIMING OF ANY FEATURES OR FUNCTIONALITY DESCRIBED FOR ORACLE'S PRODUCTS REMAINS AT THE SOLE DISCRETION OF ORACLE.
  • 6.
  • 7.
    Overall Presentation Goal Demonstrate the future potential of the JavaFX platform.
  • 8.
    Agenda > Catch up on latest news > JavaFX in Java > Explore alternative languages  JRuby  Clojure  Groovy  Scala
  • 9.
    Todays News • JavaFX Script no longer required to write JavaFX applications • Benefits: – Easier integration with business logic on JVM – Access to generics, annotations, (closures), etc – Java has great IDE support • Downsides: – JavaFX Script was kind to us
  • 10.
  • 11.
    JavaFX in Java > JavaFX API follows JavaBeans approach > Similar in feel to other UI toolkits (Swing, etc) > Researching approaches to minimize boilerplate
  • 12.
    Binding > Unquestionably the biggest JavaFX Script innovation > Researching ways to incorporate into Java > Will not be as succinct as JavaFX Script > Genius‟ are deployed in underground labs pondering this right now
  • 13.
    Observable Pseudo-Properties > Supports watching for changes to properties > Implemented via anonymous inner classes > Maybe closures in the future
  • 14.
    Observable Pseudo-Properties Rectangle rect= new Rectangle(); rect.setX(40); rect.setY(40); rect.setWidth(100); rect.setHeight(200); rect.addChangedListener(Rectangle.HOVER, new BooleanListener() { });
  • 15.
    Observable Pseudo-Properties Rectangle rect= new Rectangle(); rect.setX(40); rect.setY(40); rect.setWidth(100); Before: „addChangingListener‟ rect.setHeight(200); After: „addChangedListener‟ rect.addChangedListener(Rectangle.HOVER, new BooleanListener() { });
  • 16.
    Observable Pseudo-Properties Rectangle rect= new Rectangle(); rect.setX(40); The property we are wanting to rect.setY(40); watch rect.setWidth(100); rect.setHeight(200); rect.addChangedListener(Rectangle.HOVER, new BooleanListener() { });
  • 17.
    Observable Pseudo-Properties Rectangle rect= new Rectangle(); rect.setX(40); Listener for each primitive type, rect.setY(40); and Objects in general rect.setWidth(100); rect.setHeight(200); rect.addChangedListener(Rectangle.HOVER, new BooleanListener() { });
  • 18.
    Observable Pseudo-Properties Rectangle rect= new Rectangle(); rect.setX(40); rect.setY(40); rect.setWidth(100); rect.setHeight(200); rect.addChangedListener(Rectangle.HOVER, new BooleanListener() { public void handle(Bean bean, PropertyReference pr, boolean oldHover) { } }); Rectangle is a Bean
  • 19.
    Observable Pseudo-Properties Rectangle rect= new Rectangle(); rect.setX(40); rect.setY(40); rect.setWidth(100); rect.setHeight(200); rect.addChangedListener(Rectangle.HOVER, new BooleanListener() { public void handle(Bean bean, PropertyReference pr, boolean oldHover) { } }); Refers to the Rectangle.hover „property‟
  • 20.
    Observable Pseudo-Properties Rectangle rect= new Rectangle(); rect.setX(40); rect.setY(40); rect.setWidth(100); rect.setHeight(200); rect.addChangedListener(Rectangle.HOVER, new BooleanListener() { public void handle(Bean bean, PropertyReference pr, boolean oldHover) { } }); For performance reasons, this is the old value.
  • 21.
    Observable Pseudo-Properties Rectangle rect= new Rectangle(); rect.setX(40); rect.setY(40); rect.setWidth(100); rect.setHeight(200); rect.addChangedListener(Rectangle.HOVER, new BooleanListener() { public void handle(Bean bean, PropertyReference pr, boolean oldHover) { rect.setFill(rect.isHover() ? Color.GREEN : Color.RED); } });
  • 22.
    Sequences in Java > Sequence class available  Essentially an observable List > Public API is still sequence-based > Internal code can use lighter collections API
  • 23.
    Example Application public classHelloStage implements Runnable { public void run() { Stage stage = new Stage(); stage.setTitle("Hello Stage"); stage.setWidth(600); stage.setHeight(450); Scene scene = new Scene(); scene.setFill(Color.LIGHTGREEN); stage.setScene(scene); stage.setVisible(true); } public static void main(String[] args) { FX.start(new HelloStage()); } }
  • 24.
    Summary > The JVM has a modern UI toolkit coming to it > Total port to Java – no hacks or kludges > Many languages to choose from > Alternate languages == exciting possibilities > Choose the best language for your needs
  • 25.
    Major Question How can alternative languages make developing JavaFX user interfaces easier & more productive? 28
  • 26.
  • 27.
    Why JRuby? > Direct access to Java APIs > Dynamic Typing > Closures > „Closure conversion‟ for interfaces
  • 28.
    Java in JRuby -Accessing Properties timeline.setAutoReverse(true) timeline.autoReverse = true timeline.auto_reverse = true timeline.getKeyFrames().add(kf) timeline.key_frames.add(kf) timeline.key_frames.add kf
  • 29.
    JRuby Example 1:Simple Stage require 'java' FX = Java::javafx.lang.FX Stage = Java::javafx.stage.Stage Scene = Java::javafx.scene.Scene Color = Java::javafx.scene.paint.Color class HelloStage stage = Stage.new include java.lang.Runnable stage.title = 'Hello Stage (JRuby)' stage.width = 600 stage.height = 450 def run ..... scene = Scene.new end scene.fill = Color::LIGHTGREEN end stage.scene = scene FX.start(HelloStage.new); stage.visible = true;
  • 30.
    JRuby Example 2 rect= Rectangle.new rect.x = 25 rect.y = 40 rect.width = 100 rect.height = 50 rect.fill = Color::RED scene.content.add(rect) timeline = Timeline.new timeline.repeat_count = Timeline::INDEFINITE timeline.auto_reverse = true kv = KeyValue.new(rect, Rectangle::X, 200); kf = KeyFrame.new(Duration.valueOf(500), kv); timeline.key_frames.add kf; timeline.play();
  • 31.
    JRuby Closure Conversion rect.add_changed_listener(Rectangle::HOVER)do |bean, pr, bln| rect.fill = rect.hover ? Color::GREEN : Color::RED; end 34
  • 32.
    JRuby Swiby require 'swiby' classHelloWorldModel attr_accessor :saying end model = HelloWorldModel.new model.saying = "Hello World" Frame { title "Hello World“ width 200 content { Label { text bind(model,:saying) } } visible true } 35
  • 33.
    JavaFX With Clojure Artwork by Augusto Sellhorn http://sellmic.com/ 36
  • 34.
    A Little About Clojure > Started in 2007 by Rich Hickey > Functional Programming Language > Derived from LISP > Optimized for High Concurrency (def hello (fn [] "Hello world")) (hello) > … and looks nothing like Java! 37
  • 35.
    Clojure Syntax inOne Slide Symbols Collections (commas optional) > numbers – 2.178 > Lists > ratios – 355/113 (1, 2, 3, 4, 5) > strings – “clojure”, “rocks” > Vectors > characters – a b c d [1, 2, 3, 4, 5] > symbols – a b c d > Maps > keywords – :alpha :beta {:a 1, :b 2, :c 3, :d 4} > boolean – true, false > Sets > null - nil #{:a :b :c :d :e} (plus macros that are syntactic sugar wrapping the above) 38
  • 36.
    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) 39
  • 37.
    Clojure GUI Example Create a Function for the Application (defn javafxapp [] (let [stage (Stage. "JavaFX Stage") scene (Scene.)] (.setFill scene Color/LIGHTGREEN) (.setWidth stage 600) (.setHeight stage 450) (.setScene stage scene) (.setVisible stage true))) (javafxapp) 40
  • 38.
    Clojure GUI Example (defnjavafxapp [] (let [stage (Stage. "JavaFX Stage") scene (Scene.)] (.setFill scene Color/LIGHTGREEN) Initialize the Stage and (.setWidth stage 600) Scene Variables (.setHeight stage 450) (.setScene stage scene) (.setVisible stage true))) (javafxapp) 41
  • 39.
    Clojure GUI Example (defnjavafxapp [] Call Setter Methods (let [stage (Stage. "JavaFX Stage") on Scene and Stage scene (Scene.)] (.setFill scene Color/LIGHTGREEN) (.setWidth stage 600) (.setHeight stage 450) (.setScene stage scene) (.setVisible stage true))) (javafxapp) 42
  • 40.
    Clojure GUI Example (defnjavafxapp [] (let [stage (Stage. "JavaFX Stage") Java Constant Syntax scene (Scene.)] (.setFill scene Color/LIGHTGREEN) (.setWidth stage 600) (.setHeight stage 450) (.setScene stage scene) (.setVisible stage true))) (javafxapp) Java Method Syntax 43
  • 41.
    Simpler Code Usingdoto (defn javafxapp [] (let [stage (Stage. "JavaFX Stage") scene (Scene.)] (doto scene (.setFill Color/LIGHTGREEN)) (doto stage (.setWidth 600) (.setHeight 450) (.setScene scene) (.setVisible true)))) (javafxapp) 44
  • 42.
    Simpler Code Usingdoto (defn javafxapp [] (let [stage (Stage. "JavaFX Stage") scene (Scene.)] (doto scene (.setFill Color/LIGHTGREEN)) (doto stage doto form: (.setWidth 600) (doto symbol (.setHeight 450) (.method params)) (.setScene scene) equals: (.setVisible true)))) (.method symbol params) (javafxapp) 45
  • 43.
    Refined Clojure GUIExample (defn javafxapp [] (doto (Stage. "JavaFX Stage") (.setWidth 600) (.setHeight 450) (.setScene (doto (Scene.) (.setFill Color/LIGHTGREEN) (.setContent (list (doto (Rectangle.) (.setX 25) (.setY 40) (.setWidth 100) (.setHeight 50) (.setFill Color/RED)))))) (.setVisible true))) (javafxapp) 46
  • 44.
    Refined Clojure GUIExample (defn javafxapp [] Let replaced with (doto (Stage. "JavaFX Stage") inline declarations (.setWidth 600) (.setHeight 450) (.setScene (doto (Scene.) (.setFill Color/LIGHTGREEN) (.setContent (list (doto (Rectangle.) (.setX 25) (.setY 40) (.setWidth 100) (.setHeight 50) (.setFill Color/RED)))))) (.setVisible true))) (javafxapp) 47
  • 45.
    Refined Clojure GUIExample (defn javafxapp [] (doto (Stage. "JavaFX Stage") (.setWidth 600) Doto allows nested (.setHeight 450) (.setScene (doto (Scene.) data structures (.setFill Color/LIGHTGREEN) (.setContent (list (doto (Rectangle.) (.setX 25) (.setY 40) (.setWidth 100) (.setHeight 50) (.setFill Color/RED)))))) (.setVisible true))) (javafxapp) 48
  • 46.
    Refined Clojure GUIExample (defn javafxapp [] (doto (Stage. "JavaFX Stage") (.setWidth 600) (.setHeight 450) (.setScene (doto (Scene.) (.setFill Color/LIGHTGREEN) (.setContent (list (doto (Rectangle.) (.setX 25) (.setY 40) Now a nested (.setWidth 100) (.setHeight 50) Rectangle fits! (.setFill Color/RED)))))) (.setVisible true))) (javafxapp) 49
  • 47.
    Closures in Clojure > Inner classes can be created using proxy (.addChangeListener rect Rectangle/HOVER (proxy [BooleanListener] [] (handle [b, p, o] (.setFill rect (if (.isHover rect) Color/GREEN Color/RED))))) 50
  • 48.
    Closures in Clojure > Inner classes can be created using proxy Proxy form: (proxy [class] [args] fs+) f => (name [params*] body) (.addChangeListener rect Rectangle/HOVER (proxy [BooleanListener] [] (handle [b, p, o] (.setFill rect (if (.isHover rect) Color/GREEN Color/RED))))) 51
  • 49.
  • 50.
    Features of Groovy > Tight integration with Java  Very easy to port from Java to Groovy > Declarative syntax  Familiar to JavaFX Script developers > Builders
  • 51.
    Example 1: SimpleFX Script to Groovy
  • 52.
    Step 1: Lazyconversion to Groovy class HelloStage implements Runnable { void run() { Stage stage = new Stage(); stage.setTitle("Hello Stage (Groovy)“); stage.setWidth(600); stage.setHeight(450); Scene scene = new Scene(); scene.setFill(Color.LIGHTSKYBLUE); stage.setScene(scene); stage.setVisible(true); } static void main(args) { FX.start(new HelloStage()); } }
  • 53.
    Step 2: SlightlyMore Groovy class HelloStage implements Runnable { void run() { new Stage( title: "Hello Stage (Groovy)", width: 600, height: 450, visible: true, scene: new Scene( fill: Color.LIGHTSKYBLUE, ) ); } static void main(args) { FX.start(new HelloStage()); } }
  • 54.
    Slight Aside: GroovyBuilders > Groovy builders make writing custom DSLs easy > For the next slide, I am using a builder I defined > Hopefully the community will improve upon this
  • 55.
    Step 3: Usinga Groovy Builder FxBuilder.build { stage = stage( title: "Hello World", width: 600, height: 450, scene: scene(fill: Color.LIGHTSKYBLUE) { ... } ) stage.visible = true; }
  • 56.
    Step 4: WithContent FxBuilder.build { stage = stage( title: "Hello Rectangle (Groovy FxBuilder 2)", width: 600, height: 450, scene: scene(fill: Color.LIGHTSKYBLUE) { rectangle( x: 25, y: 40, width: 100, height: 50, fill: Color.RED ) } ) stage.visible = true; }
  • 57.
    Example 2: FXScript Animation in Groovy
  • 58.
    Step 1: JavaFXScript def timeline = Timeline { repeatCount: Timeline.INDEFINITE autoReverse: true keyFrames: [ KeyFrame { time: 750ms values : [ rect1.x => 200.0 tween Interpolator.LINEAR, rect2.y => 200.0 tween Interpolator.LINEAR, circle1.radius => 200.0 tween Interpolator.LINEAR ] } ]; } timeline.play();
  • 59.
    Step 1a: JavaFXScript Simplification def timeline = Timeline { repeatCount: Timeline.INDEFINITE autoReverse: true keyFrames: [ at (750ms) { rect1.x => 200.0 tween Interpolator.LINEAR; rect2.y => 200.0 tween Interpolator.LINEAR; circle1.radius => 200.0 tween Interpolator.LINEAR; } ]; } timeline.play();
  • 60.
    Step 2: Java-ishGroovy Animations final Timeline timeline = new Timeline( repeatCount: Timeline.INDEFINITE, autoReverse: true ) final KeyValue kv1 = new KeyValue (rect1, Rectangle.X, 200); final KeyValue kv2 = new KeyValue (rect2, Rectangle.Y, 200); final KeyValue kv3 = new KeyValue (circle1, Circle.RADIUS, 200); final KeyFrame kf = new KeyFrame(Duration.valueOf(750), kv1, kv2, kv3); timeline.getKeyFrames().add(kf); timeline.play();
  • 61.
    Step 3: JavaFXAnimation in Groovy (Using Builders) timeline = timeline(repeatCount: Timeline.INDEFINITE, autoReverse: true) { keyframes { keyframe(time: 750) { keyvalue(target: rect1, property: Rectangle.Y, endValue: 200); keyvalue(target: rect2, property: Rectangle.X, endValue: 200); keyvalue(target: circle1, property: Circle.RADIUS, endValue: 200); } } } timeline.play();
  • 62.
    Groovy Closures -With interface coercion def f = { bean, pr, bln -> rect.setFill(rect.isHover() ? Color.GREEN : Color.RED); } as BooleanListener; rect.addChangedListener(Rectangle.HOVER, f);
  • 63.
    Groovy Closures - Interfaces with multiple methods def keyValueTarget = [ getType: { Type.FLOAT }, unwrap: { this }, getValue: { Float.valueOf(rect.getX()) }, setValue: { Object value -> rect.setX((Float)value) } ] as KeyValueTarget;
  • 64.
  • 65.
    What is Scala 2001 2006 • Scala Started • Scala v2.0 2003/2004 2010 • Scala v1.0 • Scala 2.8.0 (latest) > Started in 2001 by Martin Odersky > Compiles to Java bytecodes > Pure object-oriented language > Also a functional programming language 68
  • 66.
    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 DSLs! 69
  • 67.
    Java vs. ScalaDSL public class HelloStage implements Runnable { object HelloJavaFX extends JavaFXApplication { def stage = new Stage { public void run() { title = "Hello Stage" Stage stage = new Stage(); width = 600 stage.setTitle("Hello Stage"); height = 450 stage.setWidth(600); scene = new Scene { stage.setHeight(450); fill = Color.LIGHTGREEN Scene scene = new Scene(); content = List(new Rectangle { 22 Lines scene.setFill(Color.LIGHTGREEN); Rectangle rect = new Rectangle(); 17 Lines x = 25 y = 40 rect.setX(25); width = 100 545 Characters rect.setY(40); rect.setWidth(100); 324 Characters height = 50 fill = Color.RED rect.setHeight(50); }) rect.setFill(Color.RED); } stage.add(rect); } stage.setScene(scene); } stage.setVisible(true); } public static void main(String[] args) { FX.start(new HelloStage()); } } 70
  • 68.
    object HelloJavaFX extendsJavaFXApplication { def stage = new Stage { title = "Hello Stage" width = 600 height = 450 scene = new Scene { fill = Color.LIGHTGREEN content = List(new Rectangle { x = 25 y = 40 width = 100 height = 50 fill = Color.RED }) } } } 71
  • 69.
    object HelloJavaFX extendsJavaFXApplication { def stage = new Stage { title = "Hello Stage" width = 600 height = 450 for JavaFX Base class applications scene = new Scene { fill = Color.LIGHTGREEN content = List(new Rectangle { x = 25 y = 40 width = 100 height = 50 fill = Color.RED }) } } } 72
  • 70.
    object HelloJavaFX extendsJavaFXApplication { def stage = new Stage { title = "Hello Stage" width = 600 height = 450 scene = new Scene { Declarative Stage fill = Color.LIGHTGREEN definition content = List(new Rectangle { x = 25 y = 40 width = 100 height = 50 fill = Color.RED }) } } } 73
  • 71.
    object HelloJavaFX extendsJavaFXApplication { def stage = new Stage { title = "Hello Stage" width = 600 Inline property height = 450 definitions scene = new Scene { fill = Color.LIGHTGREEN content = List(new Rectangle { x = 25 y = 40 width = 100 height = 50 fill = Color.RED }) } } } 74
  • 72.
    object HelloJavaFX extendsJavaFXApplication { def stage = new Stage { title = "Hello Stage" width = 600 height = 450 scene = new Scene { fill = Color.LIGHTGREEN content = List(new Rectangle { x = 25 y = 40 width = 100 height = 50 List Construction fill = Color.RED Syntax }) } } } 75
  • 73.
    Animation in Scala deftimeline = new Timeline { repeatCount = INDEFINITE autoReverse = true keyFrames = List( new KeyFrame(50) { values = List( new KeyValue(rect1, Rectangle.X -> 300), new KeyValue(rect2, Rectangle.Y -> 500), new KeyValue(rect2, Rectangle.Width -> 150) ) } ) } 76
  • 74.
    Animation in Scala deftimeline = new Timeline { repeatCount = INDEFINITE autoReverse = true Duration set by keyFrames = List( Constructor Parameter new KeyFrame(50) { values = List( new KeyValue(rect1, Rectangle.X -> 300), new KeyValue(rect2, Rectangle.Y -> 500), new KeyValue(rect2, Rectangle.WIDTH -> 150) ) } ) } 77
  • 75.
    Animation in Scala deftimeline = new Timeline { repeatCount = INDEFINITE autoReverse = true keyFrames = List( new KeyFrame(50) { values = List( new KeyValue(rect1, Rectangle.X -> 300), new KeyValue(rect2, Rectangle.Y -> 500), new KeyValue(rect2, Rectangle.WIDTH -> 150) ) } ) } Operator overloading for animation syntax 78
  • 76.
    Closures in Scala > Closures are also supported in Scala > And they are 100% type-safe rect.addChangedListener(Node.HOVER, (b, p, o) => { rect.fill = if (rect.hover) Color.GREEN else Color.RED }) 79
  • 77.
    Closures in Scala > Closures are also supported in Scala > And they are 100% type-safe rect.addChangedListener(Node.HOVER, (b, p, o) => { rect.fill = if (rect.hover) Color.GREEN else Color.RED }) Compact syntax (params) => {body} 80
  • 78.
    Conclusion > JavaFX as Java APIs is great > Usable in alternate languages > Over time improved support is possible  E.g. Groovy builders, Scala DSL Remember: This is a proof of concept only – you can not leave this session and do this today.
  • 79.
    Stephen Chin Jonathan Giles steve@widgetfx.org Jonathan.giles@oracle.com tweet: @steveonjava tweet: @jonathangiles 83