+ All Categories
Home > Technology > JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

Date post: 12-May-2015
Category:
Upload: stephen-chin
View: 52,088 times
Download: 0 times
Share this document with a friend
Description:
JavaFX 2.0 is the next version of a revolutionary rich client platform for developing immersive desktop applications. One of the new features in JavaFX 2.0 is a set of pure Java APIs that can be used from any JVM language, opening up tremendous possibilities. This presentation demonstrates the benefits of using JavaFX 2.0 together with the Scala programming language to provide a type-safe declarative syntax with support for lazy bindings and collections. Advanced language features, such as DelayedInit and @specialized will be discussed, as will ways of forcing prioritization of implicit conversions for n-level cases. Those who survive the pure technical geekiness of this talk will be rewarded with plenty of JavaFX UI eye candy.
Popular Tags:
52
JavaFX 2.0 and Scala, Like Milk and Cookies Stephen Chin Chief Agile Methodologist, GXS [email protected] m tweet: @steveonjava
Transcript
Page 1: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

JavaFX 2.0 and Scala, Like Milk and Cookies Stephen Chin

Chief Agile Methodologist, [email protected]: @steveonjava

Page 2: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

Meet the Presenter

> Chief Agile Methodologist, GXS

> Java Champion> Open Source Hacker

JFXtras ScalaFX Visage

> User Group Leader Silicon Valley JavaFX User

Group Streamed Live!

Stephen Chin

Motorcyclist

Family Man

Page 3: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

JavaFX 2.0 Platform

Immersive Application Experience

> 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.

Page 4: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

Programming Languages

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

Page 5: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

5

JavaFX

Scala

Page 6: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

JavaFX With Java

Page 7: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

JavaFX in Java

> JavaFX API uses an enhanced JavaBeans pattern

> Similar in feel to other UI toolkits (Swing, Pivot, etc.)

> Uses builder pattern to minimize boilerplate

Page 8: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

Example Application

public class HelloStage extends Application {

@Override public void start(Stage stage) { stage.setTitle("Hello Stage"); stage.setWidth(600); stage.setHeight(450);

Group root = new Group(); Scene scene = new Scene(root); scene.setFill(Color.LIGHTGREEN);

stage.setScene(scene); stage.show(); }

public static void main(String[] args) { Application.launch(args); }}

Page 9: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

Example Application Using Builders

public class HelloStage extends Application {

@Override public void start(Stage stage) { stage.setTitle("Hello Stage"); stage.setScene(SceneBuilder.create() .fill(Color.LIGHTGREEN) .width(600) .height(450) .build()); stage.show(); }

public static void main(String[] args) { Application.launch(args); }}

Page 10: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

Observable Properties

> Supports watching for changes to properties

> Implemented via anonymous inner classes

> Will take advantage of closures in the future

Page 11: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

Observable Pseudo-Properties

final Rectangle rect = new Rectangle();rect.setX(40);rect.setY(40);rect.setWidth(100);rect.setHeight(200);

rect.hoverProperty().addListener(new ChangeListener<Boolean>() {

});

Page 12: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

Observable Pseudo-Properties

final Rectangle rect = new Rectangle();rect.setX(40);rect.setY(40);rect.setWidth(100);rect.setHeight(200);

rect.hoverProperty().addListener(new ChangeListener<Boolean>() {

});

The property we want to watch

Page 13: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

Observable Pseudo-Properties

final Rectangle rect = new Rectangle();rect.setX(40);rect.setY(40);rect.setWidth(100);rect.setHeight(200);

rect.hoverProperty().addListener(new ChangeListener<Boolean>() {

});

Only one listener used with generics to specify the data type

Page 14: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

Observable Pseudo-Properties

final Rectangle rect = new Rectangle();rect.setX(40);rect.setY(40);rect.setWidth(100);rect.setHeight(200);

rect.hoverProperty().addListener(new ChangeListener<Boolean>() { public void changed(ObservableValue<? extends Boolean> property, Boolean oldValue, Boolean value) {

}});

Refers to the Rectangle.hoverProperty()

Page 15: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

Observable Pseudo-Properties

final Rectangle rect = new Rectangle();rect.setX(40);rect.setY(40);rect.setWidth(100);rect.setHeight(200);

rect.hoverProperty().addListener(new ChangeListener<Boolean>() { public void changed(ObservableValue<? extends Boolean> property, Boolean oldValue, Boolean value) { rect.setFill(rect.isHover() ? Color.GREEN : Color.RED); }});

Page 16: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

