Top Banner
Thierry Wasylczenko @twasyl #JavaFX.forReal() martine fait du code
96
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: #JavaFX.forReal()

Thierry Wasylczenko

@twasyl

#JavaFX.forReal()martine fait du code

Page 2: #JavaFX.forReal()

Disclaimer

Swing lovers won’t be hurt and no beard or mustach will be shaved.

You will maybe discover new technologies or concepts. Don’t be

afraid.

The presentation of technologies are not promotional.

SlideshowFX is my own open source project and will only be used as

an example of implementations of technologies presented.

2

Page 3: #JavaFX.forReal()

presentation.agenda()public class Presentation extends Application {

public void init() { Speaker.load("twasyl"); }

public void start(Stage stage) {

JavaFX.getVersion(8).load();

new ScriptEngineManager().getEngineByName("nashorn");

Bundle.deploy("OSGi");

Markups.stream().filter(m -> m.name.equals("asciidoctor")));

vertx.createHttpServer().listen(8080, "localhost");

leapMotionController.isConnected();

}

public void stop() { Speaker.shutdown("twasyl"); }

}

3

Page 4: #JavaFX.forReal()

4

Page 5: #JavaFX.forReal()

5

Page 6: #JavaFX.forReal()

Pourquoi le OuestFX tour?

Un espagnol breton perdu en Normandie nous refait l'histoire des ihm en java c'est @LostInBrittany au @normandyjug 8:03 PM - 14 Oct 2014

Yann PETIT @finalspy

Follow

2 RETWEETS 1 FAVORITE

6

Page 7: #JavaFX.forReal()

Pourquoi le OuestFX tour?

@finalspy @LostInBrittany @normandyjug Il a parlé #JavaFX au moins?Thierry Wasylczenko @twasyl

@twasyl @finalspy @normandyjug #javafx ? Moi j'ai fait du vrai client lourd, j'ai fait du #swing :p9:33 AM - 15 Oct 2014 Paris, Ile-de-France, France

Horacio Gonzalez @LostInBrittany

Follow

1 RETWEET

15 Oct

7

Page 8: #JavaFX.forReal()

8

Page 9: #JavaFX.forReal()

#JavaFX 8

9

Page 10: #JavaFX.forReal()

<2 />

<8>

Page 11: #JavaFX.forReal()

FXML

Page 12: #JavaFX.forReal()

FXML - the easy one<BorderPane xmlns:fx="http://javafx.com/fxml"> <top> <MenuBar> <Menu text="File"> <MenuItem text="Quit" /> </Menu> </MenuBar> </top> <center> <FlowPane> <Button text="Show" /> <Button text="more" /> </FlowPane> </center></BorderPane>

12

Page 13: #JavaFX.forReal()

FXML - the controller

• The backend of FXML

• Associated to the view

public class MyController implements Initializable {

// Some interesting things to code

@Override

public void initialize(URL url, ResourceBundle resourceBundle)

// Some other interesting things to code !

}

}

13

Page 14: #JavaFX.forReal()

FXML + controller

<BorderPane fx:controller="com.SuperController">

<center>

<Button text="Click !" fx:id="myButton"

onAction="#doSomething" />

</center>

</BorderPane>

public class SuperController implements Initializable {

@FXML private Button myButton;

@FXML private void doSomething(ActionEvent e) {}

}

14

Page 15: #JavaFX.forReal()

FXML - fx:define

<BorderPane fx:controller="com.SuperController">

<fx:define>

<Double fx:id="MY_DOUBLE" fx:value="20.0" />

</fx:define>

<center>

<TextField text="$MY_DOUBLE" />

</center>

</BorderPane>

15

Page 16: #JavaFX.forReal()

FXML - fx:factory

...

<ComboBox promptText="IP address">

<items><NetworkUtils fx:factory="getObservableIPs" /></items>

</ComboBox>

...

public class NetworkUtils {

public static ObservableList<String> getObservableIPs() {

/* ... */

}

}

16

