SlideShare a Scribd company logo
Hacking JavaFX with Groovy, Clojure,
Scala, and Visage
                       Stephen Chin
                       Java Evangelist, Oracle
                       stephen.chin@oracle.com
                       tweet: @steveonjava
Meet the Presenter

           Stephen Chin
                                     >   Java Evangelist, Oracle
                                     >   Author, Pro JavaFX Platform 2
      Family Man
                                     >   Open Source Hacker
                                            JFXtras
                                            ScalaFX
                      Motorcyclist          Visage
                                     >   User Group Co-Leader
                                            Silicon Valley JavaFX
                                             User Group
                                            Streamed Live!
Safe Harbor Statement
The following is intended to outline our general product
direction. It is intended for information purposes only, and
may not be incorporated into any contract. It is not a
commitment to deliver any material, code, or functionality,
and should not be relied upon in making purchasing
decisions. The development, release, and timing of any
features or functionality described for Oracle’s products
remains at the sole discretion of Oracle.
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 With Java
Programming Languages
>   JavaFX 2.0 APIs are now in Java
       Pure Java APIs for all of JavaFX
       Binding and Sequences exposed as Java APIs
       FXML Markup for tooling
>   Embrace all JVM languages
       Groovy, Scala, Clojure, JRuby
       Fantom, Mira, Gosu, Jython, etc.
>   JavaFX Script is no longer supported by Oracle
       Existing JavaFX Script based applications will continue to run
       Visage is the open-source successor to the JavaFX Script language
Vanishing Circles




                    7
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++) {
        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));
                                                                                              40 Lines
        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);
                                                                                              1299 Characters
            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();
    }
}




                                                                                                                8
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);
}

                                                           10
Setup Binding
circle.strokeWidthProperty().bind(Bindings
   .when(circle.hoverProperty())
   .then(4)
   .otherwise(0)
);




                                             11
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();
  }
});




                                                                    12
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();


                                                                  13
JavaFX With Groovy
Features of Groovy
>   Modern language
       Closures
       AST Transforms
       Strongly typed dynamic language

>   Tight integration with Java
       Very easy to port from Java to Groovy

>   Declarative syntax with GroovyFX Builders
       Familiar to Groovy and JavaFX Script developers
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 ->


                                                                                                                     29 Lines
        final Circle circle = new Circle(150);                                                              timeline {

                  40 Lines
        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));                                                       }
                                                                                                          }
                                                                                                              at(3.s) { change e.source.radiusProperty() to 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();
                                                                                                    }
                                                                                                      }
                                                                                                                     671 Characters
                                                                                                      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();
    }
}




                                                                                                                                                                                                16
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)
          }
        }
      }
    }
}
                                                                          17
GroovyFX.start { primaryStage ->
  def sg = new SceneGraphBuilder()
  def rand = new Random().&nextInt
  def circles = []
                                       Builder for GroovyFX scene graphs
    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)
          }
        }
      }
    }
}
                                                                          18
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)
          }
        }
      }
    }
}
                                                                          19
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)
          }
        }
      }
    }
}
                                                                          20
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)
          }
        }
      }
    }
}
                                                                          21
GroovyFX.start { primaryStage ->
  def sg = new SceneGraphBuilder()
  def rand = new Random().&nextInt
  def circles = []

    sg.stage(title: 'Vanishing Circles', show: Sequence Creation Via Loop
                                               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)
          }
        }
      }
    }
}
                                                                          22
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()




                                                                 23
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}




                                                                 24
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



                                                                 25
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




                                                                     26
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()
}



                                                        27
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}
                                                        28
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()
}



                                                                             29
But wait, there is more Grooviness…   30
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.
    }
}


                                                                               31
Properties in GroovyFX
public class Person {
  @FXBindable String firstName;
  @FXBindable String lastName;
}




                                  32
Properties in GroovyFX
public class Person {
  @FXBindable String firstName;
  @FXBindable String lastName = “Smith”;
}

                                           Optional initializers




                                                                   33
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);
                                                                            34
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) })
}




                                                                    35
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);




                                                               36
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")
     }
  }
}

                                                               37
Layout in GroovyFX




                     38
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")
}
                                                                              39
Layout in GroovyFX




                     40
GroovyFX Supports…




                     41
JavaFX With Clojure




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




                                                            42
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!

                                                    43
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)
                                                                                             44
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)

                                        45
Refined Clojure GUI Example
(defn javafxapp []
  (doto (Stage. "JavaFX Stage")
    (.setWidth 600)
    (.setHeight 450)
    (.setScene (doto (Scene.)
      (.setFill Color/LIGHTGREEN)
      (.setContent (list (doto (Rectangle.)
        (.setX 25)
        (.setY 40)
        (.setWidth 100)
        (.setHeight 50)
        (.setFill Color/RED))))))
    (.setVisible true)))
(javafxapp)

                                              46
Refined Clojure GUI Example
(defn javafxapp []
  (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)

                                                                        47
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)))))




                                                             48
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)))))




                                                             49
JavaFX With Scala




                    50
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
                                                                              51
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)
        final Circle circle = new Circle(150);                                                        effect = new BoxBlur(10, 10, 3)

                  40 Lines
        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));
                                                                                                                 33 Lines
                                                                                                      strokeWidth <== when (hover) then 4 otherwise 0
                                                                                                      stroke = WHITE
                                                                                                      onMouseClicked = {
                                                                                                        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();
    }
}




                                                                                                                                                            52
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)
      }
    }
  }
}
                                                            53
object VanishingCircles extends JFXApp {
  stage = new Stage {
    title = "Disappearing Circles"
    width = 800
    height Base class for JavaFX applications
            = 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)
      }
    }
  }
}
                                                            54
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)
      }
    }
  }
}
                                                                     55
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)
      }
    }
  }
}
                                                                       56
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)
      }
    }
  }
}
                                                                   57
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"

                                                               58
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();

                                                          59
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();

                                                            60
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
                                                                   61
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
                                                           62
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()
    }


                                                  63
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}
                                                  64
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()
    }


                                                                      65
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)},
   }
)}

                                                      66