Binding

> Unquestionably the biggest JavaFX Script innovation

> Supported via a PropertyBinding class> Lazy invocation for high performance> Static construction syntax for simple

cases e.g.: bind(<property>),

bindBiDirectional(<property>)

Page 17: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

Sequences in Java

> Replaced with an Observable List

> Public API is based on JavaFX sequences

> Internal code can use lighter collections API

> JavaFX 2.0 also has an Observable Map

Page 18: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

18

Vanishing Circles

Page 19: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

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…] }}

Page 20: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

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

20

Page 21: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

Setup Binding

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

21

Page 22: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

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

22

Page 23: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

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

23

Page 24: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

24

JavaFX With Scala

Page 25: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

25

What is Scala

> Started in 2001 by Martin Odersky> Compiles to Java bytecodes> Pure object-oriented language> Also a functional programming language

2001• Scala Started

2003/2004• Scala v1.0

2006• Scala v2.0

2011• Scala 2.9.1

2012• Scala 2.9.1-1

(latest)

Page 26: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

26

Why Scala?

> Shares many language features with JavaFX Script that make GUI programming easier: Static Type Checking – Catch your errors at compile

time Closures – Wrap behavior and pass it by reference Declarative – Express the UI by describing what it

should look like

> Scala also supports Type Safe DSLs! Implicit Conversions – type safe class extension Operator Overloading – with standard precedence

rules

Page 27: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

Java vs. Scala DSLpublic 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)); circle.setEffect(new BoxBlur(10, 10, 3)); circle.addEventHandler(MouseEvent.MOUSE_CLICKED, new

EventHandler<MouseEvent>() { public void handle(MouseEvent t) { KeyValue collapse = new KeyValue(circle.radiusProperty(), 0); new Timeline(new KeyFrame(Duration.seconds(3), collapse)).play(); } }); circle.setStroke(Color.WHITE);

circle.strokeWidthProperty().bind(Bindings.when(circle.hoverProperty()) .then(4) .otherwise(0)); circles.add(circle); } root.getChildren().addAll(circles); primaryStage.setScene(scene); primaryStage.show(); Timeline moveCircles = new Timeline(); for (Circle circle : circles) { KeyValue moveX = new KeyValue(circle.centerXProperty(), Math.random()

* 800); KeyValue moveY = new KeyValue(circle.centerYProperty(), Math.random()

* 600); moveCircles.getKeyFrames().add(new KeyFrame(Duration.seconds(40),

moveX, moveY)); } moveCircles.play(); }}

object VanishingCircles extends JFXApp { var circles: Seq[Circle] = null stage = new Stage { title = "Vanishing Circles" width = 800 height = 600 scene = new Scene { fill = BLACK circles = for (i <- 0 until 50) yield new Circle { centerX = random * 800 centerY = random * 600 radius = 150 fill = color(random, random, random, .2) effect = new BoxBlur(10, 10, 3) strokeWidth <== when (hover) then 4 otherwise 0 stroke = WHITE onMouseClicked = { Timeline(at (3 s) {radius -> 0}).play() } } content = circles } }

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

27

40 Lines1299 Characters

33 Lines591 Characters

Page 28: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

object VanishingCircles extends JFXApp { stage = new Stage { title = "Disappearing Circles" width = 800 height = 600 scene = new Scene { fill = BLACK content = 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) } } }}

28

Page 29: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

29

object VanishingCircles extends JFXApp { stage = new Stage { title = "Disappearing Circles" width = 800 height = 600 scene = new Scene { fill = BLACK content = 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) } } }}

Base class for JavaFX applications

Page 30: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

30

object VanishingCircles extends JFXApp { stage = new Stage { title = "Disappearing Circles" width = 800 height = 600 scene = new Scene { fill = BLACK content = 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) } } }}

Declarative Stage definition

Page 31: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

31

object VanishingCircles extends JFXApp { stage = new Stage { title = "Disappearing Circles" width = 800 height = 600 scene = new Scene { fill = BLACK content = 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) } } }}

Inline property definitions

Page 32: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

32

object VanishingCircles extends JFXApp { stage = new Stage { title = "Disappearing Circles" width = 800 height = 600 scene = new Scene { fill = BLACK content = 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) } } }}

Sequence Creation Via Loop

Page 33: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

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"

33

Page 34: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

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

34

Page 35: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

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

Animation in Scala

35

JavaFX Script-like animation syntax: at (duration) {keyframes}

Page 36: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

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

Animation in Scala

36

Operator overloading for animation syntax

