1. JavaFX Your Way
Building JavaFX Applications with Alternative Languages
Stephen Chin
GXS
steveonjava@gmail.com
tweet: @steveonjava
Jonathan Giles
Oracle
Jonathan.giles@oracle.com
tweet: @jonathangiles
6. THE FOLLOWING IS INTENDED TO OUTLINE ORACLE’S 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 DECISION. THE
DEVELOPMENT, RELEASE, AND TIMING OF ANY FEATURES OR
FUNCTIONALITY DESCRIBED FOR ORACLE'S PRODUCTS REMAINS
AT THE SOLE DISCRETION OF ORACLE.
9. Agenda
> JavaFX 2.0 Announcement
> JavaFX in Java
> Explore alternative languages
JRuby
Clojure
Groovy
Scala
+???
10. JavaFX 2.0 Announcement
• JavaFX Script is no longer required to write
JavaFX applications
• Benefits:
– Easier integration with business logic on JVM
– Access to generics, annotations, (closures), etc
– Java has great IDE support
• Downsides:
– JavaFX Script was kind to us
12. JavaFX in Java
> JavaFX API follows JavaBeans approach
> Similar in feel to other UI toolkits (Swing, etc.)
> Researching approaches to minimize boilerplate
13. Binding
> Unquestionably the biggest JavaFX Script
innovation
> Will be supported via a PropertyBinding class
> Lazy invocation for high performance
> Static construction syntax for simple cases
e.g.: bindTo(<property>)
14. Observable Pseudo-Properties
> Supports watching for changes to properties
> Implemented via anonymous inner classes
> Will take advantage of closures in the future
15. Observable Pseudo-Properties
Rectangle rect = new Rectangle();
rect.setX(40);
rect.setY(40);
rect.setWidth(100);
rect.setHeight(200);
rect.addChangedListener(Rectangle.HOVER, new Listener() {
});
16. Observable Pseudo-Properties
Rectangle rect = new Rectangle();
rect.setX(40);
rect.setY(40);
rect.setWidth(100);
rect.setHeight(200);
rect.addChangedListener(Rectangle.HOVER, new Listener() {
});
The property we want to watch
17. Observable Pseudo-Properties
Rectangle rect = new Rectangle();
rect.setX(40);
rect.setY(40);
rect.setWidth(100);
rect.setHeight(200);
rect.addChangedListener(Rectangle.HOVER, new Listener() {
});
Only one listener used
regardless of data type
18. Observable Pseudo-Properties
Rectangle rect = new Rectangle();
rect.setX(40);
rect.setY(40);
rect.setWidth(100);
rect.setHeight(200);
rect.addChangedListener(Rectangle.HOVER, new Listener() {
public void handle(Bean bean, PropertyReference pr) {
}
});
Rectangle is a Bean
19. Observable Pseudo-Properties
Rectangle rect = new Rectangle();
rect.setX(40);
rect.setY(40);
rect.setWidth(100);
rect.setHeight(200);
rect.addChangedListener(Rectangle.HOVER, new Listener() {
public void handle(Bean bean, PropertyReference pr) {
}
});
Refers to the
Rectangle.hover ‘property’
20. Observable Pseudo-Properties
Rectangle rect = new Rectangle();
rect.setX(40);
rect.setY(40);
rect.setWidth(100);
rect.setHeight(200);
rect.addChangedListener(Rectangle.HOVER, new Listener() {
public void handle(Bean bean, PropertyReference pr) {
rect.setFill(rect.isHover() ? Color.GREEN : Color.RED);
}
});
21. 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 will also have an Observable Map
22. Example Application
public class HelloStage implements Runnable {
public void run() {
Stage stage = new Stage();
stage.setTitle("Hello Stage");
stage.setWidth(600);
stage.setHeight(450);
Scene scene = new Scene();
scene.setFill(Color.LIGHTGREEN);
stage.setScene(scene);
stage.setVisible(true);
}
public static void main(String[] args) {
FX.start(new HelloStage());
}
}
23. Summary
> The JVM has a modern UI toolkit coming to it
> Total port to Java – no hacks or kludges
> Many languages to choose from
> Alternate languages == exciting possibilities
> Choose the best language for your needs
24. Major Question
24
How can alternative languages make developing
JavaFX user interfaces easier & more productive?
33. A Little About Clojure
> Started in 2007 by Rich Hickey
> Functional Programming Language
> Derived from LISP
> Optimized for High Concurrency
> … and looks nothing like Java!
33
(def hello (fn [] "Hello world"))
(hello)
34. Clojure Syntax in One Slide
Symbols
> numbers – 2.178
> ratios – 355/113
> strings – “clojure”, “rocks”
> characters – a b c d
> symbols – a b c d
> keywords – :alpha :beta
> boolean – true, false
> null - nil
Collections
(commas optional)
> Lists
(1, 2, 3, 4, 5)
> Vectors
[1, 2, 3, 4, 5]
> Maps
{:a 1, :b 2, :c 3, :d 4}
> Sets
#{:a :b :c :d :e}
34
(plus macros that are syntactic sugar wrapping the above)
46. Closures in Clojure
46
> Inner classes can be created using proxy
(.addChangeListener rect Rectangle/HOVER
(proxy [BooleanListener] []
(handle [b, p, o]
(.setFill rect
(if (.isHover rect) Color/GREEN Color/RED)))))
47. Closures in Clojure
> Inner classes can be created using proxy
47
(.addChangeListener rect Rectangle/HOVER
(proxy [Listener] []
(handle [b, p]
(.setFill rect
(if (.isHover rect) Color/GREEN Color/RED)))))
Proxy form:
(proxy [class] [args] fs+)
f => (name [params*] body)
49. Features of Groovy
> Tight integration with Java
Very easy to port from Java to Groovy
> Declarative syntax
Familiar to JavaFX Script developers
> Builders
53. Slight Aside: Groovy Builders
> Groovy builders make writing custom DSLs easy
> For the next slide, I am using a builder I defined
> Hopefully the community will improve upon this
63. 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
2010
• Scala 2.8.0 (latest)
63
64. 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 DSLs!
64
65. Java vs. Scala DSL
public class HelloStage implements Runnable {
public void run() {
Stage stage = new Stage();
stage.setTitle("Hello Stage");
stage.setWidth(600);
stage.setHeight(450);
Scene scene = new Scene();
scene.setFill(Color.LIGHTGREEN);
Rectangle rect = new Rectangle();
rect.setX(25);
rect.setY(40);
rect.setWidth(100);
rect.setHeight(50);
rect.setFill(Color.RED);
stage.add(rect);
stage.setScene(scene);
stage.setVisible(true);
}
public static void main(String[] args) {
FX.start(new HelloStage());
}
}
object HelloJavaFX extends JavaFXApplication {
def stage = new Stage {
title = "Hello Stage"
width = 600
height = 450
scene = new Scene {
fill = Color.LIGHTGREEN
content = List(new Rectangle {
x = 25
y = 40
width = 100
height = 50
fill = Color.RED
})
}
}
}
65
22 Lines
545 Characters
17 Lines
324 Characters
66. object HelloJavaFX extends JavaFXApplication {
def stage = new Stage {
title = "Hello Stage"
width = 600
height = 450
scene = new Scene {
fill = Color.LIGHTGREEN
content = List(new Rectangle {
x = 25
y = 40
width = 100
height = 50
fill = Color.RED
})
}
}
}
66
67. 67
object HelloJavaFX extends JavaFXApplication {
def stage = new Stage {
title = "Hello Stage"
width = 600
height = 450
scene = new Scene {
fill = Color.LIGHTGREEN
content = List(new Rectangle {
x = 25
y = 40
width = 100
height = 50
fill = Color.RED
})
}
}
}
object HelloJavaFX extends JavaFXApplication {
def stage = new Stage {
title = "Hello Stage"
width = 600
height = 450
scene = new Scene {
fill = Color.LIGHTGREEN
content = List(new Rectangle {
x = 25
y = 40
width = 100
height = 50
fill = Color.RED
})
}
}
}
Base class for JavaFX
applications
68. 68
object HelloJavaFX extends JavaFXApplication {
def stage = new Stage {
title = "Hello Stage"
width = 600
height = 450
scene = new Scene {
fill = Color.LIGHTGREEN
content = List(new Rectangle {
x = 25
y = 40
width = 100
height = 50
fill = Color.RED
})
}
}
}
Declarative Stage
definition
69. 69
object HelloJavaFX extends JavaFXApplication {
def stage = new Stage {
title = "Hello Stage"
width = 600
height = 450
scene = new Scene {
fill = Color.LIGHTGREEN
content = List(new Rectangle {
x = 25
y = 40
width = 100
height = 50
fill = Color.RED
})
}
}
}
Inline property
definitions
70. 70
object HelloJavaFX extends JavaFXApplication {
def stage = new Stage {
title = "Hello Stage"
width = 600
height = 450
scene = new Scene {
fill = Color.LIGHTGREEN
content = List(new Rectangle {
x = 25
y = 40
width = 100
height = 50
fill = Color.RED
})
}
}
}
List Construction
Syntax
71. Animation in Scala
def timeline = new Timeline {
repeatCount = INDEFINITE
autoReverse = true
keyFrames = List(
new KeyFrame(50) {
values = List(
new KeyValue(rect1.x() -> 300),
new KeyValue(rect2.y() -> 500),
new KeyValue(rect2.width() -> 150)
)
}
)
}
71
72. Animation in Scala
72
Duration set by
Constructor Parameter
def timeline = new Timeline {
repeatCount = INDEFINITE
autoReverse = true
keyFrames = List(
new KeyFrame(50) {
values = List(
new KeyValue(rect1.x() -> 300),
new KeyValue(rect2.y() -> 500),
new KeyValue(rect2.width() -> 150)
)
}
)
}
73. Animation in Scala
73
Operator overloading for
animation syntax
def timeline = new Timeline {
repeatCount = INDEFINITE
autoReverse = true
keyFrames = List(
new KeyFrame(50) {
values = List(
new KeyValue(rect1.x() -> 300),
new KeyValue(rect2.y() -> 500),
new KeyValue(rect2.width() -> 150)
)
}
)
}
74. Closures in Scala
74
> Closures are also supported in Scala
> And they are 100% type-safe
rect.addChangedListener(Node.HOVER, (b, p, o) => {
rect.fill = if (rect.hover) Color.GREEN else Color.RED
})
75. Closures in Scala
> Closures are also supported in Scala
> And they are 100% type-safe
75
rect.addChangedListener(Node.HOVER, (b, p) => {
rect.fill = if (rect.hover) Color.GREEN else Color.RED
})
Compact syntax
(params) => {body}
rect.addChangedListener(Node.HOVER, (b, p) => {
rect.fill = if (rect.hover) Color.GREEN else Color.RED
})
76. Other JVM Languages to Try
> Jython
Started by Jim Hugunin
High Performance Python
> Mirah
Invented by Charles Nutter
Originally called Duby
Local Type Inference, Static and Dynamic Typing
> Fantom
Created by Brian and Andy Frank
Originally called Fan
Built-in Declarative Syntax
Portable to Java and .NET
Local Type Inference, Static and Dynamic Typing
76
77. Fantom Code Example
Void main() {
Stage {
title = "Hello Stage"
width = 600
height = 450
Scene {
fill = Color.LIGHTGREEN
Rectangle {
x = 25
y = 40
width = 100
height = 50
fill = Color.RED
}
}
}.open
}
77
78. timeline := Timeline {
repeatCount = Timeline.INDEFINITE
autoReverse = true
KeyFrame {
time = 50ms
KeyValue(rect1.x() -> 300),
KeyValue(rect2.y() -> 500),
KeyValue(rect2.width() -> 150)
}
}
Animation in Fantom
78
Fantom has a built-in
Duration type
And also supports
operator overloading
79. Announcing Project Visage
79
> 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/
> “Visage is a domain specific language (DSL)
designed for the express purpose of writing
user interfaces.”
81. Visage Android Workshop
Today @ 21:00 – 22:00
Room: BOF 2
Description:
Bring your Android device and learn how to build
and deploy Android market applications using the
Visage language.
Prizes will be awarded for finding defects
and helping the dev team make Visage
better.
81
82. Conclusion
> JavaFX as Java APIs is great
> Usable in alternate languages
> Over time improved support is possible
Groovy Builders, Scala DSL, Visage
Remember: This is a proof of concept only – you
can not leave this session and do this today.
There are two kinds of listener: ‘changedListener’ and ‘ChangingListener’. Being informed of the change before it happens allow for it to be vetoed.
It is also possible to either watch a single property, or all properties belonging to a bean.
Note that the value passed to the callback is the old value. This is to ensure that we aren’t eagerly computing the new value when it might not be required. To get the new value, you can call the function on the bean or via the propertyReference
There are two kinds of listener: ‘changedListener’ and ‘ChangingListener’. Being informed of the change before it happens allow for it to be vetoed.
It is also possible to either watch a single property, or all properties belonging to a bean.
Note that the value passed to the callback is the old value. This is to ensure that we aren’t eagerly computing the new value when it might not be required. To get the new value, you can call the function on the bean or via the propertyReference
There are two kinds of listener: ‘changedListener’ and ‘ChangingListener’. Being informed of the change before it happens allow for it to be vetoed.
It is also possible to either watch a single property, or all properties belonging to a bean.
Note that the value passed to the callback is the old value. This is to ensure that we aren’t eagerly computing the new value when it might not be required. To get the new value, you can call the function on the bean or via the propertyReference
There are two kinds of listener: ‘changedListener’ and ‘ChangingListener’. Being informed of the change before it happens allow for it to be vetoed.
It is also possible to either watch a single property, or all properties belonging to a bean.
Note that the value passed to the callback is the old value. This is to ensure that we aren’t eagerly computing the new value when it might not be required. To get the new value, you can call the function on the bean or via the propertyReference
There are two kinds of listener: ‘changedListener’ and ‘ChangingListener’. Being informed of the change before it happens allow for it to be vetoed.
It is also possible to either watch a single property, or all properties belonging to a bean.
Note that the value passed to the callback is the old value. This is to ensure that we aren’t eagerly computing the new value when it might not be required. To get the new value, you can call the function on the bean or via the propertyReference
There are two kinds of listener: ‘changedListener’ and ‘ChangingListener’. Being informed of the change before it happens allow for it to be vetoed.
It is also possible to either watch a single property, or all properties belonging to a bean.
Note that the value passed to the callback is the old value. This is to ensure that we aren’t eagerly computing the new value when it might not be required. To get the new value, you can call the function on the bean or via the propertyReference
There are two kinds of listener: ‘changedListener’ and ‘ChangingListener’. Being informed of the change before it happens allow for it to be vetoed.
It is also possible to either watch a single property, or all properties belonging to a bean.
Note that the value passed to the callback is the old value. This is to ensure that we aren’t eagerly computing the new value when it might not be required. To get the new value, you can call the function on the bean or via the propertyReference
Slight conversion to Groovy. This can be compiled by the Groovy compiler and run, but basically there is only one line difference (the ‘static void main’ line)
This is the same code as the previous slide, taking advantage of some of the Groovy syntax tricks. This is getting to look a lot more like JavaFX Script.
This DSL handles running on the EDT, and can actually be run as-is – there is no need for a class declaration, or anything else to ensure that we’re on the EDT. This is getting us fairly close to the simple JavaFX Script at the beginning
This DSL handles running on the EDT, and can actually be run as-is – there is no need for a class declaration, or anything else to ensure that we’re on the EDT. This is getting us fairly close to the simple JavaFX Script at the beginning