Gerrit Grunwald - jug-ostfalen.deA!"#$% history scene graph Java API properties Bindings controls...

117

Transcript of Gerrit Grunwald - jug-ostfalen.deA!"#$% history scene graph Java API properties Bindings controls...

GerritGrunwaldcanoo  Engineering  AG

Twitter: @hansolo_ blog: harmonic-code.org

A!"#$%✴ history✴ scene graph✴ Java API✴ properties✴ Bindings

✴ controls✴ css✴ WebView✴ JFXPanel✴ charts

S&'"

History

R&%$'%(

W)%*

Java FXr"%++, -....

I* -. *)" ./00"..&r *&

Java Swing

%#$ -*'. .*-++ #&*

finished

Av%-+%b+" f&r✴ Windows✴ Mac os x✴ Linux✴ ARM *

* preview

Av%-+%b+" f&r✴ Apple ios*✴ Android*

* preview

V"r.-&#.✴ JavaFX 2.2 Bundled with jdk

>Java 7u6✴ Standalone for Java6*

* Windows only

1" %r0)-*"0*/r"

1" %r0)-*"0*/r"

Prism processes the rendering jobs.

1" %r0)-*"0*/r"

OpenGL on Mac, Linux, Embedded

1" %r0)-*"0*/r"

DirectX 9 on Windows XP, VistaDirectX 11 on Windows 7

1" %r0)-*"0*/r"

Java2D when hardware acceleration is not possible

1" %r0)-*"0*/r"

Provides low level native operatingsystem services

1" %r0)-*"0*/r"

Ties Prism and Glass Windowing Toolkit together and makes them available to the JavaFX layer above

1" %r0)-*"0*/r"

A!%-# % #"w

plugin

Br&w."r P+/!-#✴ Faster loading of JavaFX

web apps based on prism

✴ pre-loader for improved user experience

1"

scene graph

C&++"0*-&# &f

Nodes

S0"#" Gr%()✴ Handles the UI✴ tree structure✴ has one root node✴ Branch + leaf nodes

S0"#" Gr%()root

branch

leaf

✴ The Only node without a parent node

R&&* N&$"

Br%#0) N&$".✴ are derived from

javafx.scene.Parent

✴ can contain other nodes

L"%f N&$".✴ Shapes✴ Images✴ Text✴ WebView

✴ Media✴ Controls✴ Charts

L"%f N&$".✴ Have no

getChildren()

1" N&$".Node

(abstract)

Parent(abstract)

Control(abstract)

resizable, skinnable + CSS stylable

Group

non- resizable

Region

resizable + CSS stylable

Pane TabPane TitledPane SplitPane Accordian ToolBar

StackPane HBox VBox TilePane FlowPane AnchorPane BorderPane GridPane

I# J%v%F2

Stage

Branch Node

Leaf Node

S(""$ +-'-*

60 fps

S0"#" Gr%()✴ root node is a Parent✴ stage is container for root✴ alive...no dead bitmaps

public class SceneGraphStructure extends Application { @Override public void start(Stage stage) { stage.setTitle("Hello World"); Button button = new Button("Say 'Hello World'"); button.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent evt) { System.out.println("Hello World"); } }); StackPane root = new StackPane(); root.getChildren().add(button); stage.setScene(new Scene(root, 300, 250)); stage.show(); }

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

}

