SlideShare a Scribd company logo
1 of 95
Download to read offline
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

JavaFX and Scala in the Cloud
JavaFX and Scala in the CloudJavaFX and Scala in the Cloud
JavaFX and Scala in the CloudStephen Chin
 
JavaFX Your Way: Building JavaFX Applications with Alternative Languages
JavaFX Your Way: Building JavaFX Applications with Alternative LanguagesJavaFX Your Way: Building JavaFX Applications with Alternative Languages
JavaFX Your Way: Building JavaFX Applications with Alternative LanguagesStephen Chin
 
The Ring programming language version 1.6 book - Part 46 of 189
The Ring programming language version 1.6 book - Part 46 of 189The Ring programming language version 1.6 book - Part 46 of 189
The Ring programming language version 1.6 book - Part 46 of 189Mahmoud Samir Fayed
 
JavaFX 2.0 With Alternative Languages [Portuguese]
JavaFX 2.0 With Alternative Languages [Portuguese]JavaFX 2.0 With Alternative Languages [Portuguese]
JavaFX 2.0 With Alternative Languages [Portuguese]Stephen Chin
 
Zend Framework 1 + Doctrine 2
Zend Framework 1 + Doctrine 2Zend Framework 1 + Doctrine 2
Zend Framework 1 + Doctrine 2Ralph Schindler
 
Building node.js applications with Database Jones
Building node.js applications with Database JonesBuilding node.js applications with Database Jones
Building node.js applications with Database JonesJohn David Duncan
 
Developing for Node.JS with MySQL and NoSQL
Developing for Node.JS with MySQL and NoSQLDeveloping for Node.JS with MySQL and NoSQL
Developing for Node.JS with MySQL and NoSQLJohn David Duncan
 
Java7 New Features and Code Examples
Java7 New Features and Code ExamplesJava7 New Features and Code Examples
Java7 New Features and Code ExamplesNaresh Chintalcheru
 
Scala vs Java 8 in a Java 8 World
Scala vs Java 8 in a Java 8 WorldScala vs Java 8 in a Java 8 World
Scala vs Java 8 in a Java 8 WorldBTI360
 
Clojure: Functional Concurrency for the JVM (presented at OSCON)
Clojure: Functional Concurrency for the JVM (presented at OSCON)Clojure: Functional Concurrency for the JVM (presented at OSCON)
Clojure: Functional Concurrency for the JVM (presented at OSCON)Howard Lewis Ship
 
The Ring programming language version 1.2 book - Part 79 of 84
The Ring programming language version 1.2 book - Part 79 of 84The Ring programming language version 1.2 book - Part 79 of 84
The Ring programming language version 1.2 book - Part 79 of 84Mahmoud Samir Fayed
 
The Ring programming language version 1.2 book - Part 32 of 84
The Ring programming language version 1.2 book - Part 32 of 84The Ring programming language version 1.2 book - Part 32 of 84
The Ring programming language version 1.2 book - Part 32 of 84Mahmoud Samir Fayed
 
PHP and MySQL Tips and tricks, DC 2007
PHP and MySQL Tips and tricks, DC 2007PHP and MySQL Tips and tricks, DC 2007
PHP and MySQL Tips and tricks, DC 2007Damien Seguy
 
JDays Lviv 2014: Java8 vs Scala: Difference points & innovation stream
JDays Lviv 2014:  Java8 vs Scala:  Difference points & innovation streamJDays Lviv 2014:  Java8 vs Scala:  Difference points & innovation stream
JDays Lviv 2014: Java8 vs Scala: Difference points & innovation streamRuslan Shevchenko
 
Scala ActiveRecord
Scala ActiveRecordScala ActiveRecord
Scala ActiveRecordscalaconfjp
 

What's hot (20)

JavaFX and Scala in the Cloud
JavaFX and Scala in the CloudJavaFX and Scala in the Cloud
JavaFX and Scala in the Cloud
 
JavaFX Your Way: Building JavaFX Applications with Alternative Languages
JavaFX Your Way: Building JavaFX Applications with Alternative LanguagesJavaFX Your Way: Building JavaFX Applications with Alternative Languages
JavaFX Your Way: Building JavaFX Applications with Alternative Languages
 