JavaFX With Visage




                     67
About Project Visage
>   “Visage is a domain specific language (DSL) designed for the
    express purpose of writing user interfaces.”



>   Visage project goals:
       Compile to JavaFX Java APIs
       Evolve the Language (Annotations, Maps, etc.)
       Support Other Toolkits

>   Come join the team!
>   For more info: http://visage-lang.org/
                                                                   68
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
        final Circle circle = new Circle(150);                                                          fill: color(random(), random(), random(), .2)

                  40 Lines
        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));
                                                                                                               35 Lines
                                                                                                        effect: BoxBlur {
                                                                                                          height: 10
                                                                                                          width: 10
                                                                                                          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();
    }
}




                                                                                                                                                        69
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
        }
      }
    }
  }
}

                                       70
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
        }
      }
    }
  }
}

                                       71
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
        }
      }
    }
  }
}

                                       72
Visage is JavaFX Script++
>   Default Parameters
>   New Literal Syntax For:
       Angles – 35deg, 4rad, 1turn
       Colors – #DDCCBB, #AA33AA|CC
       Lengths – 5px, 2pt, 3in, 4sp
>   Null-check Dereference
       var width = rect.!width
>   Built-in Bindable Maps (coming soon!)
       var fruitMap = ["red" : apple, "yellow" : banana]
       var fruit = bind fruitMap["red"]
                                                            73
Visage and JavaFX 2.0 are made for each other…
>   Enhanced Binding
       Retains lazy evaluation properties with additional expressive power
>   Integrated Collections
       Sequences and Maps automatically convert between JavaFX
        Observable Lists/Maps
>   Built-in Animation Syntax
       Ties into JavaFX animation subsystem
       Provides consistent, clean APIs



                                                                              74
Other JVM Languages to Try
>   JRuby
       Faithful to Ruby language with the power of the JVM
>   Gosu
       Up and coming language created at GuideWire
       Easy to enhance libraries and create DSLs
>   Mirah
       Invented by Charles Nutter
       Local Type Inference, Static and Dynamic Typing
>   Fantom
       Created by Brian and Andy Frank
       Portable to Java and .NET
       Local Type Inference, Static and Dynamic Typing

                                                              75
Conclusion
>   You can write JavaFX applications in pure Java
>   JavaFX is also usable in alternate languages
>   You can get improved support using DSL libraries
       GroovyFX
       ScalaFX
>   Or a dedicated UI JVM Language
       Visage
Stephen Chin
                                                            stephen.chin@oracle.com
                                                            tweet: @steveonjava




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

More Related Content

What's hot

Java FX 2.0 - A Developer's Guide
Java FX 2.0 - A Developer's GuideJava FX 2.0 - A Developer's Guide
Java FX 2.0 - A Developer's Guide
Stephen Chin
 
JavaFX and Scala in the Cloud
JavaFX and Scala in the CloudJavaFX and Scala in the Cloud
JavaFX and Scala in the Cloud
Stephen 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 189
Mahmoud 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 84
Mahmoud Samir Fayed
 
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
 
Beyond Breakpoints: Advanced Debugging with XCode
Beyond Breakpoints: Advanced Debugging with XCodeBeyond Breakpoints: Advanced Debugging with XCode
Beyond Breakpoints: Advanced Debugging with XCode
Aijaz Ansari
 
SDC - Einführung in Scala
SDC - Einführung in ScalaSDC - Einführung in Scala
SDC - Einführung in Scala
Christian Baranowski
 
Backbone.js: Run your Application Inside The Browser
Backbone.js: Run your Application Inside The BrowserBackbone.js: Run your Application Inside The Browser
Backbone.js: Run your Application Inside The Browser
Howard Lewis Ship
 
Zend Framework 1 + Doctrine 2
Zend Framework 1 + Doctrine 2Zend Framework 1 + Doctrine 2
Zend Framework 1 + Doctrine 2
Ralph Schindler
 
Scala in practice
Scala in practiceScala in practice
Scala in practice
andyrobinson8
 
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
Mahmoud Samir Fayed
 
The Ring programming language version 1.9 book - Part 53 of 210
The Ring programming language version 1.9 book - Part 53 of 210The Ring programming language version 1.9 book - Part 53 of 210
The Ring programming language version 1.9 book - Part 53 of 210
Mahmoud Samir Fayed
 
Alternate JVM Languages
Alternate JVM LanguagesAlternate JVM Languages
Alternate JVM Languages
Saltmarch Media
 
Php forum2015 tomas_final
Php forum2015 tomas_finalPhp forum2015 tomas_final
Php forum2015 tomas_final
Bertrand Matthelie
 
The Ring programming language version 1.2 book - Part 35 of 84
The Ring programming language version 1.2 book - Part 35 of 84The Ring programming language version 1.2 book - Part 35 of 84
The Ring programming language version 1.2 book - Part 35 of 84
Mahmoud Samir Fayed
 
Clojure Deep Dive
Clojure Deep DiveClojure Deep Dive
Clojure Deep Dive
Howard Lewis Ship
 
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
BTI360
 
On the Impossibility of Batch Update for Cryptographic Accumulators
On the Impossibility of Batch Update for Cryptographic AccumulatorsOn the Impossibility of Batch Update for Cryptographic Accumulators
On the Impossibility of Batch Update for Cryptographic Accumulators
Philippe Camacho, Ph.D.
 
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
Damien Seguy
 
Xm lparsers
Xm lparsersXm lparsers
Xm lparsers
Suman Lata
 

What's hot (20)

Java FX 2.0 - A Developer's Guide
Java FX 2.0 - A Developer's GuideJava FX 2.0 - A Developer's Guide
Java FX 2.0 - A Developer's Guide
 
JavaFX and Scala in the Cloud
JavaFX and Scala in the CloudJavaFX and Scala in the Cloud
JavaFX and Scala in the Cloud
 
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
 
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
 
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)
 
