SlideShare a Scribd company logo
Hacking JavaFX with Groovy, Clojure,
Scala, and Visage
                       Stephen Chin
                       Java Evangelist, Oracle
                       stephen.chin@oracle.com
                       tweet: @steveonjava
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!
Disclaimer:
This is Code-Heavy
JavaFX 2.0 Platform
Immersive Application Experience
Leverage your Java skills with modern JavaFX
APIs
>    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.
JavaFX is Now Open Source!
Part of the OpenJDK Project

Controls available now, additional code
added incrementally

Project Page:
>  http://openjdk.java.net/projects/openjfx/




                                               5
And Will Run on Tablets!*

>  iPad (iOS)
>  Linux (Popular
     Platform for
     Tablets That
     Runs Something
     Similar to Java)

 *No Release Timeline Announced Yet
                                      6
JavaFX With Java
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
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
Example Application
public	
  class	
  HelloStage	
  extends	
  Application	
  {	
  
	
  
	
  	
  @Override	
  public	
  void	
  start(Stage	
  stage)	
  {	
  
	
  	
  	
  	
  stage.setTitle("Hello	
  Stage");	
  
	
  	
  	
  	
  stage.setWidth(600);	
  
	
  	
  	
  	
  stage.setHeight(450);	
  
	
  
	
  	
  	
  	
  Group	
  root	
  =	
  new	
  Group();	
  
	
  	
  	
  	
  Scene	
  scene	
  =	
  new	
  Scene(root);	
  
	
  	
  	
  	
  scene.setFill(Color.LIGHTGREEN);	
  
	
  
	
  	
  	
  	
  stage.setScene(scene);	
  
	
  	
  	
  	
  stage.show();	
  
	
  	
  }	
  
	
  
	
  	
  public	
  static	
  void	
  main(String[]	
  args)	
  {	
  
	
  	
  	
  	
  Application.launch(args);	
  
	
  	
  }	
  
}	
  
Example Application Using Builders
public	
  class	
  HelloStage	
  extends	
  Application	
  {	
  
	
  
	
  	
  @Override	
  public	
  void	
  start(Stage	
  stage)	
  {	
  
	
  	
  	
  	
  stage.setTitle("Hello	
  Stage");	
  
	
  	
  	
  	
  stage.setScene(SceneBuilder.create()	
  
	
  	
  	
  	
  	
  	
  .fill(Color.LIGHTGREEN)	
  
	
  	
  	
  	
  	
  	
  .width(600)	
  
	
  	
  	
  	
  	
  	
  .height(450)	
  
	
  	
  	
  	
  .build());	
  
	
  	
  	
  	
  stage.show();	
  
	
  	
  }	
  
	
  
	
  	
  public	
  static	
  void	
  main(String[]	
  args)	
  {	
  
	
  	
  	
  	
  Application.launch(args);	
  
	
  	
  }	
  
}	
  
Observable Properties
>  Supports watching for changes to properties
>  Implemented via anonymous inner classes

>  Will take advantage of closures in the future
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>()	
  {	
  
	
  	
  	
  	
  
	
  
	
  	
  	
  
});	
  
Observable Pseudo-Properties
	
  
final	
  Rectangle	
  rect	
  =	
  new	
  Rectangle();	
  
rect.setX(40);	
  
rect.setY(40);	
  
                                                           The property      we want to watch
rect.setWidth(100);	
  
rect.setHeight(200);	
  
	
  
	
  
rect.hoverProperty().addListener(new	
  ChangeListener<Boolean>()	
  {	
  
	
  	
  	
  
	
  
	
  	
  	
  
});	
  
Observable Pseudo-Properties
	
  
final	
  Rectangle	
  rect	
  =	
  new	
  Rectangle();	
  
rect.setX(40);	
                                           Only one listener used with generics   to
rect.setY(40);	
                                                   specify the data type
rect.setWidth(100);	
  
rect.setHeight(200);	
  
	
  
	
  
rect.hoverProperty().addListener(new	
  ChangeListener<Boolean>()	
  {	
  
	
  	
  	
  
	
  	
  	
  
	
  	
  	
  
});	
  
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()
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);	
  
	
  	
  }	
  
});	
  
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>)
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
Vanishing Circles




                    !
                        20