Alternate JVM Languages
Alternate JVM LanguagesAlternate JVM Languages
Alternate JVM Languages
 
The Ring programming language version 1.6 book - Part 46 of 189
The Ring programming language version 1.6 book - Part 46 of 189The Ring programming language version 1.6 book - Part 46 of 189
The Ring programming language version 1.6 book - Part 46 of 189
 
JavaFX 2.0 With Alternative Languages [Portuguese]
JavaFX 2.0 With Alternative Languages [Portuguese]JavaFX 2.0 With Alternative Languages [Portuguese]
JavaFX 2.0 With Alternative Languages [Portuguese]
 
Zend Framework 1 + Doctrine 2
Zend Framework 1 + Doctrine 2Zend Framework 1 + Doctrine 2
Zend Framework 1 + Doctrine 2
 
Scala in practice
Scala in practiceScala in practice
Scala in practice
 
Building node.js applications with Database Jones
Building node.js applications with Database JonesBuilding node.js applications with Database Jones
Building node.js applications with Database Jones
 
Php forum2015 tomas_final
Php forum2015 tomas_finalPhp forum2015 tomas_final
Php forum2015 tomas_final
 
Developing for Node.JS with MySQL and NoSQL
Developing for Node.JS with MySQL and NoSQLDeveloping for Node.JS with MySQL and NoSQL
Developing for Node.JS with MySQL and NoSQL
 
Java7 New Features and Code Examples
Java7 New Features and Code ExamplesJava7 New Features and Code Examples
Java7 New Features and Code Examples
 
Scala vs Java 8 in a Java 8 World
Scala vs Java 8 in a Java 8 WorldScala vs Java 8 in a Java 8 World
Scala vs Java 8 in a Java 8 World
 
Clojure: Functional Concurrency for the JVM (presented at OSCON)
Clojure: Functional Concurrency for the JVM (presented at OSCON)Clojure: Functional Concurrency for the JVM (presented at OSCON)
Clojure: Functional Concurrency for the JVM (presented at OSCON)
 
The Ring programming language version 1.2 book - Part 79 of 84
The Ring programming language version 1.2 book - Part 79 of 84The Ring programming language version 1.2 book - Part 79 of 84
The Ring programming language version 1.2 book - Part 79 of 84
 
The Ring programming language version 1.2 book - Part 32 of 84
The Ring programming language version 1.2 book - Part 32 of 84The Ring programming language version 1.2 book - Part 32 of 84
The Ring programming language version 1.2 book - Part 32 of 84
 
Scala active record
Scala active recordScala active record
Scala active record
 
Java 7 New Features
Java 7 New FeaturesJava 7 New Features
Java 7 New Features
 
PHP and MySQL Tips and tricks, DC 2007
PHP and MySQL Tips and tricks, DC 2007PHP and MySQL Tips and tricks, DC 2007
PHP and MySQL Tips and tricks, DC 2007
 
JDays Lviv 2014: Java8 vs Scala: Difference points & innovation stream
JDays Lviv 2014:  Java8 vs Scala:  Difference points & innovation streamJDays Lviv 2014:  Java8 vs Scala:  Difference points & innovation stream
JDays Lviv 2014: Java8 vs Scala: Difference points & innovation stream
 
Scala ActiveRecord
Scala ActiveRecordScala ActiveRecord
Scala ActiveRecord
 

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

JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)
JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)
JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)Stephen Chin
 
JavaFX Your Way - Devoxx Version
JavaFX Your Way - Devoxx VersionJavaFX Your Way - Devoxx Version
JavaFX Your Way - Devoxx VersionStephen Chin
 
JavaFX 2.0 and Alternative Languages
JavaFX 2.0 and Alternative LanguagesJavaFX 2.0 and Alternative Languages
JavaFX 2.0 and Alternative LanguagesStephen Chin
 