Beyond Breakpoints: Advanced Debugging with XCode
Beyond Breakpoints: Advanced Debugging with XCodeBeyond Breakpoints: Advanced Debugging with XCode
Beyond Breakpoints: Advanced Debugging with XCode
 
SDC - Einführung in Scala
SDC - Einführung in ScalaSDC - Einführung in Scala
SDC - Einführung in Scala
 
Backbone.js: Run your Application Inside The Browser
Backbone.js: Run your Application Inside The BrowserBackbone.js: Run your Application Inside The Browser
Backbone.js: Run your Application Inside The Browser
 
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
 
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.9 book - Part 53 of 210
The Ring programming language version 1.9 book - Part 53 of 210The Ring programming language version 1.9 book - Part 53 of 210
The Ring programming language version 1.9 book - Part 53 of 210
 
Alternate JVM Languages
Alternate JVM LanguagesAlternate JVM Languages
Alternate JVM Languages
 
Php forum2015 tomas_final
Php forum2015 tomas_finalPhp forum2015 tomas_final
Php forum2015 tomas_final
 
The Ring programming language version 1.2 book - Part 35 of 84
The Ring programming language version 1.2 book - Part 35 of 84The Ring programming language version 1.2 book - Part 35 of 84
The Ring programming language version 1.2 book - Part 35 of 84
 
Clojure Deep Dive
Clojure Deep DiveClojure Deep Dive
Clojure Deep Dive
 
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
 
On the Impossibility of Batch Update for Cryptographic Accumulators
On the Impossibility of Batch Update for Cryptographic AccumulatorsOn the Impossibility of Batch Update for Cryptographic Accumulators
On the Impossibility of Batch Update for Cryptographic Accumulators
 
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
 
Xm lparsers
Xm lparsersXm lparsers
Xm lparsers
 

Viewers also liked

DukeScript
DukeScriptDukeScript
DukeScript
Stephen Chin
 
Internet of Things Magic Show
Internet of Things Magic ShowInternet of Things Magic Show
Internet of Things Magic Show
Stephen Chin
 
Confessions of a Former Agile Methodologist
Confessions of a Former Agile MethodologistConfessions of a Former Agile Methodologist
Confessions of a Former Agile Methodologist
Stephen Chin
 
Java on Raspberry Pi Lab
Java on Raspberry Pi LabJava on Raspberry Pi Lab
Java on Raspberry Pi Lab
Stephen Chin
 
JCrete Embedded Java Workshop
JCrete Embedded Java WorkshopJCrete Embedded Java Workshop
JCrete Embedded Java Workshop
Stephen Chin
 
Raspberry Pi with Java (JJUG)
Raspberry Pi with Java (JJUG)Raspberry Pi with Java (JJUG)
Raspberry Pi with Java (JJUG)
Stephen Chin
 
Raspberry Pi à la GroovyFX
Raspberry Pi à la GroovyFXRaspberry Pi à la GroovyFX
Raspberry Pi à la GroovyFX
Stephen Chin
 
JavaFX GUI architecture with Clojure core.async
JavaFX GUI architecture with Clojure core.asyncJavaFX GUI architecture with Clojure core.async
JavaFX GUI architecture with Clojure core.async
Falko Riemenschneider
 
Zombie Time - JSR 310 for the Undead
Zombie Time - JSR 310 for the UndeadZombie Time - JSR 310 for the Undead
Zombie Time - JSR 310 for the Undead
Stephen Chin
 
Raspberry Pi Gaming 4 Kids - Dutch Version
Raspberry Pi Gaming 4 Kids - Dutch VersionRaspberry Pi Gaming 4 Kids - Dutch Version
Raspberry Pi Gaming 4 Kids - Dutch Version
Stephen Chin
 
Raspberry pi gaming 4 kids
Raspberry pi gaming 4 kidsRaspberry pi gaming 4 kids
Raspberry pi gaming 4 kids
Stephen Chin
 
RetroPi Handheld Raspberry Pi Gaming Console
RetroPi Handheld Raspberry Pi Gaming ConsoleRetroPi Handheld Raspberry Pi Gaming Console
RetroPi Handheld Raspberry Pi Gaming Console
Stephen Chin
 
OpenJFX on Android and Devices
OpenJFX on Android and DevicesOpenJFX on Android and Devices
OpenJFX on Android and Devices
Stephen Chin
 
JavaFX on Mobile (by Johan Vos)
JavaFX on Mobile (by Johan Vos)JavaFX on Mobile (by Johan Vos)
JavaFX on Mobile (by Johan Vos)
Stephen Chin
 
Raspberry Pi Gaming 4 Kids (Devoxx4Kids)
Raspberry Pi Gaming 4 Kids (Devoxx4Kids)Raspberry Pi Gaming 4 Kids (Devoxx4Kids)
Raspberry Pi Gaming 4 Kids (Devoxx4Kids)
Stephen Chin
 
Confessions of a Former Agile Methodologist (JFrog Edition)
Confessions of a Former Agile Methodologist (JFrog Edition)Confessions of a Former Agile Methodologist (JFrog Edition)
Confessions of a Former Agile Methodologist (JFrog Edition)
Stephen Chin
 
Oracle IoT Kids Workshop
Oracle IoT Kids WorkshopOracle IoT Kids Workshop
Oracle IoT Kids Workshop
Stephen Chin
 
Java 8 for Tablets, Pis, and Legos
Java 8 for Tablets, Pis, and LegosJava 8 for Tablets, Pis, and Legos
Java 8 for Tablets, Pis, and Legos
Stephen Chin
 
Devoxx4Kids NAO Workshop
Devoxx4Kids NAO WorkshopDevoxx4Kids NAO Workshop
Devoxx4Kids NAO Workshop
Stephen Chin
 
Devoxx4Kids Lego Workshop
Devoxx4Kids Lego WorkshopDevoxx4Kids Lego Workshop
Devoxx4Kids Lego Workshop
Stephen Chin
 