Page 17: #JavaFX.forReal()

FXML - fx:reference

<BorderPane fx:controller="com.SuperController">

<fx:define>

<TabPane fx:id="myTabPane" />

<FXCollections fx:id="myList" fx:factory="observableArrayList"

<fx:reference source="myTabPane" />

</FXCollections>

</fx:define>

<center>

<fx:reference source="myTabPane" />

</center>

</BorderPane>

17

Page 18: #JavaFX.forReal()

Customization

Page 19: #JavaFX.forReal()

• CSS

• Inline

• Stylesheets

• Programmatically

• Custom pseudo state

• A component’s type = a CSS class

• Button   .button

• TextField   .text-field

• ...

Customization 19

Page 20: #JavaFX.forReal()

Customization - CSS

<AnchorPane>

<stylesheets>

<URL value="@/path/of/your/stylesheet.css" />

</stylesheets>

<Button text="Button 1" style="-fx-background-color: red" />

<Button text="Button 2" class="my-super-class" />

</AnchorPane>

button1.setStyle("-fx-text-fill: white");

button2.getStyleClass().add("my-super-class");

20

Page 21: #JavaFX.forReal()

Customization - Pseudo state

PseudoClass ps = PseudoClass.getPseudoClass("awesome");

myButton.pseudoClassStateChanged(ps, true);

.button:awesome {

-fx-text-fill: orange;

}

#myButton:awesome {

-fx-text-fill: green;

}

21

Page 22: #JavaFX.forReal()

• Fully customized UI

• CSS already known

• Specifities

• Not always that easy

CustomizationREX

22

Page 23: #JavaFX.forReal()

Properties

Page 24: #JavaFX.forReal()

Properties - types

IntegerProperty intP = new SimpleIntegerProperty();

DoubleProperty doubleP = new SimpleDoubleProperty();

// ...

BooleanProperty booleanP = new SimpleBooleanProperty();

StringProperty stringP = new SimpleStringProperty();

ObjectProperty<Conference> objectP = new SimpleObjectProperty<>();

24

Page 25: #JavaFX.forReal()

Properties - binding

IntegerProperty intP1 = new SimpleIntegerProperty();

IntegerProperty intP2 = new SimpleIntegerProperty();

intP1.bind(intP2);

intP2.set(10);

System.out.println("And P1? " + intP1.get());

25

Page 26: #JavaFX.forReal()

Properties - binding

IntegerProperty intP1 = new SimpleIntegerProperty();

IntegerProperty intP2 = new SimpleIntegerProperty();

intP1.bindBidirectional(intP2);

intP2.set(10);

System.out.println("And P1? " + intP1.get());

intP1.set(20);

System.out.println("And P2? " + intP2.get());

26

Page 27: #JavaFX.forReal()

Properties - Events

IntegerProperty intP1 = new SimpleIntegerProperty();

intP1.addListener((valueInt, oldInt, newInt) -> {

System.out.println("Change");

});

intP1.set(10);

27

Page 28: #JavaFX.forReal()

Properties - POJO 2.0

public class Conference {

private StringProperty name = new SimpleStringProperty();

public StringProperty nameProperty() { return this.name; }

public String getName() { return this.name.get(); }

public void setName(String name) { this.name.set(name); }

}

final Conference jug = new Conference();

tf.textProperty().bindBidirectional(jug.nameProperty());

28

Page 29: #JavaFX.forReal()

Not serializable

Page 30: #JavaFX.forReal()

Properties - POJO 1.5

public class Conference {

private PropertyChangeStatus pcs =

new PropertyChangeStatus(this);

private String name;

public void addPropertyChangeListener(PropertyChangeListener listener)

this.pcs.addPropertyChangeListener(listener);

}

public void removePropertyChangeListener(PropertyChangeListener listener)

this.pcs.removePropertyChangeListener(listener);

}

30

Page 31: #JavaFX.forReal()

Properties - POJO 1.5

public class Conference {

// ...

public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener)

this.pcs.addPropertyChangeListener(propertyName, listener);

}