A *3-0%+ %((

S0"#" Gr%()

S*%r* J%v%F2 %((+-0%*-&#

1"

JavaA(-

J%v%F2 S0r-(* -.

DEADnot

I* +-v". &# %.

Visage

N&w w" )%v"

pure Java

S&'"

examples

// Java FX 1.xpublic def timer = Timeline { repeatCount: Timeline.INDEFINITE keyframes: KeyFrame { time: 1s action: function() {...}}}

C&$" 4%'(+".// Java FX 2.xprivate Timeline timer = TimelineBuilder.create() .cycleCount(Timeline.INDEFINITE) .keyFrames( new KeyFrame(Duration.seconds(1), new EventHandler() {...} )) .build();

// Java FX 1.xview = ImageView { image:image translateX:bind x + (view.scaleX - 1) translateY:bind y + (view.scaleY - 1)};

C&$" 4%'(+".// Java FX 2.xview = new ImageView(image);view.translateXProperty().bind( x.add(view.getScaleX() - 1));view.translateYProperty().bind( y.add(view.getScaleY() - 1));

Pr&("r*-". %#$

bindings

// Property stringprivate static final String VALUE_PROPERTY = "value";

// A double propertyprivate double value = 0;

// The getter methodpublic double getValue() { return value;}

// The setter methodpublic void setValue(double newValue) { double oldValue = value; value = newValue;

firePropertyChange(VALUE_PROPERTY, oldValue, value);}

Pr&("r*-".J%v% Sw-#!

// A double propertyprivate DoubleProperty value = new SimpleDoubleProperty(0);

// The getter methodpublic double getValue() { return value.get();}

// The setter methodpublic void setValue(double newValue) { value.set(newValue);}

// The property methodpublic DoubleProperty valueProperty() { return value;}

Pr&("r*-".J%v%F2

// A double propertyDoubleProperty value;

// The getter methodpublic double getValue() { return value.get();}

// The setter methodpublic void setValue(double newValue) { value.set(newValue);}

// The property methodpublic DoubleProperty valueProperty() { return value;}

Pr&("r*-".J%v%F2

B-#$-#!.✴ High-level binding

✴ fluent api✴ bindings class

✴ low-level binding

B-#$-#!.✴ unidirectional binding

bind();

✴ bidirectional bindingbindBidirectional();

IntegerProperty number1 = new SimpleIntegerProperty(1);IntegerProperty number2 = new SimpleIntegerProperty(2);DoubleProperty number3 = new SimpleDoubleProperty(0.5);

// High-Level Binding (Fluent API)NumberBinding sum1 = number1.add(number2);

NumberBinding result1 = number1.add(number2).multiply(number3);

// High-Level Binding (Binding class)NumberBinding sum2 = Bindings.add(number1, number2);

NumberBinding result2 = Bindings.add(number1, multiply(number2, number3));

H-!)-L"v"+

H-!)-L"v"+✴ Fluent api is selfexplaining✴ more readable code✴ might be a bit slower

IntegerProperty number1 = new SimpleIntegerProperty(1);IntegerProperty number2 = new SimpleIntegerProperty(2);DoubleProperty number3 = new SimpleDoubleProperty(0.5);

// Low-Level BindingDoubleBinding db = new DoubleBinding() { { super.bind(number1, number2, number3); }

@Override protected double computeValue() { return (number1.get() + number2.get() * number3.get()); }}

L&w-L"v"+

L&w-L"v"+✴ Overrides a binding class✴ is more flexible✴ could be faster

J%v%F2

controls

S&'"

examples

C&#*r&+ .*r/0*/r"✴ Control✴ Skin✴ Behavior✴ css

C&#*r&+ B")%v-&r

S5-#CSS

S*,+-#! w-*)

css

R"'"'b"rLook + Feels

-# Sw-#! ?

F&r!"* *)"'...

U.-#! CSS✴ One default css caspian.css

for root and controls✴ JavaFX css is based on w3C

CSS 2.1 + some additions

U.-#! CSS✴ either override the

defaults to style your app✴ or apply your own css file

.root { -fx-base : #d0d0d0; -fx-background : #f4f4f4; -fx-color : -fx-base; -fx-hover-base : ladder(-fx-base, derive(-fx-base, 20%) 20%, derive(-fx-base, 30%) 35%, derive(-fx-base, 40%) 50%); -fx-pressed-base: derive(-fx-base, -20%); -fx-focused-base: -fx-base; -fx-body-color : linear-gradient(to bottom, derive(-fx-color, 34%) 0%, derive(-fx-color, -18%) 100%); ...

1" C%.(-%#.0..

.button { -fx-skin : "com.sun.javafx.scene.control.skin.ButtonSkin"; -fx-background-color : -fx-shadow-highlight-color, -fx-outer-border, -fx-inner-border, -fx-body-color; -fx-background-insets: 0 0 -1 0, 0, 1, 2; -fx-background-radius: 5, 5, 4, 3; -fx-padding : 0.166667em 0.833333em 0.25em 0.833333em; -fx-text-fill : -fx-text-base-color; -fx-alignment : CENTER; -fx-content-display : LEFT;}

1" $"f%/+* CSS

.root { -fx-base: #252525; /* scene.getRoot().setStyle("-fx-base: #252525"); */}

.button { -fx-font-family : "Verdana"; -fx-font-size : 16px; -fx-background-radius: 9, 9, 8, 7; -fx-padding : 9px 16px 9px 16px;}

1" 0/.*&' CSS

A .-'(+" %((

C%.(-%# S*,+"r

Scene scene = new Scene(pane, Color.rgb(75, 75, 75));scene.getStylesheets().add("file:///customStylesheet.css");

A((+, .&'" CSS

.root { -fx-font-family : "Verdana"; -fx-font-size : 13.0px; -fx-base : #363636; -fx-background : #5C5C5C; -fx-focus-color : #FF001B; -fx-control-inner-background: #DCDCDC; -fx-inner-border : linear-gradient(to bottom, derive(-fx-color, 90.23825953613186%) 0%, derive(-fx-color, 17.136566353587632%) 100%); -fx-body-color : linear-gradient(to bottom, derive(-fx-color, 45.81081081081081%) 0%, derive(-fx-color, -9.603603603603602%) 100%);}.button { -fx-background-radius : 30, 30, 29, 28; -fx-padding : 7px 14px 7px 14px;}.label { -fx-padding : 7px 22px 7px 14px;}.label { -fx-padding : 7px 8px 7px 10px;}.text-field { -fx-padding : 7px 10px 7px 10px;}.label { -fx-text-fill : -fx-text-background-color;}.button { -fx-background-insets : 0 0 -1 0, 0, 3, 4;}.button:focused { -fx-background-insets : -1.4, 0, 3, 4;}.separator:horizontal .line { -fx-border-color : derive(-fx-background, -80%) transparent transparent transparent;}

A .-'(+" %((

W"bV-"w %#$

webengine

Scene

NODEGroup

NODE

webview

Scene

WEBENGINEWebKit

W"bV-"w✴ extension of node✴ encapsulates webengine✴ incorporates html into

the scene

W"bE#!-#"✴ provides webpage function✴ supports user interaction✴ enables dom access and js

stage.setTitle("WebView");

WebView browser = new WebView();WebEngine engine = browser.getEngine();engine.load("http://harmonic-code.org");

StackPane pane = new StackPane();pane.getChildren().add(browser);stage.setScene(new Scene(pane, 980, 720));stage.show();

W"bV-"w

InteractionW)%* %b&/*

w-*) H*'+5Interacts

H&w J%v%F2

<head>! <title>MyPage</title> ! <script type="text/javascript"> var gauge; ... </script>...

I#*"r%0*-&#

WebView browser = new WebView();WebEngine engine = browser.getEngine();engine.load("http://mypage.html");

// JavaFX interact with WebViewengine.executeScript("gauge.setValue(5)");

I#*"r%0*-&#

w-*) J%v%F2Interacts

H&w H*'+5

L-.*"# *&

DOM events

<!DOCTYPE html><html><head> <meta charset=“utf-8“>! <title>MyPage</title> </head> ! <body> <button id=“buttonId“>Click me</button> </body></html>

I#*"r%0*-&#

// WebView interact with JavaFX (Part I: Document Events)engine.getLoadWorker().stateProperty().addListener(new ChangeListener<State>() { @Override public void changed(ObservableValue<? extends State> ov, State old, State now) { if (newState == State.SUCCEEDED) { Document doc = (Document) engine.executeScript(“document“); EventTarget button = (EventTarget) document.getElementById(“buttonId“); button.addEventListener(“click“, new DocEventListener(), true); } } });

private static class DocEventListener implements EventListener { @Override public void handleEvent(Event event) { System.out.println(“Event received: “ + event.getType()); }}

I#*"r%0*-&#

L-.*"# *&

Status

<!DOCTYPE html><html><head> <meta charset=“utf-8“> <title>MyPage</title> <script type=“text/javascript“> function setStatus(id) { window.status = id; } </script></head> ! <body> <button id=“buttonId“>Click me</button> </body></html>

I#*"r%0*-&#

// WebView interact with JavaFX (Part II: via window.status)engine.getLoadWorker().stateProperty().addListener(new ChangeListener<State>() { @Override public void changed(ObservableValue<? extends State> ov, State old, State now) { if (newState == State.SUCCEEDED) { engine.setOnStatusChanged(new EventHandler<WebEvent<String>>() { @Override public void handle(WebEvent<String> event) { // Get the window.status value System.out.println(“Status value: “ + event.getData()); } }); } }});

I#*"r%0*-&#

I#6"0* %

JSObject

// WebView interact with JavaFX (Part II: via window.status)class Bridge { public void exit() { Platform.exit(); }}

...

// Inject the JSObject with the name "java" into the html pageJSObject jsobj = (JSObject) webEngine.executeScript("window");jsobj.setMember("java", new Bridge());

...

// Remove the JSObject againJSObject.removeMember();

JSOb6"0*

<!DOCTYPE html><html><head> <meta charset=“utf-8“> <title>Close JavaFX from HTML</title> <script type=“text/javascript“> function closeJavaFXProgram() { java.exit(); } </script></head> ! <body> <button onclick=“closeJavaFXProgram()“>Close Java</button> </body></html>

JSOb6"0*

M-!r%*-#! w-*)

JFXpanel

is it ?W)%*

✴ B")%v". +-5" JP%#"+✴ H7*. % J%v%F2 S0"#"✴ F&rw%r$. "v"#*.✴ S)&/+$ b" %00".."$

fr&' *)" E$*

w&r5 ?doeZ itH&w

// Add a JFXPanel to a Swing JFrameJFrame frame = new JFrame("JFXPanel");JFXPanel fxPanel = new JFXPanel();frame.add(fxPanel);

Platform.runLater(new Runnable() { @Override public void run() { initFX(fxPanel); }});

Cr"%*-&#

// Initialize the JFXPanelvoid initFX(JFXPanel fxPanel) {

// Code to create a JavaFX scene ...

fxPanel.setScene(scene);}

I#-*-%+8%*-&#

-# Sw-#!...java FXS& ,&/ 0&/+$ /."

-# Sw-#!html 5...'"%#. %+.&

-# '-#$keep

B/*

Y&/ )%v"

ui-threads2

I*'. /( *& ,&/ *&

*)"' '%#/%+,syncronize

J%v%F2

charts

Pie

Bubble

AreaBar

Line

Scatter

J%v%F2 C)%r*.✴ Can be animated

✴ can be styled using css

✴ can be customized

@Override public void start(Stage stage) { Scene scene = new Scene(new Group(), 500, 500); stage.setTitle("Imported fruits");

ObservableList<PieChart.Data> pieChartData = FXCollections.observableArrayList( new PieChart.Data("Grapefruit", 13), new PieChart.Data("Oranges", 25), new PieChart.Data("Plums", 10), new PieChart.Data("Pears", 22), new PieChart.Data("Apples", 30)); final PieChart chart = new PieChart(pieChartData); chart.setTitle("Imported Fruits");

((Group) scene.getRoot()).getChildren().add(chart); stage.setScene(scene); stage.show();}

Cr"%*-#! % P-"0)%r*

N""$ '&r"

controls ?

)"r" ,&/ !&

jfxtras

S&'"

examples

the party ?you wanna be part of

JFXTRASWe want you at

W)%*'. #"w -#

Java FX 8

J%v%F2 8✴ support for Embedded✴ 3D support ✴ Swing-Node ( hopefully )

✴ public api for controls✴ Performance++✴ no focus on plugin anymore

K""( 0&$-#!...