JavaFX 2.0 With Alternative Languages - Groovy, Clojure, Scala, Fantom, and V...
JavaFX 2.0 With Alternative Languages - Groovy, Clojure, Scala, Fantom, and V...JavaFX 2.0 With Alternative Languages - Groovy, Clojure, Scala, Fantom, and V...
JavaFX 2.0 With Alternative Languages - Groovy, Clojure, Scala, Fantom, and V...Stephen Chin
 
Mary Had a Little λ (QCon)
Mary Had a Little λ (QCon)Mary Had a Little λ (QCon)
Mary Had a Little λ (QCon)Stephen Chin
 
Scala @ TechMeetup Edinburgh
Scala @ TechMeetup EdinburghScala @ TechMeetup Edinburgh
Scala @ TechMeetup EdinburghStuart Roebuck
 
Don't panic in Fortaleza - ScalaFX
Don't panic in Fortaleza - ScalaFXDon't panic in Fortaleza - ScalaFX
Don't panic in Fortaleza - ScalaFXAlain Béarez
 
Akka Cluster in Java - JCConf 2015
Akka Cluster in Java - JCConf 2015Akka Cluster in Java - JCConf 2015
Akka Cluster in Java - JCConf 2015Jiayun Zhou
 
Painless Persistence with Realm
Painless Persistence with RealmPainless Persistence with Realm
Painless Persistence with RealmChristian Melchior
 
Vert.x - Reactive & Distributed [Devoxx version]
Vert.x - Reactive & Distributed [Devoxx version]Vert.x - Reactive & Distributed [Devoxx version]
Vert.x - Reactive & Distributed [Devoxx version]Orkhan Gasimov
 
Greach, GroovyFx Workshop
Greach, GroovyFx WorkshopGreach, GroovyFx Workshop
Greach, GroovyFx WorkshopDierk König
 
JJUG CCC 2011 Spring
JJUG CCC 2011 SpringJJUG CCC 2011 Spring
JJUG CCC 2011 SpringKiyotaka Oku
 
Clojure - A new Lisp
Clojure - A new LispClojure - A new Lisp
Clojure - A new Lispelliando dias
 
Practical Experience Building JavaFX Rich Clients
Practical Experience Building JavaFX Rich ClientsPractical Experience Building JavaFX Rich Clients
Practical Experience Building JavaFX Rich ClientsRichard Bair
 
Eric Lafortune - The Jack and Jill build system
Eric Lafortune - The Jack and Jill build systemEric Lafortune - The Jack and Jill build system
Eric Lafortune - The Jack and Jill build systemGuardSquare
 
An Introduction to Property Based Testing
An Introduction to Property Based TestingAn Introduction to Property Based Testing
An Introduction to Property Based TestingC4Media
 
apidays LIVE Australia - Building distributed systems on the shoulders of gia...
apidays LIVE Australia - Building distributed systems on the shoulders of gia...apidays LIVE Australia - Building distributed systems on the shoulders of gia...
apidays LIVE Australia - Building distributed systems on the shoulders of gia...apidays
 
OracleCode One 2018: Java 5, 6, 7, 8, 9, 10, 11: What Did You Miss?
OracleCode One 2018: Java 5, 6, 7, 8, 9, 10, 11: What Did You Miss?OracleCode One 2018: Java 5, 6, 7, 8, 9, 10, 11: What Did You Miss?
OracleCode One 2018: Java 5, 6, 7, 8, 9, 10, 11: What Did You Miss?Henri Tremblay
 

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

JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)
JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)
JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)
 
JavaFX Your Way - Devoxx Version
JavaFX Your Way - Devoxx VersionJavaFX Your Way - Devoxx Version
JavaFX Your Way - Devoxx Version
 
JavaFX 2.0 and Alternative Languages
JavaFX 2.0 and Alternative LanguagesJavaFX 2.0 and Alternative Languages
JavaFX 2.0 and Alternative Languages
 
JavaFX 2.0 With Alternative Languages - Groovy, Clojure, Scala, Fantom, and V...
JavaFX 2.0 With Alternative Languages - Groovy, Clojure, Scala, Fantom, and V...JavaFX 2.0 With Alternative Languages - Groovy, Clojure, Scala, Fantom, and V...
JavaFX 2.0 With Alternative Languages - Groovy, Clojure, Scala, Fantom, and V...
 