Viewers also liked (20)

DukeScript
DukeScriptDukeScript
DukeScript
 
Internet of Things Magic Show
Internet of Things Magic ShowInternet of Things Magic Show
Internet of Things Magic Show
 
Confessions of a Former Agile Methodologist
Confessions of a Former Agile MethodologistConfessions of a Former Agile Methodologist
Confessions of a Former Agile Methodologist
 
Java on Raspberry Pi Lab
Java on Raspberry Pi LabJava on Raspberry Pi Lab
Java on Raspberry Pi Lab
 
JCrete Embedded Java Workshop
JCrete Embedded Java WorkshopJCrete Embedded Java Workshop
JCrete Embedded Java Workshop
 
Raspberry Pi with Java (JJUG)
Raspberry Pi with Java (JJUG)Raspberry Pi with Java (JJUG)
Raspberry Pi with Java (JJUG)
 
Raspberry Pi à la GroovyFX
Raspberry Pi à la GroovyFXRaspberry Pi à la GroovyFX
Raspberry Pi à la GroovyFX
 
JavaFX GUI architecture with Clojure core.async
JavaFX GUI architecture with Clojure core.asyncJavaFX GUI architecture with Clojure core.async
JavaFX GUI architecture with Clojure core.async
 
Zombie Time - JSR 310 for the Undead
Zombie Time - JSR 310 for the UndeadZombie Time - JSR 310 for the Undead
Zombie Time - JSR 310 for the Undead
 
Raspberry Pi Gaming 4 Kids - Dutch Version
Raspberry Pi Gaming 4 Kids - Dutch VersionRaspberry Pi Gaming 4 Kids - Dutch Version
Raspberry Pi Gaming 4 Kids - Dutch Version
 
Raspberry pi gaming 4 kids
Raspberry pi gaming 4 kidsRaspberry pi gaming 4 kids
Raspberry pi gaming 4 kids
 
RetroPi Handheld Raspberry Pi Gaming Console
RetroPi Handheld Raspberry Pi Gaming ConsoleRetroPi Handheld Raspberry Pi Gaming Console
RetroPi Handheld Raspberry Pi Gaming Console
 
OpenJFX on Android and Devices
OpenJFX on Android and DevicesOpenJFX on Android and Devices
OpenJFX on Android and Devices
 
JavaFX on Mobile (by Johan Vos)
JavaFX on Mobile (by Johan Vos)JavaFX on Mobile (by Johan Vos)
JavaFX on Mobile (by Johan Vos)
 
Raspberry Pi Gaming 4 Kids (Devoxx4Kids)
Raspberry Pi Gaming 4 Kids (Devoxx4Kids)Raspberry Pi Gaming 4 Kids (Devoxx4Kids)
Raspberry Pi Gaming 4 Kids (Devoxx4Kids)
 
Confessions of a Former Agile Methodologist (JFrog Edition)
Confessions of a Former Agile Methodologist (JFrog Edition)Confessions of a Former Agile Methodologist (JFrog Edition)
Confessions of a Former Agile Methodologist (JFrog Edition)
 
Oracle IoT Kids Workshop
Oracle IoT Kids WorkshopOracle IoT Kids Workshop
Oracle IoT Kids Workshop
 
Java 8 for Tablets, Pis, and Legos
Java 8 for Tablets, Pis, and LegosJava 8 for Tablets, Pis, and Legos
Java 8 for Tablets, Pis, and Legos
 
Devoxx4Kids NAO Workshop
Devoxx4Kids NAO WorkshopDevoxx4Kids NAO Workshop
Devoxx4Kids NAO Workshop
 
Devoxx4Kids Lego Workshop
Devoxx4Kids Lego WorkshopDevoxx4Kids Lego Workshop
Devoxx4Kids Lego Workshop
 

Similar to Hacking JavaFX with Groovy, Clojure, Scala, and Visage

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 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
 
JavaFX Your Way - Devoxx Version
JavaFX Your Way - Devoxx VersionJavaFX Your Way - Devoxx Version
JavaFX Your Way - Devoxx Version
Stephen 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 Languages
Stephen Chin
 
Don't panic in Fortaleza - ScalaFX
Don't panic in Fortaleza - ScalaFXDon't panic in Fortaleza - ScalaFX
Don't panic in Fortaleza - ScalaFX
Alain Béarez
 
JavaFX 2.0 and Alternative Languages
JavaFX 2.0 and Alternative LanguagesJavaFX 2.0 and Alternative Languages
JavaFX 2.0 and Alternative Languages
Stephen Chin
 
Painless Persistence with Realm
Painless Persistence with RealmPainless Persistence with Realm
Painless Persistence with Realm
Christian Melchior
 
Greach, GroovyFx Workshop
Greach, GroovyFx WorkshopGreach, GroovyFx Workshop
Greach, GroovyFx Workshop
Dierk König
 
Scala @ TechMeetup Edinburgh
Scala @ TechMeetup EdinburghScala @ TechMeetup Edinburgh
Scala @ TechMeetup Edinburgh
Stuart Roebuck
 
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
 
JJUG CCC 2011 Spring
JJUG CCC 2011 SpringJJUG CCC 2011 Spring
JJUG CCC 2011 Spring
Kiyotaka Oku
 
Coding in Style
Coding in StyleCoding in Style
Coding in Style
scalaconfjp
 
Scala introduction
Scala introductionScala introduction
Scala introduction
vito jeng
 
ES6(ES2015) is beautiful
ES6(ES2015) is beautifulES6(ES2015) is beautiful
ES6(ES2015) is beautiful
monikagupta18jan
 
Building mobile web apps with Mobello
Building mobile web apps with MobelloBuilding mobile web apps with Mobello
Building mobile web apps with Mobello
Jeong-Geun Kim
 
Introduction to Scala
Introduction to ScalaIntroduction to Scala
Introduction to Scala
Raúl Raja Martínez
 