Vanishing Circles in Java
public	
  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
Application Skeleton
public	
  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…]	
  
	
  	
  }	
  
}	
  
Create the Circles
List<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
Setup Binding
circle.strokeWidthProperty().bind(Bindings	
  
	
  	
  .when(circle.hoverProperty())	
  
	
  	
  .then(4)	
  
	
  	
  .otherwise(0)	
  
);	
  




                                                 24
Setup Event Listeners
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();	
  
	
  	
  }	
  
});	
  




                                                                                                                                                 25
Begin the Animation
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();	
  


                                                                                                                                                                                                               26
JavaFX With Groovy
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
Java vs. GroovyFX DSL
public	
  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
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
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
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
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
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
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
Animation in GroovyFX
timeline(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
Animation in GroovyFX
timeline(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
Animation in GroovyFX
timeline(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
Animation in GroovyFX
timeline(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
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
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
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
But wait, there is more Grooviness…   43
Properties in Java
public 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
Properties in GroovyFX
public class Person {!
     @FXBindable String firstName; !
     @FXBindable String lastName;!
}!
	
  




                                       45
Properties in GroovyFX
public class Person {!
     @FXBindable String firstName; !
     @FXBindable String lastName = “Smith”;!
}!
	
  
                                           Optional initializers




                                                                   46
Properties in GroovyFX
public class Person {!
   @FXBindable String firstName; !
   @FXBindable String lastName = “Smith”;!
}!
!                                          Get and set values
def p = new Person()!
def last = p.lastName!
p.firstName = “Agent”!
!




                                                                47
Properties in GroovyFX
public class Person {!
   @FXBindable String firstName; !
   @FXBindable String lastName = “Smith”;!
}!
!
def p = new Person()!
def last = p.lastName!                 Access underlying property for
p.firstName = “Agent”!                           binding
!
textField(text: bind(p.lastNameProperty()))!
!


                                                                        48
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
TableView in Java
ObservableList<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
TableView in GroovyFX
def 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
Layout in Java
TextField 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
Layout in GroovyFX

sg.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
Layout in GroovyFX




                     54
Layout in GroovyFX
gridPane(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
Layout in GroovyFX




                     56
GroovyFX Supports…




                     57
GroovyFX Supports…




                     58
JavaFX With Clojure




        Artwork by Augusto Sellhorn   http://sellmic.com/




                                                            59
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
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
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
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
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
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
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
JavaFX With Scala




                    67
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
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
Java vs. Scala DSL
public	
  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
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
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
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
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
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
Binding in Scala
Infix Addition/Subtraction/Multiplication/Division:
height	
  <==	
  rect1.height	
  +	
  rect2.height	
  
	
  
Aggregate Operators:
width	
  <==	
  max(rect1.width,	
  rect2.width,	
  rect3.width)	
  
	
  
Conditional Expressions:
strokeWidth	
  <==	
  when	
  (hover)	
  then	
  4	
  otherwise	
  0	
  
	
  
Compound Expressions:
text	
  <==	
  when	
  (rect.hover	
  ||	
  circle.hover	
  &&	
  !disabled)	
  then	
  
     textField.text	
  +	
  "	
  is	
  enabled"	
  otherwise	
  "disabled"	
  

                                                                                           76
Animation in Scala
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();	
  
                                                                                                    77
JavaFX Script-like animation
Animation 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
Animation in Scala
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	
  
	
  	
  	
  	
  )	
  
	
  	
  }	
  
}	
  
                                                       Operator overloading for animation
timeline.play();	
                                                     syntax
                                                                                                    79
Animation in Scala
val	
  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
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
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
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
TableView in ScalaFX
def 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
JavaFX With Visage




                     85
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
Java vs. Visage DSL
public	
  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
How about JavaFX on… Visage
Stage	
  {	
  
	
  	
  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
How about JavaFX on… Visage
Stage	
  {	
  
	
  	
  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
How about JavaFX on… Visage
Stage	
  {	
  
	
  	
  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
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
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
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
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
Stephen Chin
                                                            stephen.chin@oracle.com
                                                            tweet: @steveonjava




Thanks to Dean Iverson and Jonathan Giles for help preparing this talk          95

More Related Content

What's hot (20)

PPTX
JavaFX and Scala in the Cloud
Stephen Chin
 
PDF
JavaFX Your Way: Building JavaFX Applications with Alternative Languages
Stephen Chin
 
PDF
Alternate JVM Languages
Saltmarch Media
 
PDF
The Ring programming language version 1.6 book - Part 46 of 189
Mahmoud Samir Fayed
 
PPTX
JavaFX 2.0 With Alternative Languages [Portuguese]
Stephen Chin
 
PDF
Zend Framework 1 + Doctrine 2
Ralph Schindler
 
PDF
Scala in practice
andyrobinson8
 
PDF
Building node.js applications with Database Jones
John David Duncan
 
PPTX
Php forum2015 tomas_final
Bertrand Matthelie
 
PDF
Developing for Node.JS with MySQL and NoSQL
John David Duncan
 
PDF
Java7 New Features and Code Examples
Naresh Chintalcheru
 
PDF
Scala vs Java 8 in a Java 8 World
BTI360
 
PDF
Clojure: Functional Concurrency for the JVM (presented at OSCON)
Howard Lewis Ship
 
PDF
The Ring programming language version 1.2 book - Part 79 of 84
Mahmoud Samir Fayed
 
PDF
The Ring programming language version 1.2 book - Part 32 of 84
Mahmoud Samir Fayed
 
PDF
Scala active record
鉄平 土佐
 
PDF
Java 7 New Features
Jussi Pohjolainen
 
PDF
PHP and MySQL Tips and tricks, DC 2007
Damien Seguy
 
PDF
JDays Lviv 2014: Java8 vs Scala: Difference points & innovation stream
Ruslan Shevchenko
 
PDF
Scala ActiveRecord
scalaconfjp
 
JavaFX and Scala in the Cloud
Stephen Chin
 
JavaFX Your Way: Building JavaFX Applications with Alternative Languages
Stephen Chin
 
Alternate JVM Languages
Saltmarch Media
 
The Ring programming language version 1.6 book - Part 46 of 189
Mahmoud Samir Fayed
 
JavaFX 2.0 With Alternative Languages [Portuguese]
Stephen Chin
 
Zend Framework 1 + Doctrine 2
Ralph Schindler
 
Scala in practice
andyrobinson8
 
Building node.js applications with Database Jones
John David Duncan
 
Php forum2015 tomas_final
Bertrand Matthelie
 
Developing for Node.JS with MySQL and NoSQL
John David Duncan
 
Java7 New Features and Code Examples
Naresh Chintalcheru
 
Scala vs Java 8 in a Java 8 World
BTI360
 
Clojure: Functional Concurrency for the JVM (presented at OSCON)
Howard Lewis Ship
 
The Ring programming language version 1.2 book - Part 79 of 84
Mahmoud Samir Fayed
 
The Ring programming language version 1.2 book - Part 32 of 84
Mahmoud Samir Fayed
 
Scala active record
鉄平 土佐
 
Java 7 New Features
Jussi Pohjolainen
 
PHP and MySQL Tips and tricks, DC 2007
Damien Seguy
 
JDays Lviv 2014: Java8 vs Scala: Difference points & innovation stream
Ruslan Shevchenko
 
Scala ActiveRecord
scalaconfjp
 

Similar to Hacking JavaFX with Groovy, Clojure, Scala, and Visage: Stephen Chin (20)

PPTX
JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)
Stephen Chin
 
PPTX
Java Core | JavaFX 2.0: Great User Interfaces in Java | Simon Ritter
JAX London
 
PPTX
JavaFX Your Way - Devoxx Version
Stephen Chin
 
PPTX
OpenJFX on Android and Devices
Stephen Chin
 
PDF
JavaFX 1.0 SDK Aquarium Paris
Alexis Moussine-Pouchkine
 
ODP
Java Fx Overview Tech Tour
Carol McDonald
 
PPT
Intro to JavaFX & Widget FX
Stephen Chin
 
PDF
JavaFX Overview
José Maria Silveira Neto
 
PDF
Javafx Overview 90minutes
SiliconExpert Technologies
 
PDF
Javafx Overview 90minutes
SiliconExpert Technologies
 
PDF
Javafx Overview 90minutes
SiliconExpert Technologies
 
PPT
JavaFX - Next Generation Java UI
Yoav Aharoni
 
PDF
Java Fx Ajaxworld Rags V1
rajivmordani
 
PPTX
JavaFX 2.0 and Alternative Languages
Stephen Chin
 
PPTX
Raspberry Pi à la GroovyFX
Stephen Chin
 
PPTX
JavaFX 2.0 With Alternative Languages - Groovy, Clojure, Scala, Fantom, and V...
Stephen Chin
 
PDF
BeJUG JavaFx In Practice
Pursuit Consulting
 
ODP
JavaFX introduction
José Maria Silveira Neto
 
PDF
Moving to the Client - JavaFX and HTML5
Stephen Chin
 
PDF
JavaFX goes Scala
Cofinpro AG
 
JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)
Stephen Chin
 
Java Core | JavaFX 2.0: Great User Interfaces in Java | Simon Ritter
JAX London
 
JavaFX Your Way - Devoxx Version
Stephen Chin
 
OpenJFX on Android and Devices
Stephen Chin
 
JavaFX 1.0 SDK Aquarium Paris
Alexis Moussine-Pouchkine
 
Java Fx Overview Tech Tour
Carol McDonald
 
Intro to JavaFX & Widget FX
Stephen Chin
 
JavaFX Overview
José Maria Silveira Neto
 
Javafx Overview 90minutes
SiliconExpert Technologies
 
Javafx Overview 90minutes
SiliconExpert Technologies
 
Javafx Overview 90minutes
SiliconExpert Technologies
 
JavaFX - Next Generation Java UI
Yoav Aharoni
 
Java Fx Ajaxworld Rags V1
rajivmordani
 
JavaFX 2.0 and Alternative Languages
Stephen Chin
 
Raspberry Pi à la GroovyFX
Stephen Chin
 
JavaFX 2.0 With Alternative Languages - Groovy, Clojure, Scala, Fantom, and V...
Stephen Chin
 
BeJUG JavaFx In Practice
Pursuit Consulting
 
JavaFX introduction
José Maria Silveira Neto
 
Moving to the Client - JavaFX and HTML5
Stephen Chin
 
JavaFX goes Scala
Cofinpro AG
 

Recently uploaded (20)

PDF
Reverse Engineering of Security Products: Developing an Advanced Microsoft De...
nwbxhhcyjv
 
PDF
"AI Transformation: Directions and Challenges", Pavlo Shaternik
Fwdays
 
PDF
Transforming Utility Networks: Large-scale Data Migrations with FME
Safe Software
 
PDF
Jak MŚP w Europie Środkowo-Wschodniej odnajdują się w świecie AI
dominikamizerska1
 
PDF
Mastering Financial Management in Direct Selling
Epixel MLM Software
 
PDF
Bitcoin for Millennials podcast with Bram, Power Laws of Bitcoin
Stephen Perrenod
 
PDF
The Rise of AI and IoT in Mobile App Tech.pdf
IMG Global Infotech
 
PPTX
Seamless Tech Experiences Showcasing Cross-Platform App Design.pptx
presentifyai
 
PPTX
From Sci-Fi to Reality: Exploring AI Evolution
Svetlana Meissner
 
PDF
How do you fast track Agentic automation use cases discovery?
DianaGray10
 
PDF
Achieving Consistent and Reliable AI Code Generation - Medusa AI
medusaaico
 
PDF
CIFDAQ Market Insights for July 7th 2025
CIFDAQ
 
DOCX
Python coding for beginners !! Start now!#
Rajni Bhardwaj Grover
 
PDF
Transcript: New from BookNet Canada for 2025: BNC BiblioShare - Tech Forum 2025
BookNet Canada
 
PPTX
"Autonomy of LLM Agents: Current State and Future Prospects", Oles` Petriv
Fwdays
 
PDF
Agentic AI lifecycle for Enterprise Hyper-Automation
Debmalya Biswas
 
PDF
The 2025 InfraRed Report - Redpoint Ventures
Razin Mustafiz
 
PPTX
Q2 FY26 Tableau User Group Leader Quarterly Call
lward7
 
PPTX
Webinar: Introduction to LF Energy EVerest
DanBrown980551
 
PPTX
MuleSoft MCP Support (Model Context Protocol) and Use Case Demo
shyamraj55
 
Reverse Engineering of Security Products: Developing an Advanced Microsoft De...
nwbxhhcyjv
 
"AI Transformation: Directions and Challenges", Pavlo Shaternik
Fwdays
 
Transforming Utility Networks: Large-scale Data Migrations with FME
Safe Software
 
Jak MŚP w Europie Środkowo-Wschodniej odnajdują się w świecie AI
dominikamizerska1
 
Mastering Financial Management in Direct Selling
Epixel MLM Software
 
Bitcoin for Millennials podcast with Bram, Power Laws of Bitcoin
Stephen Perrenod
 
The Rise of AI and IoT in Mobile App Tech.pdf
IMG Global Infotech
 
Seamless Tech Experiences Showcasing Cross-Platform App Design.pptx
presentifyai
 
From Sci-Fi to Reality: Exploring AI Evolution
Svetlana Meissner
 
How do you fast track Agentic automation use cases discovery?
DianaGray10
 
Achieving Consistent and Reliable AI Code Generation - Medusa AI
medusaaico
 
CIFDAQ Market Insights for July 7th 2025
CIFDAQ
 
Python coding for beginners !! Start now!#
Rajni Bhardwaj Grover
 
Transcript: New from BookNet Canada for 2025: BNC BiblioShare - Tech Forum 2025
BookNet Canada
 
"Autonomy of LLM Agents: Current State and Future Prospects", Oles` Petriv
Fwdays
 
Agentic AI lifecycle for Enterprise Hyper-Automation
Debmalya Biswas
 
The 2025 InfraRed Report - Redpoint Ventures
Razin Mustafiz
 
Q2 FY26 Tableau User Group Leader Quarterly Call
lward7
 
Webinar: Introduction to LF Energy EVerest
DanBrown980551
 
MuleSoft MCP Support (Model Context Protocol) and Use Case Demo
shyamraj55
 

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

  • 1. Hacking JavaFX with Groovy, Clojure, Scala, and Visage Stephen Chin Java Evangelist, Oracle [email protected] tweet: @steveonjava
  • 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!
  • 4. JavaFX 2.0 Platform Immersive Application Experience Leverage your Java skills with modern JavaFX APIs >  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. JavaFX is Now Open Source! Part of the OpenJDK Project Controls available now, additional code added incrementally Project Page: >  http://openjdk.java.net/projects/openjfx/ 5
  • 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
  • 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. 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. Example Application public  class  HelloStage  extends  Application  {        @Override  public  void  start(Stage  stage)  {          stage.setTitle("Hello  Stage");          stage.setWidth(600);          stage.setHeight(450);            Group  root  =  new  Group();          Scene  scene  =  new  Scene(root);          scene.setFill(Color.LIGHTGREEN);            stage.setScene(scene);          stage.show();      }        public  static  void  main(String[]  args)  {          Application.launch(args);      }   }  
  • 11. Example Application Using Builders public  class  HelloStage  extends  Application  {        @Override  public  void  start(Stage  stage)  {          stage.setTitle("Hello  Stage");          stage.setScene(SceneBuilder.create()              .fill(Color.LIGHTGREEN)              .width(600)              .height(450)          .build());          stage.show();      }        public  static  void  main(String[]  args)  {          Application.launch(args);      }   }  
  • 12. Observable Properties >  Supports watching for changes to properties >  Implemented via anonymous inner classes >  Will take advantage of closures in the future
  • 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. Observable Pseudo-Properties   final  Rectangle  rect  =  new  Rectangle();   rect.setX(40);   rect.setY(40);   The property we want to watch rect.setWidth(100);   rect.setHeight(200);       rect.hoverProperty().addListener(new  ChangeListener<Boolean>()  {                 });  
  • 15. Observable Pseudo-Properties   final  Rectangle  rect  =  new  Rectangle();   rect.setX(40);   Only one listener used with generics to rect.setY(40);   specify the data type rect.setWidth(100);   rect.setHeight(200);       rect.hoverProperty().addListener(new  ChangeListener<Boolean>()  {                     });  
  • 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. 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. 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. 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
  • 21. Vanishing Circles in Java public  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. Application Skeleton public  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. Create the Circles List<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. Setup Binding circle.strokeWidthProperty().bind(Bindings      .when(circle.hoverProperty())      .then(4)      .otherwise(0)   );   24
  • 25. Setup Event Listeners 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();      }   });   25
  • 26. Begin the Animation 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();   26
  • 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. Java vs. GroovyFX DSL public  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. 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. 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. 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. 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. 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. 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. Animation in GroovyFX timeline(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. Animation in GroovyFX timeline(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. Animation in GroovyFX timeline(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. Animation in GroovyFX timeline(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. 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. 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. 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. But wait, there is more Grooviness… 43
  • 44. Properties in Java public 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. Properties in GroovyFX public class Person {! @FXBindable String firstName; ! @FXBindable String lastName;! }!   45
  • 46. Properties in GroovyFX public class Person {! @FXBindable String firstName; ! @FXBindable String lastName = “Smith”;! }!   Optional initializers 46
  • 47. Properties in GroovyFX public class Person {! @FXBindable String firstName; ! @FXBindable String lastName = “Smith”;! }! ! Get and set values def p = new Person()! def last = p.lastName! p.firstName = “Agent”! ! 47
  • 48. Properties in GroovyFX public class Person {! @FXBindable String firstName; ! @FXBindable String lastName = “Smith”;! }! ! def p = new Person()! def last = p.lastName! Access underlying property for p.firstName = “Agent”! binding ! textField(text: bind(p.lastNameProperty()))! ! 48
  • 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. TableView in Java ObservableList<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. TableView in GroovyFX def 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. Layout in Java TextField 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. Layout in GroovyFX sg.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
  • 55. Layout in GroovyFX gridPane(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
  • 59. JavaFX With Clojure Artwork by Augusto Sellhorn http://sellmic.com/ 59
  • 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. 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. 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. 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. 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. 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. 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
  • 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. 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. Java vs. Scala DSL public  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. 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. 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. 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. 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. 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. Binding in Scala Infix Addition/Subtraction/Multiplication/Division: height  <==  rect1.height  +  rect2.height     Aggregate Operators: width  <==  max(rect1.width,  rect2.width,  rect3.width)     Conditional Expressions: strokeWidth  <==  when  (hover)  then  4  otherwise  0     Compound Expressions: text  <==  when  (rect.hover  ||  circle.hover  &&  !disabled)  then   textField.text  +  "  is  enabled"  otherwise  "disabled"   76
  • 77. Animation in Scala 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();   77
  • 78. JavaFX Script-like animation Animation 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. Animation in Scala 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          )      }   }   Operator overloading for animation timeline.play();   syntax 79
  • 80. Animation in Scala val  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. 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. 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. 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. TableView in ScalaFX def 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
  • 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. Java vs. Visage DSL public  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. How about JavaFX on… Visage Stage  {      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. How about JavaFX on… Visage Stage  {      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. How about JavaFX on… Visage Stage  {      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. 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. 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. 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. 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. Stephen Chin [email protected] tweet: @steveonjava Thanks to Dean Iverson and Jonathan Giles for help preparing this talk 95