public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener)

this.pcs.removePropertyChangeListener(propertyName, listener);

}

// ...

}

31

Page 32: #JavaFX.forReal()

Properties - POJO 1.5

public class Conference {

// ...

public String getName() { return this.name; }

public void setName(String name) {

final String old = this.name;

this.name = name;

this.pcs.firePropertyChange("name", old, this.name);

}

}

32

Page 33: #JavaFX.forReal()

Properties - POJO 1.5

final Conference jug = new Conference();

JavaBeanStringPropertyBuilder builder = new ...

JavaBeanStringProperty nameProperty = builder.bean(jug)

.name("name")

.build();

nameProperty.addListener((valueName, oldIName, newName) -> {

// ...

});

33

Page 34: #JavaFX.forReal()

Controls

Page 35: #JavaFX.forReal()

ImageView

Page 36: #JavaFX.forReal()

ImageView - FXML

<ImageView>

<image>

<Image url="@/path/to/my-image.png" preserveRatio="true"

smooth="true" backgroundLoading="true"

requestedHeight="20" requestedWidth="20" />

</image>

</ImageView>

36

Page 37: #JavaFX.forReal()

ImageView - Java

final URL url = ...

final InputStream stream = ...

final Image image1 = new Image(url, true);

final Image image2 = new Image(stream);

final ImageView view = new ImageView(image1);

• Prefer the Image contructor with a URL

37

Page 38: #JavaFX.forReal()

WebView

Page 39: #JavaFX.forReal()

WebView - the State

final WebView browser = new WebView();

browser.getEngine().stateProperty().addListener((stateValue, oldState, newState) -> {

if(newState == Worker.State.SUCCEEDED) {

final Element div = browser.getEngine().getDocument()

.getElementById("twasyl");

if(div != null) {

div.getTextContent();

}

}

});

39

Page 40: #JavaFX.forReal()

WebView - interact with events

• When the page sends event:

webEngine.setOnAlert(event -> { /* ... */ } );

webEngine.setOnError(event -> { /* ... */ } );

webEngine.setPromptHandler(event -> { /* ... */ } );

40

Page 41: #JavaFX.forReal()

• WebHistory

• int getMaxSize()

• ObservableList<WebHistory.Entry>

getEntries()

• WebHistory.Entry

• Date getLastVisitedDate()

• String getTitle()

• String getUrl()

WebView - history 41

Page 42: #JavaFX.forReal()

• Stylesheet inheritance

• HTML buttons inherit from JavaFX

buttons

• ...

• Performance

WebViewREX

42

Page 43: #JavaFX.forReal()

TableView

Page 44: #JavaFX.forReal()

TableView - basics

@FXML private TableView<Conference> confs;

@Override public void initialize(URL location, ResourceBundle bundle)

final Conference conf1 = new Conference("BreizhJUG");

final Conference conf2 = new Conference("NantesJUG");

final Conference conf3 = new Conference("NormandyJUG");

this.confs.getItems().addAll(conf1, conf2, conf3);

}

44

Page 45: #JavaFX.forReal()

TableView - display an image 1/3

public class ImageCell extends TableCell<Conference, Image> {

protected void updateItem(Image item, boolean empty) {

if(!empty && item != null) {

final ImageView view = new ImageView(item);

setGraphic(view);

} else {

setGraphic(null);

}

}

}

45

Page 46: #JavaFX.forReal()

TableView - display an image 2/3

public class ImageCellFactory implements

Callback<TableColumn<Conference, Image>,

TableCell<Conference, Image>> {

@Override

public TableCell<Conference, Image> call(TableColumn<Conference, Image> param) {

final TableCell<Conference, Image> cell =

new ImageCell<Conference, Image>();

return cell;

}

}

46

Page 47: #JavaFX.forReal()

TableView - display an image 3/3

@FXML private TableView<Conference> confs;

@Override public void initialize(URL location, ResourceBundle bundle)

final TableColumn<Conference, Image> logoColumn =