SVGo workshop
SVGo workshopSVGo workshop
SVGo workshop
Anthony Starks
 
TypeScript Introduction
TypeScript IntroductionTypeScript Introduction
TypeScript Introduction
Dmitry Sheiko
 
ES6 Overview
ES6 OverviewES6 Overview
ES6 Overview
Bruno Scopelliti
 
Emerging Languages: A Tour of the Horizon
Emerging Languages: A Tour of the HorizonEmerging Languages: A Tour of the Horizon
Emerging Languages: A Tour of the Horizon
Alex Payne
 

Similar to Hacking JavaFX with Groovy, Clojure, Scala, and Visage (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 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]
 
JavaFX Your Way - Devoxx Version
JavaFX Your Way - Devoxx VersionJavaFX Your Way - Devoxx Version
JavaFX Your Way - Devoxx Version
 
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
 
Don't panic in Fortaleza - ScalaFX
Don't panic in Fortaleza - ScalaFXDon't panic in Fortaleza - ScalaFX
Don't panic in Fortaleza - ScalaFX
 
JavaFX 2.0 and Alternative Languages
JavaFX 2.0 and Alternative LanguagesJavaFX 2.0 and Alternative Languages
JavaFX 2.0 and Alternative Languages
 
Painless Persistence with Realm
Painless Persistence with RealmPainless Persistence with Realm
Painless Persistence with Realm
 
Greach, GroovyFx Workshop
Greach, GroovyFx WorkshopGreach, GroovyFx Workshop
Greach, GroovyFx Workshop
 
Scala @ TechMeetup Edinburgh
Scala @ TechMeetup EdinburghScala @ TechMeetup Edinburgh
Scala @ TechMeetup Edinburgh
 
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...
 
JJUG CCC 2011 Spring
JJUG CCC 2011 SpringJJUG CCC 2011 Spring
JJUG CCC 2011 Spring
 
Coding in Style
Coding in StyleCoding in Style
Coding in Style
 
Scala introduction
Scala introductionScala introduction
Scala introduction
 
ES6(ES2015) is beautiful
ES6(ES2015) is beautifulES6(ES2015) is beautiful
ES6(ES2015) is beautiful
 
Building mobile web apps with Mobello
Building mobile web apps with MobelloBuilding mobile web apps with Mobello
Building mobile web apps with Mobello
 
Introduction to Scala
Introduction to ScalaIntroduction to Scala
Introduction to Scala
 
SVGo workshop
SVGo workshopSVGo workshop
SVGo workshop
 
TypeScript Introduction
TypeScript IntroductionTypeScript Introduction
TypeScript Introduction
 
ES6 Overview
ES6 OverviewES6 Overview
ES6 Overview
 
Emerging Languages: A Tour of the Horizon
Emerging Languages: A Tour of the HorizonEmerging Languages: A Tour of the Horizon
Emerging Languages: A Tour of the Horizon
 

More from Stephen Chin

DevOps Tools for Java Developers v2
DevOps Tools for Java Developers v2DevOps Tools for Java Developers v2
DevOps Tools for Java Developers v2
Stephen Chin
 
10 Ways Everyone Can Support the Java Community
10 Ways Everyone Can Support the Java Community10 Ways Everyone Can Support the Java Community
10 Ways Everyone Can Support the Java Community
Stephen Chin
 
Java Clients and JavaFX: The Definitive Guide
Java Clients and JavaFX: The Definitive GuideJava Clients and JavaFX: The Definitive Guide
Java Clients and JavaFX: The Definitive Guide
Stephen Chin
 
DevOps Tools for Java Developers
DevOps Tools for Java DevelopersDevOps Tools for Java Developers
DevOps Tools for Java Developers
Stephen Chin
 
Java Clients and JavaFX - Presented to LJC
Java Clients and JavaFX - Presented to LJCJava Clients and JavaFX - Presented to LJC
Java Clients and JavaFX - Presented to LJC
Stephen Chin
 
LUGOD Raspberry Pi Hacking
LUGOD Raspberry Pi HackingLUGOD Raspberry Pi Hacking
LUGOD Raspberry Pi Hacking
Stephen Chin
 
Moving to the Client - JavaFX and HTML5
Moving to the Client - JavaFX and HTML5Moving to the Client - JavaFX and HTML5
Moving to the Client - JavaFX and HTML5
Stephen Chin
 
JavaFX 2 - A Java Developer's Guide (San Antonio JUG Version)
JavaFX 2 - A Java Developer's Guide (San Antonio JUG Version)JavaFX 2 - A Java Developer's Guide (San Antonio JUG Version)
JavaFX 2 - A Java Developer's Guide (San Antonio JUG Version)
Stephen Chin
 
JavaFX 2 Using the Spring Framework
JavaFX 2 Using the Spring FrameworkJavaFX 2 Using the Spring Framework
JavaFX 2 Using the Spring Framework
Stephen Chin
 

More from Stephen Chin (9)

DevOps Tools for Java Developers v2
DevOps Tools for Java Developers v2DevOps Tools for Java Developers v2
DevOps Tools for Java Developers v2
 
10 Ways Everyone Can Support the Java Community
10 Ways Everyone Can Support the Java Community10 Ways Everyone Can Support the Java Community
10 Ways Everyone Can Support the Java Community
 
Java Clients and JavaFX: The Definitive Guide
Java Clients and JavaFX: The Definitive GuideJava Clients and JavaFX: The Definitive Guide
Java Clients and JavaFX: The Definitive Guide
 
DevOps Tools for Java Developers
DevOps Tools for Java DevelopersDevOps Tools for Java Developers
DevOps Tools for Java Developers
 
Java Clients and JavaFX - Presented to LJC
Java Clients and JavaFX - Presented to LJCJava Clients and JavaFX - Presented to LJC
Java Clients and JavaFX - Presented to LJC
 
LUGOD Raspberry Pi Hacking
LUGOD Raspberry Pi HackingLUGOD Raspberry Pi Hacking
LUGOD Raspberry Pi Hacking
 
