+ All Categories
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!


Top Related