Mary Had a Little λ (QCon)
Mary Had a Little λ (QCon)Mary Had a Little λ (QCon)
Mary Had a Little λ (QCon)
 
Scala @ TechMeetup Edinburgh
Scala @ TechMeetup EdinburghScala @ TechMeetup Edinburgh
Scala @ TechMeetup Edinburgh
 
JavaFX introduction
JavaFX introductionJavaFX introduction
JavaFX introduction
 
Don't panic in Fortaleza - ScalaFX
Don't panic in Fortaleza - ScalaFXDon't panic in Fortaleza - ScalaFX
Don't panic in Fortaleza - ScalaFX
 
Akka Cluster in Java - JCConf 2015
Akka Cluster in Java - JCConf 2015Akka Cluster in Java - JCConf 2015
Akka Cluster in Java - JCConf 2015
 
Painless Persistence with Realm
Painless Persistence with RealmPainless Persistence with Realm
Painless Persistence with Realm
 
Vert.x - Reactive & Distributed [Devoxx version]
Vert.x - Reactive & Distributed [Devoxx version]Vert.x - Reactive & Distributed [Devoxx version]
Vert.x - Reactive & Distributed [Devoxx version]
 
Greach, GroovyFx Workshop
Greach, GroovyFx WorkshopGreach, GroovyFx Workshop
Greach, GroovyFx Workshop
 
JJUG CCC 2011 Spring
JJUG CCC 2011 SpringJJUG CCC 2011 Spring
JJUG CCC 2011 Spring
 
Clojure - A new Lisp
Clojure - A new LispClojure - A new Lisp
Clojure - A new Lisp
 
Practical Experience Building JavaFX Rich Clients
Practical Experience Building JavaFX Rich ClientsPractical Experience Building JavaFX Rich Clients
Practical Experience Building JavaFX Rich Clients
 
Clojure And Swing
Clojure And SwingClojure And Swing
Clojure And Swing
 
Eric Lafortune - The Jack and Jill build system
Eric Lafortune - The Jack and Jill build systemEric Lafortune - The Jack and Jill build system
Eric Lafortune - The Jack and Jill build system
 
An Introduction to Property Based Testing
An Introduction to Property Based TestingAn Introduction to Property Based Testing
An Introduction to Property Based Testing
 
apidays LIVE Australia - Building distributed systems on the shoulders of gia...
apidays LIVE Australia - Building distributed systems on the shoulders of gia...apidays LIVE Australia - Building distributed systems on the shoulders of gia...
apidays LIVE Australia - Building distributed systems on the shoulders of gia...
 
OracleCode One 2018: Java 5, 6, 7, 8, 9, 10, 11: What Did You Miss?
OracleCode One 2018: Java 5, 6, 7, 8, 9, 10, 11: What Did You Miss?OracleCode One 2018: Java 5, 6, 7, 8, 9, 10, 11: What Did You Miss?
OracleCode One 2018: Java 5, 6, 7, 8, 9, 10, 11: What Did You Miss?
 

Recently uploaded

New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brandgvaughan
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity PlanDatabarracks
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsSergiu Bodiu
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfAlex Barbosa Coqueiro
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxNavinnSomaal
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxLoriGlavin3
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Enterprise Knowledge
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteDianaGray10
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfAddepto
 
DSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningDSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningLars Bell
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfRankYa
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxhariprasad279825
 
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfHyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfPrecisely
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Manik S Magar
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupFlorian Wilhelm
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...Fwdays
 

Recently uploaded (20)

New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brand
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity Plan
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platforms
 
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptxE-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdf
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptx
 
DMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special EditionDMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special Edition
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test Suite
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdf
 
DSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningDSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine Tuning
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdf
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptx
 
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfHyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project Setup
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
 

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

  • 1. Hacking JavaFX with Groovy, Clojure, Scala, and Visage Stephen Chin Java Evangelist, Oracle stephen.chin@oracle.com 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 stephen.chin@oracle.com tweet: @steveonjava Thanks to Dean Iverson and Jonathan Giles for help preparing this talk 95