Moving to the Client - JavaFX and HTML5
Moving to the Client - JavaFX and HTML5Moving to the Client - JavaFX and HTML5
Moving to the Client - JavaFX and HTML5
 
JavaFX 2 - A Java Developer's Guide (San Antonio JUG Version)
JavaFX 2 - A Java Developer's Guide (San Antonio JUG Version)JavaFX 2 - A Java Developer's Guide (San Antonio JUG Version)
JavaFX 2 - A Java Developer's Guide (San Antonio JUG Version)
 
JavaFX 2 Using the Spring Framework
JavaFX 2 Using the Spring FrameworkJavaFX 2 Using the Spring Framework
JavaFX 2 Using the Spring Framework
 

Recently uploaded

Nordic Marketo Engage User Group_June 13_ 2024.pptx
Nordic Marketo Engage User Group_June 13_ 2024.pptxNordic Marketo Engage User Group_June 13_ 2024.pptx
Nordic Marketo Engage User Group_June 13_ 2024.pptx
MichaelKnudsen27
 
GraphRAG for Life Science to increase LLM accuracy
GraphRAG for Life Science to increase LLM accuracyGraphRAG for Life Science to increase LLM accuracy
GraphRAG for Life Science to increase LLM accuracy
Tomaz Bratanic
 
Digital Marketing Trends in 2024 | Guide for Staying Ahead
Digital Marketing Trends in 2024 | Guide for Staying AheadDigital Marketing Trends in 2024 | Guide for Staying Ahead
Digital Marketing Trends in 2024 | Guide for Staying Ahead
Wask
 
20240607 QFM018 Elixir Reading List May 2024
20240607 QFM018 Elixir Reading List May 202420240607 QFM018 Elixir Reading List May 2024
20240607 QFM018 Elixir Reading List May 2024
Matthew Sinclair
 
Cosa hanno in comune un mattoncino Lego e la backdoor XZ?
Cosa hanno in comune un mattoncino Lego e la backdoor XZ?Cosa hanno in comune un mattoncino Lego e la backdoor XZ?
Cosa hanno in comune un mattoncino Lego e la backdoor XZ?
Speck&Tech
 
Webinar: Designing a schema for a Data Warehouse
Webinar: Designing a schema for a Data WarehouseWebinar: Designing a schema for a Data Warehouse
Webinar: Designing a schema for a Data Warehouse
Federico Razzoli
 
Generating privacy-protected synthetic data using Secludy and Milvus
Generating privacy-protected synthetic data using Secludy and MilvusGenerating privacy-protected synthetic data using Secludy and Milvus
Generating privacy-protected synthetic data using Secludy and Milvus
Zilliz
 
National Security Agency - NSA mobile device best practices
National Security Agency - NSA mobile device best practicesNational Security Agency - NSA mobile device best practices
National Security Agency - NSA mobile device best practices
Quotidiano Piemontese
 
Deep Dive: AI-Powered Marketing to Get More Leads and Customers with HyperGro...
Deep Dive: AI-Powered Marketing to Get More Leads and Customers with HyperGro...Deep Dive: AI-Powered Marketing to Get More Leads and Customers with HyperGro...
Deep Dive: AI-Powered Marketing to Get More Leads and Customers with HyperGro...
saastr
 
AI 101: An Introduction to the Basics and Impact of Artificial Intelligence
AI 101: An Introduction to the Basics and Impact of Artificial IntelligenceAI 101: An Introduction to the Basics and Impact of Artificial Intelligence
AI 101: An Introduction to the Basics and Impact of Artificial Intelligence
IndexBug
 
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
名前 です男
 
Best 20 SEO Techniques To Improve Website Visibility In SERP
Best 20 SEO Techniques To Improve Website Visibility In SERPBest 20 SEO Techniques To Improve Website Visibility In SERP
Best 20 SEO Techniques To Improve Website Visibility In SERP
Pixlogix Infotech
 
Programming Foundation Models with DSPy - Meetup Slides
Programming Foundation Models with DSPy - Meetup SlidesProgramming Foundation Models with DSPy - Meetup Slides
Programming Foundation Models with DSPy - Meetup Slides
Zilliz
 
UiPath Test Automation using UiPath Test Suite series, part 6
UiPath Test Automation using UiPath Test Suite series, part 6UiPath Test Automation using UiPath Test Suite series, part 6
UiPath Test Automation using UiPath Test Suite series, part 6
DianaGray10
 
Driving Business Innovation: Latest Generative AI Advancements & Success Story
Driving Business Innovation: Latest Generative AI Advancements & Success StoryDriving Business Innovation: Latest Generative AI Advancements & Success Story
Driving Business Innovation: Latest Generative AI Advancements & Success Story
Safe Software
 
Energy Efficient Video Encoding for Cloud and Edge Computing Instances
Energy Efficient Video Encoding for Cloud and Edge Computing InstancesEnergy Efficient Video Encoding for Cloud and Edge Computing Instances
Energy Efficient Video Encoding for Cloud and Edge Computing Instances
Alpen-Adria-Universität
 
How to use Firebase Data Connect For Flutter
How to use Firebase Data Connect For FlutterHow to use Firebase Data Connect For Flutter
How to use Firebase Data Connect For Flutter
Daiki Mogmet Ito
 
Recommendation System using RAG Architecture
Recommendation System using RAG ArchitectureRecommendation System using RAG Architecture
Recommendation System using RAG Architecture
fredae14
 
Taking AI to the Next Level in Manufacturing.pdf
Taking AI to the Next Level in Manufacturing.pdfTaking AI to the Next Level in Manufacturing.pdf
Taking AI to the Next Level in Manufacturing.pdf
ssuserfac0301
 
Columbus Data & Analytics Wednesdays - June 2024
Columbus Data & Analytics Wednesdays - June 2024Columbus Data & Analytics Wednesdays - June 2024
Columbus Data & Analytics Wednesdays - June 2024
Jason Packer
 

Recently uploaded (20)