Page 37: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

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

Animation in Scala

37

Optional tween syntax

Page 38: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

Event Listeners in Scala

38

> Supported using the built-in Closure syntax> Optional arguments for event objects> 100% type-safe

onMouseClicked = { Timeline(at(3 s){radius->0}).play()

}

Page 39: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

Event Listeners in Scala

> Supported using the built-in Closure syntax> Optional arguments for event objects> 100% type-safe

39

Compact syntax{body}

onMouseClicked = { Timeline(at(3 s){radius->0}).play()

}

Page 40: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

Event Listeners in Scala

> Supported using the built-in Closure syntax> Optional arguments for event objects> 100% type-safe

40

Optional event parameter

{(event) => body}

onMouseClicked = { (e: MouseEvent) =>

Timeline(at(3 s){radius->0}).play()

}

Page 41: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

a.k.a. How to Write Your Own Scala DSL

41

ScalaFX Internals

With quotes from Stephen Colebourne (@jodastephen) to help us keep our sanity!Disclaimer: Statements taken from http://blog.joda.org and may not accurately reflect his opinion or viewpoint.

Luc Viatour / www.Lucnix.be

Page 42: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

42

Application Initialization

> JavaFX Requires all UI code executed on the Application Thread

> But our ScalaFX Application has no start method:

object VanishingCircles extends JFXApp {

stage = new Stage { … }}

How Does This Code Work?!?

Page 43: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

43

DelayedInit

> Introduced in Scala 2.9> How to Use It:1. Extend a special trait called DelayedInit2. Implement a method of type:

def delayedInit(x: => Unit): Unit3. Store off the init closure and call it on the

Application Thread

For me, Scala didn't throw enough away and added too much - a lethal combination.

Joda says…

Page 44: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

Hierarchical Implicit Conversions

> ScalaFX defines a set of proxies that mirror the JavaFX hierarchy

> JavaFX classes are "implicitly" wrapped when you call a ScalaFX API

> But Scala implicit priority ignores type hierarchy!

44

JFXNode

JFXShape

JFXCircle

SFXNode

SFXShape

SFXCircle

?

!

Page 45: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

N-Level Implicit Precedence

> Scala throws an exception if two implicits have the same precedence

> Classes that are extended have 1 lower precedence:

> You can stack extended traits n-levels deep to reduce precision by n

45

Well, it may be type safe, but its also silent and very deadly.

Joda says…

object HighPriorityIncludes extends LowerPriorityIncludes {…}trait LowerPriorityIncludes {…}

Page 46: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

Properties

> JavaFX supports properties of type Boolean, Integer, Long, Float, Double, String, and Object

> Properties use Generics for type safety> But generics don't support primitives…

> JavaFX solves this with 20 interfaces and 44 classes for all the type/readable/writable combinations.

> Can we do better?

46

Page 47: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

@specialized

> Special annotation that generates primitive variants of the class

> Improves performance by avoiding boxing/unboxing

> Cuts down on code duplication (ScalaFX only has 18 property/value classes total)

47

Whatever the problem, the type system is bound to be part of the solution.

Joda says…

trait ObservableValue[@specialized(Int, Long, Float, Double, Boolean) T, J]

Page 48: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

Bindings

48

> How does Scala know what order to evaluate this in?

text <== when (rect.hover || circle.hover && !disabled) then textField.text + " is enabled" otherwise "disabled

And why the funky bind operator?!?

Page 49: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

Operator Precedence Rules

49

> First Character Determines Precedence

Highest Precedence

10. (all letters)9. |8. ^7. &6. < >5. = !4. :3. + *2. / %1. (all other special characters)

Lowest Precedence

11. Assignment Operators end with equal> But don't start with equal> And cannot be one of:

<= >= !=

Exception Assignment Operators, which are even lower…

Page 50: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

Operator Precedence

50

Personally, I find the goal of the open and flexible syntax (arbitrary DSLs) to be not worth the pain

Joda says…

text <== when (rect.hover || circle.hover

&& !disabled) then textField.text + " is

enabled" otherwise "disabled"

911 10

7 105 3

10

Page 51: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

Conclusion

> You can use Scala and JavaFX together.> ScalaFX provides cleaner APIs that are tailor

designed for Scala.> Try using ScalaFX today and help contribute APIs

for our upcoming 1.0 release!

http://code.google.com/p/scalafx/

Page 52: JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)

52

Stephen [email protected]: @steveonjava

Pro JavaFX 2 Platform Available Now!


Recommended