new TableColumn<>("Logo");

logoColumn.setCellValueFactory(

new PropertyValueFactory<Conference, Image>("logo")

);

logoColumn.setCellFactory(new ImageCellFactory());

this.confs.getColumns().add(logoColumn);

}

47

Page 48: #JavaFX.forReal()

TableView - FXML

<TableView fx:id="confs">

<columns>

<TableColumn text="Logo">

<cellValueFactory>

<PropertyValueFactory property="logo" />

</cellValueFactory>

<cellFactory> <ImageCellFactory /> </cellFactory>

</TableColumn>

</columns>

</TableView>

48

Page 49: #JavaFX.forReal()

Concurrency

Page 50: #JavaFX.forReal()

• Questions:

1. How to not block my UI when I

download a file ?

2. How to work with the file when

download is done ?

• javafx.concurrent

• Worker

• Task

• Service

• ScheduledService

concurrency.setTricky(true) 50

Page 51: #JavaFX.forReal()

• Implements Worker

• Task#updateMessage(String)

• Task#updateProgress(long,long)

• Task#get() // blocking

• Task#getValue() // non-blocking

• Task#succeeded()

• Task#running()

• Task#failed()

• Task#cancelled()

• Worker.State

Concurrency - Task 51

Page 52: #JavaFX.forReal()

Concurrency - Task example 1/2public class DownloadPresentationTask extends Task<File> {

@Override

protected File call() throws Exception {

return new File("awesome.pdf");

}

@Override

protected void succeeded() {

super.succeeded();

this.updateMessage("Download successful");

this.updateProgress(0, 0);

}

}

52

Page 53: #JavaFX.forReal()

Concurrency - Task example 2/2

final DownloadPresentationTask task = new DownloadPresentationTask();

task.stateProperty().addListener((value, oldState, newState) -> {

if(newState == Worker.State.SUCCEEDED

&& task.getValue() != null) {

// Do awesome things

}

});

new Thread(task).start();

53

Page 54: #JavaFX.forReal()

Packaging

Page 55: #JavaFX.forReal()

• Native applications

• Embed a JRE

• No need to download a JRE

• javafxpackager tool

• Ant tasks

Packaging 55

Page 56: #JavaFX.forReal()

UI testing

Page 57: #JavaFX.forReal()

• Automaton

• Support both Swing and JavaFX 2

• Works with JavaFX 8

• Tests can be written in groovy

• TestFX

• Very fluent API

UI testing 57

Page 58: #JavaFX.forReal()

Tooling

Page 59: #JavaFX.forReal()

SceneBuilder

• FXML WYSIWYG editor + CSS support

59

Page 60: #JavaFX.forReal()

Scenic View 60

Page 61: #JavaFX.forReal()

#JavaScript

61

Page 62: #JavaFX.forReal()

• Execute standalone JavaScript

function sayHello(name) {

print("Hello " + name);

}

sayHello('Thierry');

$ jjs hello.js

Hello Thierry

Nashorn 62

Page 63: #JavaFX.forReal()

• Execute Java from JavaScript

$ jjs java.js

[Hello, world]

Nashorn