Nordic Marketo Engage User Group_June 13_ 2024.pptx
Nordic Marketo Engage User Group_June 13_ 2024.pptxNordic Marketo Engage User Group_June 13_ 2024.pptx
Nordic Marketo Engage User Group_June 13_ 2024.pptx
 
GraphRAG for Life Science to increase LLM accuracy
GraphRAG for Life Science to increase LLM accuracyGraphRAG for Life Science to increase LLM accuracy
GraphRAG for Life Science to increase LLM accuracy
 
Digital Marketing Trends in 2024 | Guide for Staying Ahead
Digital Marketing Trends in 2024 | Guide for Staying AheadDigital Marketing Trends in 2024 | Guide for Staying Ahead
Digital Marketing Trends in 2024 | Guide for Staying Ahead
 
20240607 QFM018 Elixir Reading List May 2024
20240607 QFM018 Elixir Reading List May 202420240607 QFM018 Elixir Reading List May 2024
20240607 QFM018 Elixir Reading List May 2024
 
Cosa hanno in comune un mattoncino Lego e la backdoor XZ?
Cosa hanno in comune un mattoncino Lego e la backdoor XZ?Cosa hanno in comune un mattoncino Lego e la backdoor XZ?
Cosa hanno in comune un mattoncino Lego e la backdoor XZ?
 
Webinar: Designing a schema for a Data Warehouse
Webinar: Designing a schema for a Data WarehouseWebinar: Designing a schema for a Data Warehouse
Webinar: Designing a schema for a Data Warehouse
 
Generating privacy-protected synthetic data using Secludy and Milvus
Generating privacy-protected synthetic data using Secludy and MilvusGenerating privacy-protected synthetic data using Secludy and Milvus
Generating privacy-protected synthetic data using Secludy and Milvus
 
National Security Agency - NSA mobile device best practices
National Security Agency - NSA mobile device best practicesNational Security Agency - NSA mobile device best practices
National Security Agency - NSA mobile device best practices
 
Deep Dive: AI-Powered Marketing to Get More Leads and Customers with HyperGro...
Deep Dive: AI-Powered Marketing to Get More Leads and Customers with HyperGro...Deep Dive: AI-Powered Marketing to Get More Leads and Customers with HyperGro...
Deep Dive: AI-Powered Marketing to Get More Leads and Customers with HyperGro...
 
AI 101: An Introduction to the Basics and Impact of Artificial Intelligence
AI 101: An Introduction to the Basics and Impact of Artificial IntelligenceAI 101: An Introduction to the Basics and Impact of Artificial Intelligence
AI 101: An Introduction to the Basics and Impact of Artificial Intelligence
 
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
 
Best 20 SEO Techniques To Improve Website Visibility In SERP
Best 20 SEO Techniques To Improve Website Visibility In SERPBest 20 SEO Techniques To Improve Website Visibility In SERP
Best 20 SEO Techniques To Improve Website Visibility In SERP
 
Programming Foundation Models with DSPy - Meetup Slides
Programming Foundation Models with DSPy - Meetup SlidesProgramming Foundation Models with DSPy - Meetup Slides
Programming Foundation Models with DSPy - Meetup Slides
 
UiPath Test Automation using UiPath Test Suite series, part 6
UiPath Test Automation using UiPath Test Suite series, part 6UiPath Test Automation using UiPath Test Suite series, part 6
UiPath Test Automation using UiPath Test Suite series, part 6
 
Driving Business Innovation: Latest Generative AI Advancements & Success Story
Driving Business Innovation: Latest Generative AI Advancements & Success StoryDriving Business Innovation: Latest Generative AI Advancements & Success Story
Driving Business Innovation: Latest Generative AI Advancements & Success Story
 
Energy Efficient Video Encoding for Cloud and Edge Computing Instances
Energy Efficient Video Encoding for Cloud and Edge Computing InstancesEnergy Efficient Video Encoding for Cloud and Edge Computing Instances
Energy Efficient Video Encoding for Cloud and Edge Computing Instances
 
How to use Firebase Data Connect For Flutter
How to use Firebase Data Connect For FlutterHow to use Firebase Data Connect For Flutter
How to use Firebase Data Connect For Flutter
 
Recommendation System using RAG Architecture
Recommendation System using RAG ArchitectureRecommendation System using RAG Architecture
Recommendation System using RAG Architecture
 
Taking AI to the Next Level in Manufacturing.pdf
Taking AI to the Next Level in Manufacturing.pdfTaking AI to the Next Level in Manufacturing.pdf
Taking AI to the Next Level in Manufacturing.pdf
 
Columbus Data & Analytics Wednesdays - June 2024
Columbus Data & Analytics Wednesdays - June 2024Columbus Data & Analytics Wednesdays - June 2024
Columbus Data & Analytics Wednesdays - June 2024
 

