Hacking JavaFX with Groovy, Clojure,Scala, and Visage                       Stephen Chin                       Java Evange...
Meet the Presenter           Stephen Chin                                     >    Java Evangelist, Oracle                ...
Disclaimer:This is Code-Heavy
JavaFX 2.0 PlatformImmersive Application ExperienceLeverage your Java skills with modern JavaFXAPIs>    Cross-platform Ani...
JavaFX is Now Open Source!Part of the OpenJDK ProjectControls available now, additional codeadded incrementallyProject Pag...
And Will Run on Tablets!*>  iPad (iOS)>  Linux (Popular     Platform for     Tablets That     Runs Something     Similar t...
JavaFX With Java
Programming Languages>    JavaFX 2.0 APIs are now in Java     l    Pure Java APIs for all of JavaFX     l    Binding and...
JavaFX in Java>  JavaFX API uses an enhanced JavaBeans pattern>  Similar in feel to other UI toolkits (Swing, Pivot, etc.)...
Example Applicationpublic	  class	  HelloStage	  extends	  Application	  {	  	  	  	  @Override	  public	  void	  start(St...
Example Application Using Builderspublic	  class	  HelloStage	  extends	  Application	  {	  	  	  	  @Override	  public	  ...
Observable Properties>  Supports watching for changes to properties>  Implemented via anonymous inner classes>  Will take ...
Observable Pseudo-Properties	  final	  Rectangle	  rect	  =	  new	  Rectangle();	  rect.setX(40);	  rect.setY(40);	  rect....
Observable Pseudo-Properties	  final	  Rectangle	  rect	  =	  new	  Rectangle();	  rect.setX(40);	  rect.setY(40);	       ...
Observable Pseudo-Properties	  final	  Rectangle	  rect	  =	  new	  Rectangle();	  rect.setX(40);	                        ...
Observable Pseudo-Properties	  final	  Rectangle	  rect	  =	  new	  Rectangle();	  rect.setX(40);	  rect.setY(40);	  rect....
Observable Pseudo-Properties	  final	  Rectangle	  rect	  =	  new	  Rectangle();	  rect.setX(40);	  rect.setY(40);	  rect....
Binding>  Unquestionably the biggest JavaFX Script innovation>  Supported via a PropertyBinding class>  Lazy invocation fo...
Sequences in Java>    Replaced with an Observable List>    Public API is based on JavaFX sequences>    Internal code can u...
Vanishing Circles                    !                        20
Vanishing Circles in Javapublic	  class	  VanishingCircles	  extends	  Application	  {	  	  	  	  	  public	  static	  voi...
Application Skeletonpublic	  class	  VanishingCircles	  extends	  Application	  {	  	  	  public	  static	  void	  main(St...
Create the CirclesList<Circle>	  circles	  =	  new	  ArrayList<Circle>();	  for	  (int	  i	  =	  0;	  i	  <	  50;	  i++)	 ...
Setup Bindingcircle.strokeWidthProperty().bind(Bindings	  	  	  .when(circle.hoverProperty())	  	  	  .then(4)	  	  	  .ot...
Setup Event Listenerscircle.addEventHandler(MouseEvent.MOUSE_CLICKED,	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	 ...
Begin the AnimationTimeline	  moveCircles	  =	  new	  Timeline();	  for	  (Circle	  circle	  :	  circles)	  {	  	  	  KeyV...
JavaFX With Groovy
Features of Groovy>    Modern language     l    Closures     l    AST Transforms     l    Strongly typed dynamic langua...
Java vs. GroovyFX DSLpublic	  class	  VanishingCircles	  extends	  Application	  {	                                       ...
GroovyFX.start	  {	  primaryStage	  -­‐>	  	  	  def	  sg	  =	  new	  SceneGraphBuilder()	  	  	  def	  rand	  =	  new	  R...
GroovyFX.start	  {	  primaryStage	  -­‐>	  	  	  def	  sg	  =	  new	  SceneGraphBuilder()	  	  	  def	  rand	  =	  new	  R...
GroovyFX.start	  {	  primaryStage	  -­‐>	  	  	  def	  sg	  =	  new	  SceneGraphBuilder()	  	  	  def	  rand	  =	  new	  R...
GroovyFX.start	  {	  primaryStage	  -­‐>	  	  	  def	  sg	  =	  new	  SceneGraphBuilder()	  	  	  def	  rand	  =	  new	  R...
GroovyFX.start	  {	  primaryStage	  -­‐>	  	  	  def	  sg	  =	  new	  SceneGraphBuilder()	  	  	  def	  rand	  =	  new	  R...
GroovyFX.start	  {	  primaryStage	  -­‐>	  	  	  def	  sg	  =	  new	  SceneGraphBuilder()	  	  	  def	  rand	  =	  new	  R...
Animation in GroovyFXtimeline(cycleCount:	  Timeline.INDEFINITE,	  autoReverse:	  true)	  {	  	  	  circles.each	  {	  cir...
Animation in GroovyFXtimeline(cycleCount:	  Timeline.INDEFINITE,	  autoReverse:	  true)	  {	  	  	  circles.each	  {	  cir...
Animation in GroovyFXtimeline(cycleCount:	  Timeline.INDEFINITE,	  autoReverse:	  true)	  {	  	  	  circles.each	  {	  cir...
Animation in GroovyFXtimeline(cycleCount:	  Timeline.INDEFINITE,	  autoReverse:	  true)	  {	  	  	  circles.each	  {	  cir...
Event Listeners in GroovyFX>    Supported using the built-in Closure syntax>    Optional arguments for event objects onMou...
Event Listeners in GroovyFX>    Supported using the built-in Closure syntax>    Optional arguments for event objects onMou...
Event Listeners in GroovyFX>    Supported using the built-in Closure syntax>    Optional arguments for event objects      ...
But wait, there is more Grooviness…   43
Properties in Javapublic class Person {!       private StringProperty firstName;!       public void setFirstName(String va...
Properties in GroovyFXpublic class Person {!     @FXBindable String firstName; !     @FXBindable String lastName;!}!	     ...
Properties in GroovyFXpublic class Person {!     @FXBindable String firstName; !     @FXBindable String lastName = “Smith”...
Properties in GroovyFXpublic class Person {!   @FXBindable String firstName; !   @FXBindable String lastName = “Smith”;!}!...
Properties in GroovyFXpublic class Person {!   @FXBindable String firstName; !   @FXBindable String lastName = “Smith”;!}!...
Binding in GroovyFX@FXBindable	  class	  Time	  {	  	  	  Integer	  hours	  	  	  Integer	  minutes	  	  	  Integer	  seco...
TableView in JavaObservableList<Person> items = ...!TableView<Person> tableView = new TableView<Person>(items);!  !TableCo...
TableView in GroovyFXdef dateFormat = new SimpleDateFormat("yyyy-MM-dd");!!tableView(items: persons) {!   tableColumn(prop...
Layout in JavaTextField urlField = new TextField(“http://www.google.com”);!HBox.setHgrow(urlField, Priority.ALWAYS);!!HBox...
Layout in GroovyFXsg.stage(title: "GroovyFX WebView Demo", show: true) {  scene(fill: groovyblue, width: 1024, height: 800...
Layout in GroovyFX                     54
Layout in GroovyFXgridPane(hgap: 5, vgap: 10, padding: 25) {!   columnConstraints(minWidth: 50, halignment: "right")!   co...
Layout in GroovyFX                     56
GroovyFX Supports…                     57
GroovyFX Supports…                     58
JavaFX With Clojure        Artwork by Augusto Sellhorn   http://sellmic.com/                                              ...
A Little About          Clojure>    Started in 2007 by Rich Hickey>    Functional Programming Language>    Derived from LI...
Clojure Syntax in One Slide                    Symbols                                               Collections          ...
Clojure GUI Example(defn	  javafxapp	  []	  	  	  (let	  [stage	  (Stage.	  "JavaFX	  Stage")	  	  	  	  	  	  	  	  	  sc...
Refined Clojure GUI Example(defn	  javafxapp	  []	  	  	  (doto	  (Stage.	  "JavaFX	  Stage")	  	  	  	  	  (.setWidth	  6...
Refined Clojure GUI Example(defn	  javafxapp	  []	  	  	  (doto	  (Stage.	  "JavaFX	  Stage")	  	  	  	  	  (.setWidth	  6...
Closures in Clojure>     Inner classes can be created using proxy	       (.addListener	  hoverProperty	       	  	  (proxy...
Closures in Clojure>     Inner classes can be created using proxy	                                                        ...
JavaFX With Scala                    67
What is Scala       2001                               2006       •  Scala Started                   •  Scala v2.0        ...
Why Scala?>    Shares many language features with JavaFX Script that make GUI     programming easier:     l    Static Typ...
Java vs. Scala DSLpublic	  class	  VanishingCircles	  extends	  Application	  {	                                          ...
object	  VanishingCircles	  extends	  JFXApp	  {	  	  	  stage	  =	  new	  Stage	  {	  	  	  	  	  title	  =	  "Disappeari...
object	  VanishingCircles	  extends	  JFXApp	  {	  	  	  stage	  =	  new	  Stage	  {	  	  	  	  	  title	  =	  "Disappeari...
object	  VanishingCircles	  extends	  JFXApp	  {	  	  	  stage	  =	  new	  Stage	  {	  	  	  	  	  title	  =	  "Disappeari...
object	  VanishingCircles	  extends	  JFXApp	  {	  	  	  stage	  =	  new	  Stage	  {	  	  	  	  	  title	  =	  "Disappeari...
object	  VanishingCircles	  extends	  JFXApp	  {	  	  	  stage	  =	  new	  Stage	  {	  	  	  	  	  title	  =	  "Disappeari...
Binding in ScalaInfix Addition/Subtraction/Multiplication/Division:height	  <==	  rect1.height	  +	  rect2.height	  	  Agg...
Animation in Scalaval	  timeline	  =	  new	  Timeline	  {	  	  	  cycleCount	  =	  INDEFINITE	  	  	  autoReverse	  =	  tr...
JavaFX Script-like animationAnimation in Scala                        syntax: at (duration) {keyframes}val	  timeline	  =	...
Animation in Scalaval	  timeline	  =	  new	  Timeline	  {	  	  	  cycleCount	  =	  INDEFINITE	  	  	  autoReverse	  =	  tr...
Animation in Scalaval	  timeline	  =	  new	  Timeline	  {	  	  	  cycleCount	  =	  INDEFINITE	  	  	  autoReverse	  =	  tr...
Event Listeners in Scala>    Supported using the built-in Closure syntax>    Arguments for event objects>    100% type-saf...
Event Listeners in Scala>    Supported using the built-in Closure syntax>    Arguments for event objects>    100% type-saf...
Event Listeners in Scala>    Supported using the built-in Closure syntax>    Arguments for event objects                  ...
TableView in ScalaFXdef dateFormat = new SimpleDateFormat("yyyy-MM-dd")!new TableView[Speaker](persons) {!  columns = Seq(...
JavaFX With Visage                     85
About Project Visage>    “Visage is a domain specific language (DSL) designed for the     express purpose of writing user ...
Java vs. Visage DSLpublic	  class	  VanishingCircles	  extends	  Application	  {	                                         ...
How about JavaFX on… VisageStage	  {	  	  	  title:	  "Vanishing	  Circles"	  	  	  scene:	  Scene	  {	  	  	  	  	  width...
How about JavaFX on… VisageStage	  {	  	  	  title:	  "Vanishing	  Circles"	  	  	  scene:	  Scene	  {	  	  	  	  	  width...
How about JavaFX on… VisageStage	  {	  	  	  title:	  "Vanishing	  Circles"	  	  	  Scene	  {	  	  	  	  	  width:	  800	 ...
Visage is JavaFX Script++>    Default Parameters>    New Literal Syntax For:     l    Angles – 35deg,	  4rad,	  1turn	   ...
Visage and JavaFX 2.0 are made for each other…>    Enhanced Binding     l    Retains lazy evaluation properties with addi...
Other JVM Languages to Try>    JRuby     l    Faithful to Ruby language with the power of the JVM>    Gosu     l    Up a...
Conclusion>  You can write JavaFX applications in pure Java>  JavaFX is also usable in alternate languages>  You can get i...
Stephen Chin                                                            stephen.chin@oracle.com                           ...
Upcoming SlideShare
Loading in …5
×

Hacking JavaFX with Groovy, Clojure, Scala, and Visage: Stephen Chin

766 views
733 views

Published on

JavaFX 2 is the next version of a revolutionary rich client platform for developing immersive desktop applications. One of the new features in JavaFX 2 is a set of pure Java APIs that can be used from any JVM language, opening up tremendous possibilities. This presentation demonstrates the potential of using JavaFX 2 together with alternative languages such as Groovy, Clojure, and Scala. It also will showcase the successor to JavaFX Script, Visage, a DSL with features specifically targeted at helping create clean UIs.

Published in: Technology, Education
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
766
On SlideShare
0
From Embeds
0
Number of Embeds
10
Actions
Shares
0
Downloads
63
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

Hacking JavaFX with Groovy, Clojure, Scala, and Visage: Stephen Chin

  1. 1. Hacking JavaFX with Groovy, Clojure,Scala, and Visage Stephen Chin Java Evangelist, Oracle stephen.chin@oracle.com tweet: @steveonjava
  2. 2. Meet the Presenter Stephen Chin >  Java Evangelist, Oracle >  Author, Pro JavaFX Platform 2 Family Man >  Open Source Hacker l  JFXtras l  ScalaFX Motorcyclist l  Visage >  User Group Co-Leader l  Silicon Valley JavaFX User Group l  Streamed Live!
  3. 3. Disclaimer:This is Code-Heavy
  4. 4. JavaFX 2.0 PlatformImmersive Application ExperienceLeverage your Java skills with modern JavaFXAPIs>  Cross-platform Animation, Video, Charting>  Integrate Java, JavaScript, and HTML5 in the same application>  New graphics stack takes advantage of hardware acceleration for 2D and 3D applications>  Use your favorite IDE: NetBeans, Eclipse, IntelliJ, etc.
  5. 5. JavaFX is Now Open Source!Part of the OpenJDK ProjectControls available now, additional codeadded incrementallyProject Page:>  http://openjdk.java.net/projects/openjfx/ 5
  6. 6. And Will Run on Tablets!*>  iPad (iOS)>  Linux (Popular Platform for Tablets That Runs Something Similar to Java) *No Release Timeline Announced Yet 6
  7. 7. JavaFX With Java
  8. 8. Programming Languages>  JavaFX 2.0 APIs are now in Java l  Pure Java APIs for all of JavaFX l  Binding and Sequences exposed as Java APIs l  FXML Markup for tooling>  Embrace all JVM languages l  Groovy, Scala, Clojure, JRuby l  Fantom, Mira, Gosu, Jython, etc.>  JavaFX Script is no longer supported by Oracle l  Existing JavaFX Script based applications will continue to run l  Visage is the open-source successor to the JavaFX Script language
  9. 9. JavaFX in Java>  JavaFX API uses an enhanced JavaBeans pattern>  Similar in feel to other UI toolkits (Swing, Pivot, etc.)>  Uses builder pattern to minimize boilerplate
  10. 10. Example Applicationpublic  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)  {          Application.launch(args);      }  }  
  11. 11. Example Application Using Builderspublic  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)  {          Application.launch(args);      }  }  
  12. 12. Observable Properties>  Supports watching for changes to properties>  Implemented via anonymous inner classes>  Will take advantage of closures in the future
  13. 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>()  {                  });  
  14. 14. Observable Pseudo-Properties  final  Rectangle  rect  =  new  Rectangle();  rect.setX(40);  rect.setY(40);   The property we want to watchrect.setWidth(100);  rect.setHeight(200);      rect.hoverProperty().addListener(new  ChangeListener<Boolean>()  {                });  
  15. 15. Observable Pseudo-Properties  final  Rectangle  rect  =  new  Rectangle();  rect.setX(40);   Only one listener used with generics torect.setY(40);   specify the data typerect.setWidth(100);  rect.setHeight(200);      rect.hoverProperty().addListener(new  ChangeListener<Boolean>()  {                    });  
  16. 16. 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()
  17. 17. 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);      }  });  
  18. 18. Binding>  Unquestionably the biggest JavaFX Script innovation>  Supported via a PropertyBinding class>  Lazy invocation for high performance>  Static construction syntax for simple cases l  e.g.: bind(<property>), bindBiDirectional(<property>)
  19. 19. 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
  20. 20. Vanishing Circles ! 20
  21. 21. Vanishing Circles in Javapublic  class  VanishingCircles  extends  Application  {          public  static  void  main(String[]  args)  {          Application.launch(args);      }            @Override      public  void  start(Stage  primaryStage)  {          primaryStage.setTitle("Vanishing  Circles");          Group  root  =  new  Group();          Scene  scene  =  new  Scene(root,  800,  600,  Color.BLACK);          List<Circle>  circles  =  new  ArrayList<Circle>();          for  (int  i  =  0;  i  <  50;  i++)  {   40 Lines            final  Circle  circle  =  new  Circle(150);              circle.setCenterX(Math.random()  *  800);              circle.setCenterY(Math.random()  *  600);              circle.setFill(new  Color(Math.random(),  Math.random(),  Math.random(),  .2));   1299 Characters            circle.setEffect(new  BoxBlur(10,  10,  3));              circle.addEventHandler(MouseEvent.MOUSE_CLICKED,  new  EventHandler<MouseEvent>()  {                  public  void  handle(MouseEvent  t)  {                      KeyValue  collapse  =  new  KeyValue(circle.radiusProperty(),  0);                      new  Timeline(new  KeyFrame(Duration.seconds(3),  collapse)).play();                  }              });              circle.setStroke(Color.WHITE);              circle.strokeWidthProperty().bind(Bindings.when(circle.hoverProperty())                  .then(4)                  .otherwise(0));              circles.add(circle);          }          root.getChildren().addAll(circles);          primaryStage.setScene(scene);          primaryStage.show();                    Timeline  moveCircles  =  new  Timeline();          for  (Circle  circle  :  circles)  {              KeyValue  moveX  =  new  KeyValue(circle.centerXProperty(),  Math.random()  *  800);              KeyValue  moveY  =  new  KeyValue(circle.centerYProperty(),  Math.random()  *  600);              moveCircles.getKeyFrames().add(new  KeyFrame(Duration.seconds(40),  moveX,  moveY));          }          moveCircles.play();      }  }   21
  22. 22. Application Skeletonpublic  class  VanishingCircles  extends  Application  {      public  static  void  main(String[]  args)  {          Application.launch(args);      }      @Override      public  void  start(Stage  primaryStage)  {          primaryStage.setTitle("Vanishing  Circles");          Group  root  =  new  Group();          Scene  scene  =  new  Scene(root,  800,  600,  Color.BLACK);          [create  the  circles…]          root.getChildren().addAll(circles);          primaryStage.setScene(scene);          primaryStage.show();          [begin  the  animation…]      }  }  
  23. 23. Create the CirclesList<Circle>  circles  =  new  ArrayList<Circle>();  for  (int  i  =  0;  i  <  50;  i++)  {      final  Circle  circle  =  new  Circle(150);      circle.setCenterX(Math.random()  *  800);      circle.setCenterY(Math.random()  *  600);      circle.setFill(new  Color(Math.random(),  Math.random(),                                                        Math.random(),  .2));      circle.setEffect(new  BoxBlur(10,  10,  3));      circle.setStroke(Color.WHITE);      [setup  binding…]      [setup  event  listeners…]      circles.add(circle);  }   23
  24. 24. Setup Bindingcircle.strokeWidthProperty().bind(Bindings      .when(circle.hoverProperty())      .then(4)      .otherwise(0)  );   24
  25. 25. Setup Event Listenerscircle.addEventHandler(MouseEvent.MOUSE_CLICKED,                                                  new  EventHandler<MouseEvent>()  {      public  void  handle(MouseEvent  t)  {          KeyValue  collapse  =  new  KeyValue(circle.radiusProperty(),  0);          new  Timeline(new  KeyFrame(Duration.seconds(3),                                                                collapse)).play();      }  });   25
  26. 26. Begin the AnimationTimeline  moveCircles  =  new  Timeline();  for  (Circle  circle  :  circles)  {      KeyValue  moveX  =  new  KeyValue(circle.centerXProperty(),                                                                    Math.random()  *  800);      KeyValue  moveY  =  new  KeyValue(circle.centerYProperty(),                                                                    Math.random()  *  600);      moveCircles.getKeyFrames().add(new  KeyFrame(Duration.seconds(40),                                                                                              moveX,  moveY));  }  moveCircles.play();   26
  27. 27. JavaFX With Groovy
  28. 28. Features of Groovy>  Modern language l  Closures l  AST Transforms l  Strongly typed dynamic language>  Tight integration with Java l  Very easy to port from Java to Groovy>  Declarative syntax with GroovyFX Builders l  Familiar to Groovy and JavaFX Script developers
  29. 29. Java vs. GroovyFX DSLpublic  class  VanishingCircles  extends  Application  {   GroovyFX.start  {  primaryStage  -­‐>        def  sg  =  new  SceneGraphBuilder()      public  static  void  main(String[]  args)  {      def  rand  =  new  Random().&nextInt          Application.launch(args);      def  circles  =  []      }              sg.stage(title:  Vanishing  Circles,  show:  true)  {      @Override          scene(fill:  black,  width:  800,  height:  600)  {      public  void  start(Stage  primaryStage)  {              50.times  {          primaryStage.setTitle("Vanishing  Circles");                  circles  <<  circle(centerX:  rand(800),  centerY:  rand(600),  radius:  150,  stroke:  white,          Group  root  =  new  Group();                                  strokeWidth:  bind(hover,  converter:  {val  -­‐>  val  ?  4  :  0}))  {          Scene  scene  =  new  Scene(root,  800,  600,  Color.BLACK);                      fill  rgb(rand(255),  rand(255),  rand(255),  0.2)          List<Circle>  circles  =  new  ArrayList<Circle>();                      effect  boxBlur(width:  10,  height:  10,  iterations:  3)          for  (int  i  =  0;  i  <  50;  i++)  {                      onMouseClicked  {  e  -­‐>   40 Lines 29 Lines            final  Circle  circle  =  new  Circle(150);                          timeline  {              circle.setCenterX(Math.random()  *  800);                              at(3.s)  {  change  e.source.radiusProperty()  to  0  }              circle.setCenterY(Math.random()  *  600);                          }.play()              circle.setFill(new  Color(Math.random(),  Math.random(),  Math.random(),  .2));                      }   671 Characters            circle.setEffect(new  BoxBlur(10,  10,  3));                  }   1299 Characters            circle.addEventHandler(MouseEvent.MOUSE_CLICKED,  new  EventHandler<MouseEvent>()  {                  public  void  handle(MouseEvent  t)  {                      KeyValue  collapse  =  new  KeyValue(circle.radiusProperty(),  0);                      new  Timeline(new  KeyFrame(Duration.seconds(3),  collapse)).play();              }          }            timeline(cycleCount:  Timeline.INDEFINITE,  autoReverse:  true)  {                  }              circles.each  {  circle  -­‐>              });                  at  (40.s)  {              circle.setStroke(Color.WHITE);                      change  circle.centerXProperty()  to  rand(800)              circle.strokeWidthProperty().bind(Bindings.when(circle.hoverProperty())                      change  circle.centerYProperty()  to  rand(600)                  .then(4)                  }                  .otherwise(0));              }              circles.add(circle);          }.play()          }      }          root.getChildren().addAll(circles);   }          primaryStage.setScene(scene);          primaryStage.show();                    Timeline  moveCircles  =  new  Timeline();          for  (Circle  circle  :  circles)  {              KeyValue  moveX  =  new  KeyValue(circle.centerXProperty(),  Math.random()  *  800);              KeyValue  moveY  =  new  KeyValue(circle.centerYProperty(),  Math.random()  *  600);              moveCircles.getKeyFrames().add(new  KeyFrame(Duration.seconds(40),  moveX,  moveY));          }          moveCircles.play();      }  }   29
  30. 30. GroovyFX.start  {  primaryStage  -­‐>      def  sg  =  new  SceneGraphBuilder()      def  rand  =  new  Random().&nextInt      def  circles  =  []        sg.stage(title:  Vanishing  Circles,  show:  true)  {          scene(fill:  black,  width:  800,  height:  600)  {              50.times  {                  circles  <<  circle(centerX:  rand(800),  centerY:  rand(600),                          radius:  150,  stroke:  white,                          strokeWidth:  bind(hover,  converter:  {val  -­‐>  val  ?  4  :  0}))  {                      fill  rgb(rand(255),  rand(255),  rand(255),  0.2)                      effect  boxBlur(width:  10,  height:  10,  iterations:  3)                  }              }          }      }  }   30
  31. 31. GroovyFX.start  {  primaryStage  -­‐>      def  sg  =  new  SceneGraphBuilder()      def  rand  =  new  Random().&nextInt      def  circles  =  []        sg.stage(title:  Vanishing  Circles,  show:  true)  {   Builder for GroovyFX scene graphs        scene(fill:  black,  width:  800,  height:  600)  {              50.times  {                  circles  <<  circle(centerX:  rand(800),  centerY:  rand(600),                          radius:  150,  stroke:  white,                          strokeWidth:  bind(hover,  converter:  {val  -­‐>  val  ?  4  :  0}))  {                      fill  rgb(rand(255),  rand(255),  rand(255),  0.2)                      effect  boxBlur(width:  10,  height:  10,  iterations:  3)                  }              }          }      }  }   31
  32. 32. GroovyFX.start  {  primaryStage  -­‐>      def  sg  =  new  SceneGraphBuilder()      def  rand  =  new  Random().&nextInt      def  circles  =  []        sg.stage(title:  Vanishing  Circles,  show:  true)  {          scene(fill:  black,  width:  800,  height:  600)  {              50.times  {                  circles  <<  circle(centerX:  rand(800),  centerY:  rand(600),                          radius:  150,  stroke:  white,   Declarative Stage definition                        strokeWidth:  bind(hover,  converter:  {val  -­‐>  val  ?  4  :  0}))  {                      fill  rgb(rand(255),  rand(255),  rand(255),  0.2)                      effect  boxBlur(width:  10,  height:  10,  iterations:  3)                  }              }          }      }  }   32
  33. 33. GroovyFX.start  {  primaryStage  -­‐>      def  sg  =  new  SceneGraphBuilder()      def  rand  =  new  Random().&nextInt      def  circles  =  []     Inline property definitions    sg.stage(title:  Vanishing  Circles,  show:  true)  {          scene(fill:  black,  width:  800,  height:  600)  {              50.times  {                  circles  <<  circle(centerX:  rand(800),  centerY:  rand(600),                          radius:  150,  stroke:  white,                          strokeWidth:  bind(hover,  converter:  {val  -­‐>  val  ?  4  :  0}))  {                      fill  rgb(rand(255),  rand(255),  rand(255),  0.2)                      effect  boxBlur(width:  10,  height:  10,  iterations:  3)                  }              }          }      }  }   33
  34. 34. GroovyFX.start  {  primaryStage  -­‐>      def  sg  =  new  SceneGraphBuilder()      def  rand  =  new  Random().&nextInt      def  circles  =  []        sg.stage(title:  Vanishing  Circles,  show:  true)  {          scene(fill:  black,  width:  800,  height:  600)  {   Bind to properties            50.times  {                  circles  <<  circle(centerX:  rand(800),  centerY:  rand(600),                          radius:  150,  stroke:  white,                          strokeWidth:  bind(hover,  converter:  {val  -­‐>  val  ?  4  :  0}))  {                      fill  rgb(rand(255),  rand(255),  rand(255),  0.2)                      effect  boxBlur(width:  10,  height:  10,  iterations:  3)                  }              }          }      }  }   34
  35. 35. GroovyFX.start  {  primaryStage  -­‐>      def  sg  =  new  SceneGraphBuilder()      def  rand  =  new  Random().&nextInt      def  circles  =  []        sg.stage(title:  Vanishing  Circles,  show:  true)  {   Creation Via Loop Sequence        scene(fill:  black,  width:  800,  height:  600)  {              50.times  {                  circles  <<  circle(centerX:  rand(800),  centerY:  rand(600),                          radius:  150,  stroke:  white,                          strokeWidth:  bind(hover,  converter:  {val  -­‐>  val  ?  4  :  0}))  {                      fill  rgb(rand(255),  rand(255),  rand(255),  0.2)                      effect  boxBlur(width:  10,  height:  10,  iterations:  3)                  }              }          }      }  }   35
  36. 36. Animation in GroovyFXtimeline(cycleCount:  Timeline.INDEFINITE,  autoReverse:  true)  {      circles.each  {  circle  -­‐>          at  (40.s)  {              change  circle.centerXProperty()  to  rand(800)              change  circle.centerYProperty()  to  rand(600)          }      }  }.play()   36
  37. 37. Animation in GroovyFXtimeline(cycleCount:  Timeline.INDEFINITE,  autoReverse:  true)  {      circles.each  {  circle  -­‐>          at  (40.s)  {              change  circle.centerXProperty()  to  rand(800)              change  circle.centerYProperty()  to  rand(600)          }      }   Easy animation syntax:}.play()   at (duration) {keyframes} 37
  38. 38. Animation in GroovyFXtimeline(cycleCount:  Timeline.INDEFINITE,  autoReverse:  true)  {      circles.each  {  circle  -­‐>          at  (40.s)  {              change  circle.centerXProperty()  to  rand(800)              change  circle.centerYProperty()  to  rand(600)          }      }  }.play()   Key frame DSL 38
  39. 39. Animation in GroovyFXtimeline(cycleCount:  Timeline.INDEFINITE,  autoReverse:  true)  {      circles.each  {  circle  -­‐>          at  (40.s)  {              change  circle.centerXProperty()  to  rand(800)  tween  ease_both              change  circle.centerYProperty()  to  rand(600)  tween  linear          }      }  }.play()   Optional easing 39
  40. 40. Event Listeners in GroovyFX>  Supported using the built-in Closure syntax>  Optional arguments for event objects onMouseClicked  {  e  -­‐>      timeline  {          at(3.s)  {  change  e.source.radiusProperty()  to  0  }      }.play()   }   40
  41. 41. Event Listeners in GroovyFX>  Supported using the built-in Closure syntax>  Optional arguments for event objects onMouseClicked  {  MouseEvent  e  -­‐>      timeline  {          at(3.s)  {  change  e.source.radiusProperty()  to  0  }      }.play()   }   Compact syntax {body} 41
  42. 42. Event Listeners in GroovyFX>  Supported using the built-in Closure syntax>  Optional arguments for event objects Optional event parameter {event -> body} onMouseClicked  {  MouseEvent  e  -­‐>      timeline  {          at(3.s)  {  change  e.source.radiusProperty()  to  0  }      }.play()   }   42
  43. 43. But wait, there is more Grooviness… 43
  44. 44. Properties in Javapublic class Person {! private StringProperty firstName;! public void setFirstName(String val) { firstNameProperty().set(val); }! public String getFirstName() { return firstNameProperty().get(); }! public StringProperty firstNameProperty() { ! if (firstName == null) ! firstName = new SimpleStringProperty(this, "firstName");! return firstName; ! }! ! private StringProperty lastName;! public void setLastName(String value) { lastNameProperty().set(value); }! public String getLastName() { return lastNameProperty().get(); }! public StringProperty lastNameProperty() { ! if (lastName == null) // etc.! } !}!   44
  45. 45. Properties in GroovyFXpublic class Person {! @FXBindable String firstName; ! @FXBindable String lastName;!}!   45
  46. 46. Properties in GroovyFXpublic class Person {! @FXBindable String firstName; ! @FXBindable String lastName = “Smith”;!}!   Optional initializers 46
  47. 47. Properties in GroovyFXpublic class Person {! @FXBindable String firstName; ! @FXBindable String lastName = “Smith”;!}!! Get and set valuesdef p = new Person()!def last = p.lastName!p.firstName = “Agent”!! 47
  48. 48. Properties in GroovyFXpublic class Person {! @FXBindable String firstName; ! @FXBindable String lastName = “Smith”;!}!!def p = new Person()!def last = p.lastName! Access underlying property forp.firstName = “Agent”! binding!textField(text: bind(p.lastNameProperty()))!! 48
  49. 49. 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)      }  }   49
  50. 50. TableView in JavaObservableList<Person> items = ...!TableView<Person> tableView = new TableView<Person>(items);! !TableColumn<Person,String> firstNameCol = ! new TableColumn<Person,String>("First Name");!!firstNameCol.setCellValueFactory(! new Callback<CellDataFeatures<Person, String>, ! ObservableValue<String>>() {! public ObservableValue<String> call(CellDataFeatures<Person, String> p) ! {! return p.getValue().firstNameProperty();! }!});! !tableView.getColumns().add(firstNameCol);! 50
  51. 51. TableView in GroovyFXdef dateFormat = new SimpleDateFormat("yyyy-MM-dd");!!tableView(items: persons) {! tableColumn(property: "name", text: "Name", prefWidth: 150)! tableColumn(property: "age", text: "Age", prefWidth: 50)! tableColumn(property: "gender", text: "Gender", prefWidth: 150)! tableColumn(property: "dob", text: "Birth", prefWidth: 150, ! type: Date,! converter: { from -> return dateFormat.format(from) })!}! 51
  52. 52. Layout in JavaTextField urlField = new TextField(“http://www.google.com”);!HBox.setHgrow(urlField, Priority.ALWAYS);!!HBox hbox = new HBox();!hbox.getChildren().add(urlField);!!WebView webView = new WebView();!VBox.setVgrow(webView, Priority.ALWAYS);!!VBox vbox = new VBox();!vbox.getChildren().addAll(hbox, webView);! 52
  53. 53. Layout in GroovyFXsg.stage(title: "GroovyFX WebView Demo", show: true) { scene(fill: groovyblue, width: 1024, height: 800) { vbox { hbox(padding: 10, spacing: 5) { textField(“http://www.yahoo.com”, hgrow: "always") button("Go”) } webView(vgrow: "always") } }} 53
  54. 54. Layout in GroovyFX 54
  55. 55. Layout in GroovyFXgridPane(hgap: 5, vgap: 10, padding: 25) {! columnConstraints(minWidth: 50, halignment: "right")! columnConstraints(prefWidth: 250)! label("Send Us Your Feedback", font: "24pt sanserif", ! row: 0, columnSpan: GridPane.REMAINING, halignment: "center",! margin: [0, 0, 10])!! label("Name: ", row: 1, column: 0)! textField(promptText: "Your name", row: 1, column: 1, hgrow: always)!! label("Email:", row: 2, column: 0)! textField(promptText: "Your email", row: 2, column: 1, hgrow: always)!! label("Message:", row: 3, column: 0, valignment: "baseline")! textArea(row: 3, column: 1, hgrow: "always", vgrow: "always")!! button("Send Message", row: 4, column: 1, halignment: "right")!}! 55
  56. 56. Layout in GroovyFX 56
  57. 57. GroovyFX Supports… 57
  58. 58. GroovyFX Supports… 58
  59. 59. JavaFX With Clojure Artwork by Augusto Sellhorn http://sellmic.com/ 59
  60. 60. 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! 60
  61. 61. 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) 61
  62. 62. 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)   62
  63. 63. 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)   63
  64. 64. Refined Clojure GUI Example(defn  javafxapp  []      (doto  (Stage.  "JavaFX  Stage")          (.setWidth  600)   Doto allows nested data        (.setHeight  450)          (.setScene  (doto  (Scene.)   structures            (.setFill  Color/LIGHTGREEN)              (.setContent  (list  (doto  (Rectangle.)                  (.setX  25)                  (.setY  40)                  (.setWidth  100)                  (.setHeight  50)                  (.setFill  Color/RED))))))          (.setVisible  true)))  (javafxapp)   64
  65. 65. Closures in Clojure>  Inner classes can be created using proxy   (.addListener  hoverProperty      (proxy  [ChangeListener]  []          (handle  [p,  o,  v]              (.setFill  rect                  (if  (.isHover  rect)  Color/GREEN  Color/RED)))))   65
  66. 66. Closures in Clojure>  Inner classes can be created using proxy   Proxy form: (proxy  [class]  [args]  fs+)   f => (name  [params*]  body)   (.addListener  hoverProperty      (proxy  [ChangeListener]  []          (handle  [p,  o,  v]              (.setFill  rect                  (if  (.isHover  rect)  Color/GREEN  Color/RED)))))   66
  67. 67. JavaFX With Scala 67
  68. 68. What is Scala 2001 2006 •  Scala Started •  Scala v2.0 2003/2004 2011 •  Scala v1.0 •  Scala 2.9.2 (latest)>  Started in 2001 by Martin Odersky>  Compiles to Java bytecodes>  Pure object-oriented language>  Also a functional programming language 68
  69. 69. Why Scala?>  Shares many language features with JavaFX Script that make GUI programming easier: l  Static Type Checking – Catch your errors at compile time l  Closures – Wrap behavior and pass it by reference l  Declarative – Express the UI by describing what it should look like>  Scala also supports Type Safe DSLs! l  Implicit Conversions – type safe class extension l  Operator Overloading – with standard precedence rules l  DelayedInit / @specialized – advanced language features 69
  70. 70. Java vs. Scala DSLpublic  class  VanishingCircles  extends  Application  {   object  VanishingCircles  extends  JFXApp  {        var  circles:  Seq[Circle]  =  null      public  static  void  main(String[]  args)  {      stage  =  new  Stage  {          Application.launch(args);          title  =  "Vanishing  Circles"      }          width  =  800                height  =  600      @Override          scene  =  new  Scene  {      public  void  start(Stage  primaryStage)  {              fill  =  BLACK          primaryStage.setTitle("Vanishing  Circles");              circles  =  for  (i  <-­‐  0  until  50)  yield  new  Circle  {          Group  root  =  new  Group();                  centerX  =  random  *  800          Scene  scene  =  new  Scene(root,  800,  600,  Color.BLACK);                  centerY  =  random  *  600          List<Circle>  circles  =  new  ArrayList<Circle>();                  radius  =  150          for  (int  i  =  0;  i  <  50;  i++)  {                  fill  =  color(random,  random,  random,  .2)   40 Lines 33 Lines            final  Circle  circle  =  new  Circle(150);                  effect  =  new  BoxBlur(10,  10,  3)              circle.setCenterX(Math.random()  *  800);                  strokeWidth  <==  when  (hover)  then  4  otherwise  0              circle.setCenterY(Math.random()  *  600);                  stroke  =  WHITE              circle.setFill(new  Color(Math.random(),  Math.random(),  Math.random(),  .2));                  onMouseClicked  =  {              circle.setEffect(new  BoxBlur(10,  10,  3));                      Timeline(at  (3  s)  {radius  -­‐>  0}).play()   1299 Characters            circle.addEventHandler(MouseEvent.MOUSE_CLICKED,  new  EventHandler<MouseEvent>()  {                  public  void  handle(MouseEvent  t)  {                      KeyValue  collapse  =  new  KeyValue(circle.radiusProperty(),  0);                      new  Timeline(new  KeyFrame(Duration.seconds(3),  collapse)).play();              }   591 Characters                }              content  =  circles          }                  }      }              });                circle.setStroke(Color.WHITE);      new  Timeline  {              circle.strokeWidthProperty().bind(Bindings.when(circle.hoverProperty())          cycleCount  =  INDEFINITE                  .then(4)          autoReverse  =  true                  .otherwise(0));          keyFrames  =  for  (circle  <-­‐  circles)  yield  at  (40  s)  {              circles.add(circle);              Set(          }                  circle.centerX  -­‐>  random  *  stage.width,          root.getChildren().addAll(circles);                  circle.centerY  -­‐>  random  *  stage.height          primaryStage.setScene(scene);              )          primaryStage.show();          }                }.play();          Timeline  moveCircles  =  new  Timeline();   }          for  (Circle  circle  :  circles)  {              KeyValue  moveX  =  new  KeyValue(circle.centerXProperty(),  Math.random()  *  800);              KeyValue  moveY  =  new  KeyValue(circle.centerYProperty(),  Math.random()  *  600);              moveCircles.getKeyFrames().add(new  KeyFrame(Duration.seconds(40),  moveX,  moveY));          }          moveCircles.play();      }  }   70
  71. 71. object  VanishingCircles  extends  JFXApp  {      stage  =  new  Stage  {          title  =  "Disappearing  Circles"          width  =  800          height  =  600          scene  =  new  Scene  {              fill  =  BLACK              children  =  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)              }          }      }  }   71
  72. 72. object  VanishingCircles  extends  JFXApp  {      stage  =  new  Stage  {          title  =  "Disappearing  Circles"          width  =  800          height  =  600   for JavaFX applications Base class        scene  =  new  Scene  {              fill  =  BLACK              children  =  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)              }          }      }  }   72
  73. 73. object  VanishingCircles  extends  JFXApp  {      stage  =  new  Stage  {          title  =  "Disappearing  Circles"          width  =  800          height  =  600          scene  =  new  Scene  {   Declarative Stage definition            fill  =  BLACK              children  =  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)              }          }      }  }   73
  74. 74. object  VanishingCircles  extends  JFXApp  {      stage  =  new  Stage  {          title  =  "Disappearing  Circles"          width  =  800   Inline property definitions        height  =  600          scene  =  new  Scene  {              fill  =  BLACK              children  =  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)              }          }      }  }   74
  75. 75. object  VanishingCircles  extends  JFXApp  {      stage  =  new  Stage  {          title  =  "Disappearing  Circles"          width  =  800          height  =  600   Sequence Creation Via Loop        scene  =  new  Scene  {              fill  =  BLACK              children  =  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)              }          }      }  }   75
  76. 76. Binding in ScalaInfix 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"   76
  77. 77. Animation in Scalaval  timeline  =  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();   77
  78. 78. JavaFX Script-like animationAnimation in Scala syntax: at (duration) {keyframes}val  timeline  =  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();   78
  79. 79. Animation in Scalaval  timeline  =  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          )      }  }   Operator overloading for animationtimeline.play();   syntax 79
  80. 80. Animation in Scalaval  timeline  =  new  Timeline  {      cycleCount  =  INDEFINITE      autoReverse  =  true      keyFrames  =  for  (circle  <-­‐  circles)  yield  at  (40  s)  {          Set(    circle.centerX  -­‐>  random  *  stage.width  tween  EASE_BOTH,    circle.centerY  -­‐>  random  *  stage.height  tween  EASE_IN          )      }  }  timeline.play();   Optional tween syntax 80
  81. 81. Event Listeners in Scala>  Supported using the built-in Closure syntax>  Arguments for event objects>  100% type-safe onMouseClicked  =  {  (e:  MouseEvent)  =>      Timeline(at(3  s){radius-­‐>0}).play()   }   81
  82. 82. Event Listeners in Scala>  Supported using the built-in Closure syntax>  Arguments for event objects>  100% type-safe onMouseClicked  =  {  (e:  MouseEvent)  =>      Timeline(at(3  s){radius-­‐>0}).play()   }   Compact syntax {body} 82
  83. 83. Event Listeners in Scala>  Supported using the built-in Closure syntax>  Arguments for event objects Event parameter>  100% type-safe {(event) => body} onMouseClicked  =  {  (e:  MouseEvent)  =>      Timeline(at(3  s){radius-­‐>0}).play()   }   83
  84. 84. TableView in ScalaFXdef dateFormat = new SimpleDateFormat("yyyy-MM-dd")!new TableView[Speaker](persons) {! columns = Seq(! new TableColumn[Speaker, String] {! text: "Name"! converter = {_.firstName}! } new TableColumn[Speaker, String] {! text: "Age"! converter = {_.age}! }! new TableColumn[Speaker, String] {! text: "Gender"! converter = {_.gender}! }! new TableColumn[Speaker, String] {! text: "Birth"! converter = {dateFormat.format(_.dob)}, ! }!)}! 84
  85. 85. JavaFX With Visage 85
  86. 86. About Project Visage>  “Visage is a domain specific language (DSL) designed for the express purpose of writing user interfaces.”>  Visage project goals: l  Compile to JavaFX Java APIs l  Evolve the Language (Annotations, Maps, etc.) l  Support Other Toolkits>  Come join the team!>  For more info: http://visage-lang.org/ 86
  87. 87. Java vs. Visage DSLpublic  class  VanishingCircles  extends  Application  {   var  circles:Circle[];     Stage  {      public  static  void  main(String[]  args)  {      title:  "Vanishing  Circles"          Application.launch(args);      Scene  {      }          width:  800                height:  600      @Override          fill:  BLACK      public  void  start(Stage  primaryStage)  {          Group  {          primaryStage.setTitle("Vanishing  Circles");              circles  =  for  (i  in  [1..50])  {          Group  root  =  new  Group();                  def  c:Circle  =  Circle  {          Scene  scene  =  new  Scene(root,  800,  600,  Color.BLACK);                      centerX:  random()  *  800          List<Circle>  circles  =  new  ArrayList<Circle>();                      centerY:  random()  *  600          for  (int  i  =  0;  i  <  50;  i++)  {                      radius:  150   40 Lines 35 Lines            final  Circle  circle  =  new  Circle(150);                      fill:  color(random(),  random(),  random(),  .2)              circle.setCenterX(Math.random()  *  800);                      effect:  BoxBlur  {              circle.setCenterY(Math.random()  *  600);                          height:  10              circle.setFill(new  Color(Math.random(),  Math.random(),  Math.random(),  .2));                          width:  10              circle.setEffect(new  BoxBlur(10,  10,  3));                          iterations:  3   1299 Characters            circle.addEventHandler(MouseEvent.MOUSE_CLICKED,  new  EventHandler<MouseEvent>()  {                  public  void  handle(MouseEvent  t)  {                      KeyValue  collapse  =  new  KeyValue(circle.radiusProperty(),  0);                      new  Timeline(new  KeyFrame(Duration.seconds(3),  collapse)).play();   487 Characters                    }                      stroke:  WHITE                      strokeWidth:  bind  if  (c.hover)  5  else  0                      onMouseClicked:  function(e)  {                  }                          Timeline  {at  (3s)  {c.radius  =>  0}}.play()              });                      }              circle.setStroke(Color.WHITE);                  }              circle.strokeWidthProperty().bind(Bindings.when(circle.hoverProperty())              }                  .then(4)          }                  .otherwise(0));      }              circles.add(circle);   }          }            root.getChildren().addAll(circles);   Timeline  {          primaryStage.setScene(scene);      for  (circle  in  circles)  at  (40s)  {          primaryStage.show();          circle.centerX  =>  random()  *  800;                    circle.centerY  =>  random()  *  600          Timeline  moveCircles  =  new  Timeline();      }          for  (Circle  circle  :  circles)  {   }.play()              KeyValue  moveX  =  new  KeyValue(circle.centerXProperty(),  Math.random()  *  800);              KeyValue  moveY  =  new  KeyValue(circle.centerYProperty(),  Math.random()  *  600);              moveCircles.getKeyFrames().add(new  KeyFrame(Duration.seconds(40),  moveX,  moveY));          }          moveCircles.play();      }  }   87
  88. 88. How about JavaFX on… VisageStage  {      title:  "Vanishing  Circles"      scene:  Scene  {          width:  800          height:  600          fill:  BLACK          content:  Group  {              circles  =  for  (i  in  [1..50])  {                  Circle  {                      centerX:  random()  *  800                      centerY:  random()  *  600                  }              }          }      }  }   88
  89. 89. How about JavaFX on… VisageStage  {      title:  "Vanishing  Circles"      scene:  Scene  {          width:  800          height:  600          fill:  BLACK          content:  Group  {              circles  =  for  (i  in  [1..50])  {                  Circle  {                      centerX:  random()  *  800                      centerY:  random()  *  600                  }              }          }      }  }   89
  90. 90. How about JavaFX on… VisageStage  {      title:  "Vanishing  Circles"      Scene  {          width:  800          height:  600          fill:  BLACK          Group  {              circles  =  for  (i  in  [1..50])  {                  Circle  {                      centerX:  random()  *  800                      centerY:  random()  *  600                  }              }          }      }  }   90
  91. 91. Visage is JavaFX Script++>  Default Parameters>  New Literal Syntax For: l  Angles – 35deg,  4rad,  1turn   l  Colors – #DDCCBB,  #AA33AA|CC   l  Lengths – 5px,  2pt,  3in,  4sp  >  Null-check Dereference l  var width = rect.!width>  Built-in Bindable Maps (coming soon!) l  var fruitMap = ["red" : apple, "yellow" : banana] l  var fruit = bind fruitMap["red"] 91
  92. 92. Visage and JavaFX 2.0 are made for each other…>  Enhanced Binding l  Retains lazy evaluation properties with additional expressive power>  Integrated Collections l  Sequences and Maps automatically convert between JavaFX Observable Lists/Maps>  Built-in Animation Syntax l  Ties into JavaFX animation subsystem l  Provides consistent, clean APIs 92
  93. 93. Other JVM Languages to Try>  JRuby l  Faithful to Ruby language with the power of the JVM>  Gosu l  Up and coming language created at GuideWire l  Easy to enhance libraries and create DSLs>  Mirah l  Invented by Charles Nutter l  Local Type Inference, Static and Dynamic Typing>  Fantom l  Created by Brian and Andy Frank l  Portable to Java and .NET l  Local Type Inference, Static and Dynamic Typing 93
  94. 94. Conclusion>  You can write JavaFX applications in pure Java>  JavaFX is also usable in alternate languages>  You can get improved support using DSL libraries l  GroovyFX l  ScalaFX>  Or a dedicated UI JVM Language l  Visage
  95. 95. Stephen Chin stephen.chin@oracle.com tweet: @steveonjavaThanks to Dean Iverson and Jonathan Giles for help preparing this talk 95

×