KEMBAR78
Construire une application JavaFX 8 avec gradle | PDF
Construire une application JavaFX 8 avec 
gradle
Construire une application JavaFX 8 avec gradle 
Thierry Wasylczenko 
@twasyl 
La session trendy
3
Ce dont on va parler 
• JavaFX 8 
• gradle 
• Tooling 
• De code 
4
5 
#JavaFX 8: 
De 2 à 8
Les Properties
Les types 
8 
IntegerProperty intP = new SimpleIntegerProperty(); 
DoubleProperty doubleP = new SimpleDoubleProperty(); 
// ... 
BooleanProperty booleanP = new SimpleBooleanProperty(); 
StringProperty stringP = new SimpleStringProperty(); 
ObjectProperty<SoftShake> objectP = new SimpleObjectProperty();
Le binding 
IntegerProperty intP1 = new SimpleIntegerProperty(); 
IntegerProperty intP2 = new SimpleIntegerProperty(); 
intP1.bind(intP2); 
intP2.set(10); 
System.out.println("Et P1? " + intP1.get()); 
9
Le binding 
IntegerProperty intP1 = new SimpleIntegerProperty(); 
IntegerProperty intP2 = new SimpleIntegerProperty(); 
intP1.bindBidirectional(intP2); 
intP2.set(10); 
System.out.println("Et P1? " + intP1.get()); 
intP1.set(20); 
System.out.println("Et P2? " + intP2.get()); 
10
Les événements 
IntegerProperty intP1 = new SimpleIntegerProperty(); 
intP1.addListener((valueInt, oldInt, newInt) -> { 
System.out.println("Change"); 
}); 
intP1.set(10); 
11
POJO 2.0 
public class Conference { 
private StringProperty name = new SimpleStringProperty(); 
12 
public StringProperty nameProperty() { return this.name; } 
public String getName() { return this.name.get(); } 
public void setName(String name) { this.name.set(name); } 
} 
final Conference softShake = new Conference(); 
tf.textProperty().bindBidirectional(softShake.nameProperty());
Pas serializable
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); 
14
POJO 1.5 
final Conference softShake = new Conference(); 
JavaBeanStringPropertyBuilder builder = new ... 
JavaBeanStringProperty nameProperty = builder.bean(softShake) 
.name("name") 
.build(); 
nameProperty.addListener((valueName, oldIName, newName) -> { 
// ... 
}); 
15
Vues
FXML 
<AnchorPane xmlns:fx="http://javafx.com/fxml" 
fx:controller="org.mycompany.Controller"> 
<stylesheets> 
<URL value="@/org/mycompany/css/Default.css" /> 
<URL value="@/org/mycompany/css/Specialized.css" /> 
</stylesheets> 
<Button fx:id="myButton" text="Button" onAction="#click" /> 
<TextField fx:id="myTextField" promptText="Enter something" /> 
</AnchorPane> 
17
Controller 
public class Controller implements Initializable { 
@FXML private Button myButton; 
@FXML private TextField myTextField; 
@FXML private void click(ActionEvent evt) { /* ... */ } 
@Override 
public void initialize(URL url, ResourceBundle resourceBundle) 
// ... 
} 
} 
18
CSS
Personnaliser les composants 
FXML 
<Button style="-fx-text-fill: white" styleClass="awesome" /> 
Java 
button.setStyle("-fx-background-color: red;"); 
button.getStyleClass().add("awesome"); 
20
Personnaliser les composants 
Feuille de style 
.button { 
-fx-text-fill: white; 
-fx-background-color: red; 
} 
.button:hover { -fx-background-color: blue; } 
.awesome { -fx-background-color: gray; } 
#myButton { -fx-text-fill: black; } 
21
PseudoState personnalisés 
PseudoClass ps = PseudoClass.getPseudoClass("awesome"); 
myButton.pseudoClassStateChanged(ps, true); 
.button:awesome { 
-fx-text-fill: orange; 
} 
#myButton:awesome { 
-fx-text-fill: green; 
} 
22
WebView
JS <> JFX 
webview.getEngine().getLoadWorker().stateProperty().addListener((observableValue, if (newState == Worker.State.SUCCEEDED) { 
JSObject window = (JSObject) webview.getEngine() 
.executeScript("window"); 
window.setMember("javaObj",this); 
} 
}); 
24
JS <> JFX 
Java 
WebEngine engine = webview.getEngine(); 
String result = engine.executeScript("return 'Hello';"); 
JavaScript 
javaObj.myWonderfulMethod("Hello"); 
25
WebSocket 
window.onload = function() { 
socket = new WebSocket("ws://mycompany.com/ws"); 
socket.onopen = function(event) { /* ... */ }; 
socket.onclose = function(event) { /* ... */ }; 
socket.onmessage = function(event) { /* ... */ }; 
}; 
26
Drag'n'drop
Drag'n'drop 
obj.setOnDragDetected(event -> { /* ... */ }); 
obj.setOnDragOver(event -> { /* ... */ }); 
obj.setOnDragEntered(event -> { /* ... */ }); 
obj.setOnDragExited(event -> { /* ... */ }); 
obj.setOnDragDropped(event -> { /* ... */ }); 
obj.setOnDragDone(event -> { /* ... */ }); 
28
Printing API
Print 
Chaque Node 
PrinterJob job = PrinterJob.createPrinterJob(); 
job.printPage(myTextField); 
Une page web 
WebView view = new WebView(); 
PrinterJob job = PrinterJob.createPrinterJob(); 
view.getEngine().print(job); 
30
3D
Objets prédéfinis 
Box b = new Box(width, height, depth); 
Cylinder c = new Cylinder(radius, height); 
Sphere s = new Sphere(radius); 
TriangleMesh tm = new TriangleMesh(); 
Les plus basiques 
32
Camera & Light 
Camera camera = new PerspectiveCamera(true); 
scene.setCamera(camera); 
PointLight point = new PointLight(Color.RED); 
AmbientLight ambient = new AmbientLight(Color.WHITE); 
scene.getRoot().getChildren().addAll(point, ambient); 
Ne pas oublier de positionner les objets 
33
34 
#gradle: 
Flexibilité
Task 
• Réponds à MON besoin 
• Dynamisme 
• Dépendances 
• Greffage au cycle de vie 
task sofshake << { 
println 'Hello Soft-Shake 2014' 
} 
tasks['sofshake'].dependsOn 'jar' 
36
Task: surcharge 
apply plugin: 'java' 
task jar(overwrite: true) << { 
// ... 
manifest { 
// ... 
} 
} 
37
Dépendances 
dependencies { 
compile (':my-project') 
runtime files('libs/a.jar', 'libs/b.jar') 
runtime "org.groovy:groovy:2.2.0@jar" 
runtime group: 'org.groovy', name: 'groovy', version: '2.2.0', ext: 
} 
38
Copy 
• Copier des fichiers facilement 
• La roue est déjà inventée 
copy { 
from file1 
from file2 
into folder 
} 
39
Gradle wrapper 
• Execution de gradle sans intallation préalable 
• Plateformes d’intégration continue friendly 
task buildGradleWrapper(type: Wrapper) { 
gradleVersion = '2.1' 
} 
40
Ouvert
Intégration de Ant 
• Variables 
• Tâches 
ant.importBuild "ant/project/file.xml" 
ant.conference = "Soft-Shake 2014" 
ant.location = "Genève" 
maTacheAnt.execute() 
44
45 
Tooling
SceneBuilder 46
ScenicView 47
TestFX 
public class DesktopTest extends GuiTest { 
public Parent getRootNode() { return new Desktop(); } 
@Test public void testMe() { 
// Given 
rightClick("#desktop").move("New").click("Text Document") 
.type("myTextfile.txt").push(ENTER); 
// When 
drag(".file").to("#trash-can"); 
// Then 
verifyThat("#desktop", contains(0, ".file")); 
48
49 
#Code
Codons ! 
• JavaFX 8 
• Properties 
• FXML 
• Styling 
• gradle 
• Dépendances 
• Build 
50
Ressources 51
Ressources 
• https://github.com/TestFX/TestFX 
• http://fxexperience.com/ 
• http://fxexperience.com/controlsfx/ 
• Source code of the demo: https://bitbucket.org/twasyl/weatherfx 
52
53

Construire une application JavaFX 8 avec gradle

  • 1.
    Construire une applicationJavaFX 8 avec gradle
  • 2.
    Construire une applicationJavaFX 8 avec gradle Thierry Wasylczenko @twasyl La session trendy
  • 3.
  • 4.
    Ce dont onva parler • JavaFX 8 • gradle • Tooling • De code 4
  • 5.
  • 6.
  • 7.
  • 8.
    Les types 8 IntegerProperty intP = new SimpleIntegerProperty(); DoubleProperty doubleP = new SimpleDoubleProperty(); // ... BooleanProperty booleanP = new SimpleBooleanProperty(); StringProperty stringP = new SimpleStringProperty(); ObjectProperty<SoftShake> objectP = new SimpleObjectProperty();
  • 9.
    Le binding IntegerPropertyintP1 = new SimpleIntegerProperty(); IntegerProperty intP2 = new SimpleIntegerProperty(); intP1.bind(intP2); intP2.set(10); System.out.println("Et P1? " + intP1.get()); 9
  • 10.
    Le binding IntegerPropertyintP1 = new SimpleIntegerProperty(); IntegerProperty intP2 = new SimpleIntegerProperty(); intP1.bindBidirectional(intP2); intP2.set(10); System.out.println("Et P1? " + intP1.get()); intP1.set(20); System.out.println("Et P2? " + intP2.get()); 10
  • 11.
    Les événements IntegerPropertyintP1 = new SimpleIntegerProperty(); intP1.addListener((valueInt, oldInt, newInt) -> { System.out.println("Change"); }); intP1.set(10); 11
  • 12.
    POJO 2.0 publicclass Conference { private StringProperty name = new SimpleStringProperty(); 12 public StringProperty nameProperty() { return this.name; } public String getName() { return this.name.get(); } public void setName(String name) { this.name.set(name); } } final Conference softShake = new Conference(); tf.textProperty().bindBidirectional(softShake.nameProperty());
  • 13.
  • 14.
    POJO 1.5 publicclass 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); 14
  • 15.
    POJO 1.5 finalConference softShake = new Conference(); JavaBeanStringPropertyBuilder builder = new ... JavaBeanStringProperty nameProperty = builder.bean(softShake) .name("name") .build(); nameProperty.addListener((valueName, oldIName, newName) -> { // ... }); 15
  • 16.
  • 17.
    FXML <AnchorPane xmlns:fx="http://javafx.com/fxml" fx:controller="org.mycompany.Controller"> <stylesheets> <URL value="@/org/mycompany/css/Default.css" /> <URL value="@/org/mycompany/css/Specialized.css" /> </stylesheets> <Button fx:id="myButton" text="Button" onAction="#click" /> <TextField fx:id="myTextField" promptText="Enter something" /> </AnchorPane> 17
  • 18.
    Controller public classController implements Initializable { @FXML private Button myButton; @FXML private TextField myTextField; @FXML private void click(ActionEvent evt) { /* ... */ } @Override public void initialize(URL url, ResourceBundle resourceBundle) // ... } } 18
  • 19.
  • 20.
    Personnaliser les composants FXML <Button style="-fx-text-fill: white" styleClass="awesome" /> Java button.setStyle("-fx-background-color: red;"); button.getStyleClass().add("awesome"); 20
  • 21.
    Personnaliser les composants Feuille de style .button { -fx-text-fill: white; -fx-background-color: red; } .button:hover { -fx-background-color: blue; } .awesome { -fx-background-color: gray; } #myButton { -fx-text-fill: black; } 21
  • 22.
    PseudoState personnalisés PseudoClassps = PseudoClass.getPseudoClass("awesome"); myButton.pseudoClassStateChanged(ps, true); .button:awesome { -fx-text-fill: orange; } #myButton:awesome { -fx-text-fill: green; } 22
  • 23.
  • 24.
    JS <> JFX webview.getEngine().getLoadWorker().stateProperty().addListener((observableValue, if (newState == Worker.State.SUCCEEDED) { JSObject window = (JSObject) webview.getEngine() .executeScript("window"); window.setMember("javaObj",this); } }); 24
  • 25.
    JS <> JFX Java WebEngine engine = webview.getEngine(); String result = engine.executeScript("return 'Hello';"); JavaScript javaObj.myWonderfulMethod("Hello"); 25
  • 26.
    WebSocket window.onload =function() { socket = new WebSocket("ws://mycompany.com/ws"); socket.onopen = function(event) { /* ... */ }; socket.onclose = function(event) { /* ... */ }; socket.onmessage = function(event) { /* ... */ }; }; 26
  • 27.
  • 28.
    Drag'n'drop obj.setOnDragDetected(event ->{ /* ... */ }); obj.setOnDragOver(event -> { /* ... */ }); obj.setOnDragEntered(event -> { /* ... */ }); obj.setOnDragExited(event -> { /* ... */ }); obj.setOnDragDropped(event -> { /* ... */ }); obj.setOnDragDone(event -> { /* ... */ }); 28
  • 29.
  • 30.
    Print Chaque Node PrinterJob job = PrinterJob.createPrinterJob(); job.printPage(myTextField); Une page web WebView view = new WebView(); PrinterJob job = PrinterJob.createPrinterJob(); view.getEngine().print(job); 30
  • 31.
  • 32.
    Objets prédéfinis Boxb = new Box(width, height, depth); Cylinder c = new Cylinder(radius, height); Sphere s = new Sphere(radius); TriangleMesh tm = new TriangleMesh(); Les plus basiques 32
  • 33.
    Camera & Light Camera camera = new PerspectiveCamera(true); scene.setCamera(camera); PointLight point = new PointLight(Color.RED); AmbientLight ambient = new AmbientLight(Color.WHITE); scene.getRoot().getChildren().addAll(point, ambient); Ne pas oublier de positionner les objets 33
  • 34.
  • 35.
  • 36.
    Task • Répondsà MON besoin • Dynamisme • Dépendances • Greffage au cycle de vie task sofshake << { println 'Hello Soft-Shake 2014' } tasks['sofshake'].dependsOn 'jar' 36
  • 37.
    Task: surcharge applyplugin: 'java' task jar(overwrite: true) << { // ... manifest { // ... } } 37
  • 38.
    Dépendances dependencies { compile (':my-project') runtime files('libs/a.jar', 'libs/b.jar') runtime "org.groovy:groovy:2.2.0@jar" runtime group: 'org.groovy', name: 'groovy', version: '2.2.0', ext: } 38
  • 39.
    Copy • Copierdes fichiers facilement • La roue est déjà inventée copy { from file1 from file2 into folder } 39
  • 40.
    Gradle wrapper •Execution de gradle sans intallation préalable • Plateformes d’intégration continue friendly task buildGradleWrapper(type: Wrapper) { gradleVersion = '2.1' } 40
  • 41.
  • 44.
    Intégration de Ant • Variables • Tâches ant.importBuild "ant/project/file.xml" ant.conference = "Soft-Shake 2014" ant.location = "Genève" maTacheAnt.execute() 44
  • 45.
  • 46.
  • 47.
  • 48.
    TestFX public classDesktopTest extends GuiTest { public Parent getRootNode() { return new Desktop(); } @Test public void testMe() { // Given rightClick("#desktop").move("New").click("Text Document") .type("myTextfile.txt").push(ENTER); // When drag(".file").to("#trash-can"); // Then verifyThat("#desktop", contains(0, ".file")); 48
  • 49.
  • 50.
    Codons ! •JavaFX 8 • Properties • FXML • Styling • gradle • Dépendances • Build 50
  • 51.
  • 52.
    Ressources • https://github.com/TestFX/TestFX • http://fxexperience.com/ • http://fxexperience.com/controlsfx/ • Source code of the demo: https://bitbucket.org/twasyl/weatherfx 52
  • 53.