Hacking JavaFX with Groovy, Clojure, Scala, and Visage

  • 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  JFXtras  ScalaFX Motorcyclist  Visage > User Group Co-Leader  Silicon Valley JavaFX User Group  Streamed Live!
  • 3. Safe Harbor Statement The following is intended to outline our general product direction. It is intended for information purposes only, and may not be incorporated into any contract. It is not a commitment to deliver any material, code, or functionality, and should not be relied upon in making purchasing decisions. The development, release, and timing of any features or functionality described for Oracle’s products remains at the sole discretion of Oracle.
  • 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.
  • 6. Programming Languages > JavaFX 2.0 APIs are now in Java  Pure Java APIs for all of JavaFX  Binding and Sequences exposed as Java APIs  FXML Markup for tooling > Embrace all JVM languages  Groovy, Scala, Clojure, JRuby  Fantom, Mira, Gosu, Jython, etc. > JavaFX Script is no longer supported by Oracle  Existing JavaFX Script based applications will continue to run  Visage is the open-source successor to the JavaFX Script language
  • 8. 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++) { 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)); 40 Lines 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); 1299 Characters 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(); } } 8
  • 9. 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…] } }
  • 10. 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); } 10
  • 11. Setup Binding circle.strokeWidthProperty().bind(Bindings .when(circle.hoverProperty()) .then(4) .otherwise(0) ); 11
  • 12. 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(); } }); 12
  • 13. 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(); 13
  • 15. Features of Groovy > Modern language  Closures  AST Transforms  Strongly typed dynamic language > Tight integration with Java  Very easy to port from Java to Groovy > Declarative syntax with GroovyFX Builders  Familiar to Groovy and JavaFX Script developers
  • 16. 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 -> 29 Lines final Circle circle = new Circle(150); timeline { 40 Lines 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)); } } at(3.s) { change e.source.radiusProperty() to 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(); } } 671 Characters 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(); } } 16
  • 17. 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) } } } } } 17
  • 18. GroovyFX.start { primaryStage -> def sg = new SceneGraphBuilder() def rand = new Random().&nextInt def circles = [] Builder for GroovyFX scene graphs 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) } } } } } 18
  • 19. 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) } } } } } 19
  • 20. 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) } } } } } 20
  • 21. 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) } } } } } 21
  • 22. GroovyFX.start { primaryStage -> def sg = new SceneGraphBuilder() def rand = new Random().&nextInt def circles = [] sg.stage(title: 'Vanishing Circles', show: Sequence Creation Via Loop 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) } } } } } 22
  • 23. 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() 23
  • 24. 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} 24
  • 25. 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 25
  • 26. 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 26
  • 27. 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() } 27
  • 28. 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} 28
  • 29. 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() } 29
  • 30. But wait, there is more Grooviness… 30
  • 31. 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. } } 31
  • 32. Properties in GroovyFX public class Person { @FXBindable String firstName; @FXBindable String lastName; } 32
  • 33. Properties in GroovyFX public class Person { @FXBindable String firstName; @FXBindable String lastName = “Smith”; } Optional initializers 33
  • 34. 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); 34
  • 35. 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) }) } 35
  • 36. 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); 36
  • 37. 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") } } } 37
  • 39. 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") } 39
  • 42. JavaFX With Clojure Artwork by Augusto Sellhorn http://sellmic.com/ 42
  • 43. 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! 43
  • 44. 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) 44
  • 45. 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) 45
  • 46. Refined Clojure GUI Example (defn javafxapp [] (doto (Stage. "JavaFX Stage") (.setWidth 600) (.setHeight 450) (.setScene (doto (Scene.) (.setFill Color/LIGHTGREEN) (.setContent (list (doto (Rectangle.) (.setX 25) (.setY 40) (.setWidth 100) (.setHeight 50) (.setFill Color/RED)))))) (.setVisible true))) (javafxapp) 46
  • 47. 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) 47
  • 48. 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))))) 48
  • 49. 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))))) 49
  • 51. 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 51
  • 52. 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) final Circle circle = new Circle(150); effect = new BoxBlur(10, 10, 3) 40 Lines 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)); 33 Lines strokeWidth <== when (hover) then 4 otherwise 0 stroke = WHITE onMouseClicked = { 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(); } } 52
  • 53. 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) } } } } 53
  • 54. object VanishingCircles extends JFXApp { stage = new Stage { title = "Disappearing Circles" width = 800 height Base class for JavaFX applications = 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) } } } } 54
  • 55. 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) } } } } 55
  • 56. 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) } } } } 56
  • 57. 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) } } } } 57
  • 58. 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" 58
  • 59. 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(); 59
  • 60. 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(); 60
  • 61. 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 61
  • 62. 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 62
  • 63. 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() } 63
  • 64. 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} 64
  • 65. 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() } 65
  • 66. 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)}, } )} 66
  • 68. About Project Visage > “Visage is a domain specific language (DSL) designed for the express purpose of writing user interfaces.” > Visage project goals:  Compile to JavaFX Java APIs  Evolve the Language (Annotations, Maps, etc.)  Support Other Toolkits > Come join the team! > For more info: http://visage-lang.org/ 68
  • 69. 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 final Circle circle = new Circle(150); fill: color(random(), random(), random(), .2) 40 Lines 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)); 35 Lines effect: BoxBlur { height: 10 width: 10 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(); } } 69
  • 70. 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 } } } } } 70
  • 71. 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 } } } } } 71
  • 72. 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 } } } } } 72
  • 73. Visage is JavaFX Script++ > Default Parameters > New Literal Syntax For:  Angles – 35deg, 4rad, 1turn  Colors – #DDCCBB, #AA33AA|CC  Lengths – 5px, 2pt, 3in, 4sp > Null-check Dereference  var width = rect.!width > Built-in Bindable Maps (coming soon!)  var fruitMap = ["red" : apple, "yellow" : banana]  var fruit = bind fruitMap["red"] 73
  • 74. Visage and JavaFX 2.0 are made for each other… > Enhanced Binding  Retains lazy evaluation properties with additional expressive power > Integrated Collections  Sequences and Maps automatically convert between JavaFX Observable Lists/Maps > Built-in Animation Syntax  Ties into JavaFX animation subsystem  Provides consistent, clean APIs 74
  • 75. Other JVM Languages to Try > JRuby  Faithful to Ruby language with the power of the JVM > Gosu  Up and coming language created at GuideWire  Easy to enhance libraries and create DSLs > Mirah  Invented by Charles Nutter  Local Type Inference, Static and Dynamic Typing > Fantom  Created by Brian and Andy Frank  Portable to Java and .NET  Local Type Inference, Static and Dynamic Typing 75
  • 76. Conclusion > You can write JavaFX applications in pure Java > JavaFX is also usable in alternate languages > You can get improved support using DSL libraries  GroovyFX  ScalaFX > Or a dedicated UI JVM Language  Visage
  • 77. Stephen Chin stephen.chin@oracle.com tweet: @steveonjava Thanks to Dean Iverson and Jonathan Giles for help preparing this talk 77

Editor's Notes

  1. Stage.add??
  2. Stage.add??