function displayList() {

var ArrayList = Java.type('java.util.ArrayList'

var lst = new ArrayList();

lst.add("Hello");

lst.add("world");

print(lst);

}

63

Page 64: #JavaFX.forReal()

Nashorn - embedding

ScriptEngineManager engineManager = new ScriptEngineManager();

ScriptEngine engine = engineManager.getEngineByName("nashorn");

engine.eval("function sum(a, b) { return a + b; }");

System.out.println(engine.eval("sum(1, 2);"));

64

Page 65: #JavaFX.forReal()

• Useful ?

• Web-based app

• One browser to test

• Web developer for front

• Java deveveloper for back

• SlideshowFX

• Polyglotism

Nashorn - JavaFX 65

Page 66: #JavaFX.forReal()

Nashorn - JavaFX

WebView webView = new WebView();

// Make a Java object available in the page

JSObject window = (JSObject) webView.getEngine()

.executeScript("window");

window.setMember("sfx", SlideshowFXController.this);

// Execute some JavaScript

webView.getEngine().executeScript("sum(1, 2);");

66

Page 67: #JavaFX.forReal()

• What’s done:

• DOM manipulation

• Get current slide

• Inject custom JS libraries

• Advantages

• JavaFX – HTML communication

• Tip

• Use Base64 strings for interopability

Nashorn - SlideshowFXREX

67

Page 68: #JavaFX.forReal()

#OSGi

68

Page 69: #JavaFX.forReal()

• Jigsaw will bring modularity

• Penrose : explore interoperability between

Jigsaw & OSGi

• For now: modularity = OSGi

In Jigsaw's shadow 69

Page 70: #JavaFX.forReal()

• The Dynamic Module System for Java

• June 2014

• OSGi Release 6

• ClassPath

• Handle it or die

OSGi - Huh? 70

Page 71: #JavaFX.forReal()

• OSGi container

• Apache Felix

• Apache Karaf

• eclipse equinox

• Services

• To be registered

OSGi - services 71

Page 72: #JavaFX.forReal()

OSGi - embeddingMap configurationMap = new HashMap<>();

configurationMap.put("org.osgi.framework.bootdelegation",

"sun.misc, javax.*, javafx.*");

configurationMap.put("felix.auto.deploy.action", "install,start"

// Starting OSGi

FrameworkFactory frameworkFactory = ServiceLoader.load(FrameworkFactory.class).iterator().next();

Framework osgiFramework = frameworkFactory.newFramework(configurationMap);

try {

osgiFramework.start();

LOGGER.fine("OSGI container has bee started successfully");

} catch (BundleException e) {

LOGGER.log(Level.SEVERE, "Can not start OSGi server");

}

72

Page 73: #JavaFX.forReal()

OSGi - deploy servicesBundle bundle = null;

try {

bundle = osgiFramework.getBundleContext()

.installBundle("file:/Users/twasyl/MyBundle.jar");

} catch (BundleException e) {

// Log

}

if(bundle != null) {

try {

bundle.start();

} catch (BundleException e) {

// Log

}

}

73

Page 74: #JavaFX.forReal()

OSGi - JavaFX tips

FXMLLoader loader = new FXMLLoader(getClass().getClassLoader()

.getResource("/path/to/my.fxml"));

Pane root = null;

try {

// Tip: need to set the ClassLoader

loader.setClassLoader(getClass().getClassLoader());

root = loader.load();

this.controller = loader.getController();

} catch (IOException e) {

// Log

}

74

Page 75: #JavaFX.forReal()

• What’s done

• Embed Felix

• Support new syntax

• Add extensions

• Add hosting connectors

• Advantage

• Extend the app without modifying the

app

• Tips

• Think ClassLoader

• Think boot delegation

OSGi - SlideshowFXREX

75

Page 76: #JavaFX.forReal()

#asciidoctor

76

Page 77: #JavaFX.forReal()

• Simplified syntax for complex rendering

• Diagrams

• Formulas

• Written in Ruby

• Ports

• JavaScript

• JVM

The popular syntax 77

Page 78: #JavaFX.forReal()

AsciidoctorJ & OSGi

• Parse asciidoctor in Java

• from files

• from strings

RubyInstanceConfig config = new RubyInstanceConfig();

config.setLoader(AsciidoctorMarkup.class.getClassLoader());

JavaEmbedUtils.initialize(Arrays.asList("gems/asciidoctor-1.5.2/lib"

Asciidoctor asciidoctor = Asciidoctor.Factory

.create(AsciidoctorMarkup.class.getClassLoader());

78

Page 79: #JavaFX.forReal()

Asciidoctor - Parsing

• From strings

String html = asciidoctor.convert("I'm a hero",

new HashMap<String, Object>());

• From files

File myFile = new File("myFile.adoc");

List<File> myFiles = new ArrayList<>(); // Add files then

Map<String, Object> options = new HashMap<>();

String html = asciidoctor.convertFile(myFile, options);

String[] htmls = asciidoctor.convertFiles(myFiles, options);

79

Page 80: #JavaFX.forReal()

• Markup syntax

• OSGi context

• Advantage

• Trendy way to define slides' content

• Tip

• Usage in an OSGi context requires a

lot of attention

Asciidoctor - SlideshowFXREX

80

Page 81: #JavaFX.forReal()

#Vert.x

81

Page 82: #JavaFX.forReal()

• Lightweight for the JVM

• Polyglot components

• Java

• JavaScript

• Groovy

• CoffeeScript

• Python

• Ruby

• ...

Innovative JVM server 82

Page 83: #JavaFX.forReal()

Vert.x - Verticles

• Verticle = piece of the server

• Do some things

• Each Verticle has an instance of Vertx

public class MyVerticle extends Verticle {

@Override

public void start() {

// Do something

}

}

83

Page 84: #JavaFX.forReal()

Vert.x - RouteMatcher

• Respond to requests

RouteMatcher routeMatcher = new RouteMatcher();

routeMatcher.get("/my-app/about.html", request -> { /* ... */ })

.post("/my-app/submit", request -> { /* ... */ } );

HttpServer server = vertx.createHttpServer();

server.requestHandler(routeMatcher)

.listen(8080, "192.168.218.100");

84

Page 85: #JavaFX.forReal()

Vert.x - Websockets

Handler<ServerWebSocket> handler = serverWebSocket -> {

if (serverWebSocket.path().equals("/my-app")) {

// ...

} else {

serverWebSocket.reject();

}

};

HttpServer server = vertx.createHttpServer();

server.websocketHandler(handler)

�.listen( 8080, "192.168.218.100");

85

Page 86: #JavaFX.forReal()

Vert.x - Event Bus

• Communicating system between Verticles

• Cross Vert.x instances

Handler<Message<String>> handler = message -> {

System.out.println("Hello" + message.body());

message.reply();

};

this.vertx.eventBus().registerHandler("say.hello", handler);

this.vertx.eventBus().publish("say.hello", "Thierry");

86

Page 87: #JavaFX.forReal()

Vert.x - Shared Data

• Share data between Verticles

• Not cross Vert.x instances

Map serverInfo = vertx.sharedData().getMap("serverInfo");

Set users = vertx.sharedData().getSet("users");

serverInfo.put("ip", "192.168.218.100");

users.add("thierry");

87

Page 88: #JavaFX.forReal()

• What’s done

• Chat using websockets

• Quizz feature

• Twitter integration

• Advantages

• Embed a web server easily

• No installation for the client

• Tip

• Store HttpServer instances as

singleton for re-usage

Vert.x - SlideshowFXREX

88

Page 89: #JavaFX.forReal()

#LeapMotion

89

Page 90: #JavaFX.forReal()

• New world, new possibilities

• Forget your mouse

• Java, C++, Unity/C#, JavaScript, Python,

Objective-C

The touchless world 90

Page 91: #JavaFX.forReal()

• -Djava.library.path

• By

• platform

• architecture

• Packaging = warning

LeapMotion - Native libraries 91

Page 92: #JavaFX.forReal()

LeapMotion - The controller

• Main interface with the device

• Access

• Frames

• Configuration information

• Use listeners

Controller leapController = new Controller();

92

Page 93: #JavaFX.forReal()

LeapMotion - The listener

• Respond to events

• onInit

• onExit

• onConnect

• onDisconnect

• onFrame

Listener wonderfulListener = new WonderfulListener();

controller.addListener(listener);

93

Page 94: #JavaFX.forReal()

• What’s done

• Change slides

• Show a pointer

• Perform clicks

• Advantage

• Bring interactivity

• Tip

• Think gestures

LeapMotion - SlideshowFXREX

94

Page 95: #JavaFX.forReal()

Books 95

Page 96: #JavaFX.forReal()

96