Slide 1

Slide 1 text

JavaFX Jussi Pohjolainen 1

Slide 2

Slide 2 text

Java FX Overview 2

Slide 3

Slide 3 text

Some History • Abstract Windowing Toolkit (AWT) • Original UI kit for Java • java.awt.Button • Mostly uses the native UI widgets • Swing • In Java SE 1.2, Swing superseded AWT. Although AWT still exists. • javax.swing.JButton • Draws own widgets using Java 2D • Provides native look and feel that emulates of several platforms • JavaFX • Intented to replace Swing • Draws own widgets, uses CSS for styling • Separate markup language for UI • javafx.scene.control.Button 3

Slide 4

Slide 4 text

4

Slide 5

Slide 5 text

Java FX on Mobile • JavaFXPorts is a open source project that brings JavaFX to mobile • iOS, Android • See • http://gluonhq.com/products/mobile/javafxports/ 5

Slide 6

Slide 6 text

Java FX on Browsers • By using Java plug-in in browser, you can run JavaFX apps in browsers • Unfortunately the Java plugin is not most beloved plug-in so many users have disabled or removed the plugin • Also a webstart option, where jar is downloaded and opened • Maybe in the future we can tools like jpro.io where JavaFX apps can be run in browser without any plugins! • https://www.jpro.io/ 6

Slide 7

Slide 7 text

JavaFX on Desktop • You can package your app to • jar • .exe, .msi or .app • And you can even embed the JRE inside of your app bundle, so user does not have to install Java! 7

Slide 8

Slide 8 text

JavaFX 8 Key Features • Java APIs • FXML and Scene Builder • WebView • Swing interoperability • Built-in UI Controls and CSS • 3D Graphics • Canvas and Printing API • Multitouch • Hardware-accelerated graphics (Prism) • Self-contained application deployment model 8

Slide 9

Slide 9 text

Architecture 9 Hierarchial tree of nodes that are the visual elements in the UI Quantum Toolkit provides interface for underlying APIs Renders both in hardware or in software Connects JavaFX to native operating system

Slide 10

Slide 10 text

Scene Graph • Starting point for your app • Hierarchial tree of nodes that are the visual elements in the UI • For each node you can • create effects, blurs, shadows, opacity .. • event handlers • etc • Unlike Swing or AWT, you can also have graphics primitives, like rectangles and text in addition of having UI controls 10

Slide 11

Slide 11 text

Graphics System and Quantum Toolkit • Uses Prism to render both in hardware and software • DirectX 11 in Win7, OpenGL in Mac/Linux • Software rendering if hardware is not an options • Support for both 2D and 3D • Quantum Toolkit ties Prism and Glass Windowing Toolkit together • Glass Windowing Toolkit connects Java FX to native operating system • Provides access to native operating system services like windows, timers, event queue 11

Slide 12

Slide 12 text

CSS • JavaFX CSS provides ability to customize the UI • Based on W3C CSS 2.1 • JavaFX CSS Extensions, prefix of –fx- • CSS can be applied to any node 12

Slide 13

Slide 13 text

UI Controls 13

Slide 14

Slide 14 text

Layouts • Layout containers for arrangements of UI controls • Lot of options • BorderPane • HBox, VBox • StackPane • GridPane • FlowPane • TilePane • AnchorPane 14

Slide 15

Slide 15 text

FXML • FXML is a interface markup language used in JavaFX • Anything created in FXML can be also created in code • FXML is compiled to code • Separates business logic code from UI • Possible to have Java expert and UI/FXML expert (without Java knowledge) • JavaFX Scene Builder for creating FXML by using GUI • Although Oracle does not offer any more binary downloads for this • Has been open sourced, can be downloaded for example • http://gluonhq.com/products/scene-builder/ 15

Slide 16

Slide 16 text

Transformations and Effects • For transformations • translate • scale • rotate • ... • For Effects • Drop shadow • Reflection • Lightning 16

Slide 17

Slide 17 text

Tools 17

Slide 18

Slide 18 text

JavaFX Tools • You will need JDK1.8 and code editor • That's it! • For more advanced tools, use maven/gradle • Or IDE: Eclipse, IntelliJ IDEA, NetBeans 18

Slide 19

Slide 19 text

Hello World Java FX 19

Slide 20

Slide 20 text

Hello World in JavaFX package com.mycompany.app; import javafx.application.Application; import javafx.stage.Stage; public class App extends Application { @Override public void start(Stage stage) { stage.setTitle("JavaFX HelloWorld!"); stage.show(); } public static void main(String args[]) { launch(args); } } Application.launch will start javafx and run start() method Stage is the JavaFX window, has title and content Start method begins running JavaFX window, upon Application.launch() Set stage visible when you have set it up. Do all modification before this. 20

Slide 21

Slide 21 text

Life-cycle • Application class is the entry point for JavaFX apps. The following occurs in the lifespan of the app: • Instance of the Application class • init() method • start(Stage stage) method • Waiting for the app to stop • Either Platform.exit() or last window has been closed (and implicitExit attribute on Platform is true) • stop() method. • Notice that the init and stop methods have concrete implementations that do nothing. 21

Slide 22

Slide 22 text

Lab 01 - 02 22

Slide 23

Slide 23 text

Stage and Scene 23

Slide 24

Slide 24 text

Stage (like window) • A Stage contains all the objects of a JavaFX app. The primary stage is created by the platform itself. • Also five types of stages are available • Decorated • Undecorated • Transparent • Unified • Utility 24

Slide 25

Slide 25 text

Scene (like the content of the window) • To add stuff to the Stage, we will use javafx.scene. • Scene holds root node which may hold other nodes. • Node is a visual object in the scene • Node may include • 2D/3D Shape • UI Control, like Button • Containers (Layout panes) • Media elements, like Video object • Node is one of the three • Root node - the first one • Parent/Branch node - node with child nodes • In JavaFX: Group, Region, WebView • Leaf node - node without child nodes • In JavaFX: Rectangle, Button, ImageView 25

Slide 26

Slide 26 text

DECORATED import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.layout.StackPane; import javafx.stage.Stage; import javafx.stage.StageStyle; public class Main extends Application { @Override public void start(Stage window) { window.setTitle("JavaFX HelloWorld!"); StackPane root = new StackPane(new Button("Click")); Scene content = new Scene(root, 320, 240); window.initStyle(StageStyle.DECORATED); window.setScene(content); window.show(); } public static void main(String args[]) { launch(args); } } 26 Defines a normal Stage style with a solid white background and platform decorations.

Slide 27

Slide 27 text

UNDECORATED import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.layout.StackPane; import javafx.stage.Stage; import javafx.stage.StageStyle; public class Main extends Application { @Override public void start(Stage window) { window.setTitle("JavaFX HelloWorld!"); StackPane root = new StackPane(new Button("Click")); Scene content = new Scene(root, 320, 240); window.initStyle(StageStyle.UNDECORATED); window.setScene(content); window.show(); } public static void main(String args[]) { launch(args); } } 27 Defines a Stage style with a solid white background and no decorations.

Slide 28

Slide 28 text

TRANSPARENT import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.layout.StackPane; import javafx.stage.Stage; import javafx.stage.StageStyle; public class Main extends Application { @Override public void start(Stage window) { window.setTitle("JavaFX HelloWorld!"); StackPane root = new StackPane(new Button("Click")); Scene content = new Scene(root, 320, 240); content.setFill(null); root.setStyle("-fx-background-color: transparent;"); window.initStyle(StageStyle.TRANSPARENT); window.setScene(content); window.show(); } public static void main(String args[]) { launch(args); } } 28 Notice that we set the scene and the layout background to transparent also

Slide 29

Slide 29 text

UTILITY import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.layout.StackPane; import javafx.stage.Stage; import javafx.stage.StageStyle; public class Main extends Application { @Override public void start(Stage window) { window.setTitle("JavaFX HelloWorld!"); StackPane root = new StackPane(new Button("Click")); Scene content = new Scene(root, 320, 240); window.initStyle(StageStyle.UTILITY); window.setScene(content); window.show(); } public static void main(String args[]) { launch(args); } } 29 Defines a Stage style with a solid white background and minimal platform decorations used for a utility window.

Slide 30

Slide 30 text

UNIFIED import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.layout.StackPane; import javafx.stage.Stage; import javafx.stage.StageStyle; public class Main extends Application { @Override public void start(Stage window) { window.setTitle("JavaFX HelloWorld!"); StackPane root = new StackPane(new Button("Click")); Scene content = new Scene(root, 320, 240); window.initStyle(StageStyle.UNIFIED); window.setScene(content); window.show(); } public static void main(String args[]) { launch(args); } } 30 Defines a Stage style with platform decorations and eliminates the border between client area and decorations. There is no black line here.

Slide 31

Slide 31 text

Group • Group contains a list (ObservableList) of children nodes • Group will take the collective bounds of its children • Is not directly resizable • All the children have their preferred sizes 31

Slide 32

Slide 32 text

Example import javafx.application.Application; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.stage.Stage; public class Main extends Application { @Override public void start(Stage window) { window.setTitle("JavaFX HelloWorld!"); Button button1 = new Button("Click 1"); Button button2 = new Button("Click 2"); Group group = new Group(); group.getChildren().add(button1); group.getChildren().add(button2); Scene content = new Scene(group, 640, 480); window.setScene(content); window.show(); button2.setTranslateX(button1.getTranslateX() + button2.getWidth()); } public static void main(String args[]) { launch(args); } } 32

Slide 33

Slide 33 text

Lab 03 - 04 33

Slide 34

Slide 34 text

Java FX Layouts 34

Slide 35

Slide 35 text

JavaFX Layouts • HBox • All nodes in horizontal • VBox • All nodes in vertical • BorderPane • Top, bottom, left, right and center nodes • StackPane • Nodes on top of each other • GridPane • Rows and columns • FlowPane • Everything in one row if space (hbox). Will change if not room (vbox) • TilePane • Like FlowPane but more control how the alignment goes • AnchorPane • Possibility to anchor nodes to top, bottom, left and right • Possible to anchor to both left and right, then widget will stretch 35

Slide 36

Slide 36 text

HBox import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.layout.HBox; import javafx.stage.Stage; public class Main extends Application { @Override public void start(Stage window) { Button button1 = new Button("Click 1"); Button button2 = new Button("Click 2"); HBox group = new HBox(); group.getChildren().add(button1); group.getChildren().add(button2); Scene content = new Scene(group, 640, 480); window.setScene(content); window.show(); } public static void main(String args[]) { launch(args); } } 36

Slide 37

Slide 37 text

VBox import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.layout.VBox; import javafx.stage.Stage; public class Main extends Application { @Override public void start(Stage window) { Button button1 = new Button("Click 1"); Button button2 = new Button("Click 2"); VBox group = new VBox(); group.getChildren().add(button1); group.getChildren().add(button2); Scene content = new Scene(group, 640, 480); window.setScene(content); window.show(); } public static void main(String args[]) { launch(args); } } 37

Slide 38

Slide 38 text

HBox and VBox • Nodes in horizontal or vertical • Will resize the children to preferred widths and heigths • You can control alignment (left, center, right) 38

Slide 39

Slide 39 text

Spacing and Alignment // You can use constructor too! VBox group = new VBox(button1, button2); // Add some spacing group.setSpacing(8); // Let's center to the screen! group.setAlignment(Pos.CENTER); 39

Slide 40

Slide 40 text

BorderPane 40

Slide 41

Slide 41 text

Example import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.TextArea; import javafx.scene.layout.BorderPane; import javafx.scene.text.Text; import javafx.stage.Stage; public class Main extends Application { @Override public void start(Stage window) { BorderPane root = new BorderPane(); root.setTop(new Button("Clear Text")); root.setBottom(new Text("Bottom")); root.setLeft(new Text("Left")); root.setRight(new Text("Right")); root.setCenter(new TextArea()); Scene content = new Scene(root, 640, 480); window.setScene(content); window.show(); } public static void main(String args[]) { launch(args); } } 41

Slide 42

Slide 42 text

StackPane - Nodes on Top Each Other import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.control.Label; import javafx.scene.layout.StackPane; import javafx.scene.paint.Color; import javafx.scene.shape.Rectangle; import javafx.stage.Stage; public class Main extends Application { @Override public void start(Stage window) { StackPane root = new StackPane(new Rectangle(100,100, Color.RED), new Label("Go!")); Scene content = new Scene(root, 640, 480); window.setScene(content); window.show(); } public static void main(String args[]) { launch(args); } } 42

Slide 43

Slide 43 text

GridPane – Row and Columns import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.layout.GridPane; import javafx.stage.Stage; public class Main extends Application { @Override public void start(Stage window) { GridPane root = new GridPane(); root.add(new Button("A"), 0, 0); root.add(new Button("B"), 1, 0); root.add(new Button("C"), 0, 1); root.add(new Button("D"), 1, 1); Scene content = new Scene(root, 640, 480); window.setScene(content); window.show(); } public static void main(String args[]) { launch(args); } } 43

Slide 44

Slide 44 text

Setting Constraints GridPane root = new GridPane(); root.add(new Button("A"), 0, 0); root.add(new Button("B"), 1, 0); root.add(new Button("C"), 0, 1); root.add(new Button("D"), 1, 1); ColumnConstraints column1 = new ColumnConstraints(); column1.setPercentWidth(100 / 2f); root.getColumnConstraints().add(column1); ColumnConstraints column2 = new ColumnConstraints(); column2.setPercentWidth(100 / 2f); root.getColumnConstraints().add(column2); RowConstraints row1 = new RowConstraints(); row1.setPercentHeight(100 / 2f); root.getRowConstraints().add(row1); RowConstraints row2 = new RowConstraints(); row2.setPercentHeight(100 / 2f); root.getRowConstraints().add(row2); 44

Slide 45

Slide 45 text

Setting Constraints for(Node n : root.getChildren()) { Button button = (Button) n; GridPane.setFillWidth(button, true); button.setMaxWidth(Double.MAX_VALUE); GridPane.setFillHeight(button, true); button.setMaxHeight(Double.MAX_VALUE); } 45

Slide 46

Slide 46 text

FlowPane – It's a Wrap! import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.layout.FlowPane; import javafx.stage.Stage; public class Main extends Application { @Override public void start(Stage window) { FlowPane root = new FlowPane(new Button("Text Text Text"), new Button("Text Text Text")); Scene content = new Scene(root, 640, 480); window.setScene(content); window.show(); } public static void main(String args[]) { launch(args); } } 46

Slide 47

Slide 47 text

TilePane • TilePane is like a FlowPane, tries to put things in one row • Differences • You can define number of preferred cols and rows => Grid • Each cell in grid is the same size 47

Slide 48

Slide 48 text

Example import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.control.Label; import javafx.scene.control.TextField; import javafx.scene.layout.TilePane; import javafx.stage.Stage; public class Main extends Application { @Override public void start(Stage window) { TilePane root = new TilePane(new Label("Name"), new TextField(), new Label("E-mail"), new TextField()); root.setPrefColumns(2); root.setPrefRows(2); Scene content = new Scene(root, 640, 480); window.setScene(content); window.show(); } public static void main(String args[]) { launch(args); } } 48

Slide 49

Slide 49 text

AnchorPane import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.control.TextField; import javafx.scene.layout.AnchorPane; import javafx.stage.Stage; public class Main extends Application { @Override public void start(Stage window) { TextField a = new TextField("A"); TextField b = new TextField("B"); AnchorPane root = new AnchorPane(a, b); AnchorPane.setBottomAnchor(a, 50.0); AnchorPane.setLeftAnchor(a, 50.0); AnchorPane.setTopAnchor(b, 50.0); AnchorPane.setLeftAnchor(b, 0.0); AnchorPane.setRightAnchor(b, 0.0); Scene content = new Scene(root, 640, 480); window.setScene(content); window.show(); } public static void main(String args[]) { launch(args); } } 49

Slide 50

Slide 50 text

Lab 05 50

Slide 51

Slide 51 text

Java FX MenuBar 51

Slide 52

Slide 52 text

MenuBar • Using Menus is easy • MenuBar -> Menu -> MenuItem • Also available • CheckMenuItem, RadioMenuItem, SeparatorMenuItem • Possible to create submenus • Enabling and disabling menus • Also ContextMenu possibility 52

Slide 53

Slide 53 text

Example MenuBar menuBar = new MenuBar(); // --- Menu File Menu menuFile = new Menu("File"); // --- Menu Edit Menu menuEdit = new Menu("Edit"); // --- Menu View Menu menuView = new Menu("View"); menuBar.getMenus().addAll(menuFile, menuEdit, menuView); 53

Slide 54

Slide 54 text

Where to put the MenuBar? • The menubar can be anywhere! • Usually it's on top of the window (or in Mac, top of the display) • Just use for example VBox and set the menubar be the first UI control of the VBox 54

Slide 55

Slide 55 text

Shortcuts MenuItem cut = new MenuItem("Cut"); cut.setAccelerator(new KeyCodeCombination(KeyCode.X, KeyCombination.SHORTCUT_DOWN)); 55 The shortcut modifier is used to represent the modifier key which is used commonly in keyboard shortcuts on the host platform. This is for example control on Windows and meta (command key) on Mac.

Slide 56

Slide 56 text

Lab 06 56

Slide 57

Slide 57 text

Java FX Controls 57

Slide 58

Slide 58 text

Java FX Controls • Label • Button • RadioButton, ToggleButton, Checkbox • ChoiceBox • TextField • PasswordField • ScrollBar • ScrollPane • ListView • TableView • TreeView • ComboBox • Separator • Slider • ProgressBar • ProgressIndicator • Hyperlink • ToolTip • HTMLEditor • Menu • ColorPicker • FileChooser • ... 58

Slide 59

Slide 59 text

TreeView public class TreeViewExample extends Application { public static void main(String[] args) { launch(args); } @Override public void start(Stage primaryStage) { TreeItem rootItem = new TreeItem ("Inbox"); rootItem.setExpanded(true); for (int i = 1; i < 6; i++) { TreeItem item = new TreeItem("Message" + i); rootItem.getChildren().add(item); } TreeView tree = new TreeView(rootItem); primaryStage.setScene(new Scene(tree, 300, 250)); primaryStage.show(); } } 59

Slide 60

Slide 60 text

ListView public class ListViewExample extends Application { public static void main(String[] args) { launch(args); } @Override public void start(Stage primaryStage) { ObservableList names = FXCollections.observableArrayList(); ListView listView = new ListView(); listView.setPrefSize(200, 250); listView.setEditable(true); names.addAll( "Adam", "Alex", "Alfred", "Albert", "Brenda", "Connie", "Derek", "Donny", "Lynne", "Myrtle", "Rose", "Rudolph", "Tony", "Trudy", "Williams", "Zach" ); listView.setItems(names); primaryStage.setScene(new Scene(listView, 300, 250)); primaryStage.show(); } } 60

Slide 61

Slide 61 text

Java FX Events 61

Slide 62

Slide 62 text

Events • Events are notifications that something has happened • User clicks a button, moves a mouse • Register event handlers receive the event and provide some response • Event in Java FX is javafx.event.Event • DragEvent, KeyEvent, MouseEvent, ScrollEvent 62

Slide 63

Slide 63 text

Event Type Hierarchy 63

Slide 64

Slide 64 text

Node and Scene Events • Node and Scene has convenience methods for Event Handling • To register • setOnEvent-type(EventHandler super event-class> value) • The Event-type is the type of event that handler processes • setOnKeyTyped(...) setOnMouseClicked(...) • So for example for key events • setOnKeyTyped(EventHandler super KeyEvent> value) 64

Slide 65

Slide 65 text

Different Events User Action Event type Class Mouse is moved MouseEvent Node, Scene Drag and Drop DragEvent Node, Scene Button is pressed or menuitem selected ActionEvent Node, Scene Item in a List is edited ListView.EditEvent ListView ... ... ... 65

Slide 66

Slide 66 text

Example 1: Separate Listener Class public class Test extends Application { public static void main(String[] args) { launch(args); } @Override public void start(Stage primaryStage) { Button button = new Button("Click"); button.setOnAction(new Listener()); Scene scene = new Scene(button, 640, 480); primaryStage.setScene(scene); primaryStage.show(); } } class Listener implements EventHandler { @Override public void handle(ActionEvent event) { Button b = (Button) event.getSource(); b.setText("Clicked!"); } } 66

Slide 67

Slide 67 text

Example 2: With One Class public class Test extends Application implements EventHandler { public static void main(String[] args) { launch(args); } @Override public void start(Stage primaryStage) { Button button = new Button("Click"); button.setOnAction(this); Scene scene = new Scene(button, 640, 480); primaryStage.setScene(scene); primaryStage.show(); } @Override public void handle(ActionEvent event) { Button b = (Button) event.getSource(); b.setText("Clicked!"); } } 67

Slide 68

Slide 68 text

Example 3: Inner Class public class Test extends Application { private Button button; class Listener implements EventHandler { @Override public void handle(ActionEvent event) { button.setText("Clicked!"); } } public static void main(String[] args) { launch(args); } @Override public void start(Stage primaryStage) { button = new Button("Click"); button.setOnAction(new Listener()); Scene scene = new Scene(button, 640, 480); primaryStage.setScene(scene); primaryStage.show(); } } 68

Slide 69

Slide 69 text

Example 4: Method Inner Class public class Test extends Application { private Button button; public static void main(String[] args) { launch(args); } @Override public void start(Stage primaryStage) { class Listener implements EventHandler { @Override public void handle(ActionEvent event) { button.setText("Clicked!"); } } button = new Button("Click"); button.setOnAction(new Listener()); Scene scene = new Scene(button, 640, 480); primaryStage.setScene(scene); primaryStage.show(); } } 69

Slide 70

Slide 70 text

Example 5: Anonymous Inner Class public class Test extends Application { private Button button; public static void main(String[] args) { launch(args); } @Override public void start(Stage primaryStage) { button = new Button("Click"); button.setOnAction(new EventHandler() { @Override public void handle(ActionEvent event) { button.setText("Clicked!"); } }); Scene scene = new Scene(button, 640, 480); primaryStage.setScene(scene); primaryStage.show(); } } 70

Slide 71

Slide 71 text

Example 6: Java 8 Lambda public class Test extends Application { private Button button; public static void main(String[] args) { launch(args); } @Override public void start(Stage primaryStage) { button = new Button("Click"); button.setOnAction((event) -> button.setText("Clicked!")); Scene scene = new Scene(button, 640, 480); primaryStage.setScene(scene); primaryStage.show(); } } 71

Slide 72

Slide 72 text

Example 7: Java 8 Method Reference public class Test extends Application { private Button button; public static void main(String[] args) { launch(args); } @Override public void start(Stage primaryStage) { button = new Button("Click"); button.setOnAction(this::buttonClicked); Scene scene = new Scene(button, 640, 480); primaryStage.setScene(scene); primaryStage.show(); } public void buttonClicked(ActionEvent e) { button.setText("Clicked!"); } } 72

Slide 73

Slide 73 text

Example 8: Shapes and Dragging import javafx.application.Application; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.shape.Circle; import javafx.stage.Stage; public class DragExample extends Application { public static void main(String[] args) { launch(args); } @Override public void start(Stage primaryStage) { Circle circle = new Circle(0,0,20); Group group = new Group(); group.getChildren().addAll(circle); primaryStage.setScene(new Scene(group, 300, 250)); primaryStage.show(); circle.setOnMouseDragged((e) -> { circle.setCenterX(e.getX()); circle.setCenterY(e.getY()); }); } } 73

Slide 74

Slide 74 text

Lab 07 74

Slide 75

Slide 75 text

Java FX Dialogs 75

Slide 76

Slide 76 text

Dialog • Prebuilt Alert class for notifications • CONFIRMATION, ERROR, INFORMATION, NONE, WARNING • Also TextInputDialog and ChoiceDialog • Dialogs are modal by default • You have to make a decision if it's blocking or not whan displaying the dialog • showAndWait() (blocking) or show() (non blocking) 76

Slide 77

Slide 77 text

Different options, uses Java 8 Optional API • Option 1 Optional result = alert.showAndWait(); if (result.isPresent() && result.get() == ButtonType.OK) { formatSystem(); } • Option 2 alert.showAndWait().ifPresent(response -> { if (response == ButtonType.OK) { formatSystem(); } }); • Option 3 alert.showAndWait() .filter(response -> response == ButtonType.OK) .ifPresent(response -> formatSystem()); 77

Slide 78

Slide 78 text

Optional API? • Optional API is API for handling NullPointerExceptions • This might crash if some of these return NULL • String version = computer.getSoundcard().getUSB().getVersion(); • A lot nested checks (if not null) is required here. • Java 8 Introduces a new class called java.util.Optional to handle this • Single-value container that either contains a value or not (null) 78

Slide 79

Slide 79 text

class Car { private Optional motor; public Car(Motor motor) { // motor may hold value or null this.motor = Optional.ofNullable(motor); } public Car() { this.motor = Optional.empty(); } public Optional getMotor() { return motor; } public void setMotor(Motor motor) { this.motor = Optional.of(motor); } } class Motor { private int horsePower; public Motor(int horsePower) { this.horsePower = horsePower; } public int getHorsePower() { return horsePower; } public void setHorsePower(int horsePower) { this.horsePower = horsePower; } } class Main { public static void main(String[] args) { Car datsun = new Car( new Motor(40) ); datsun.getMotor().ifPresent(motor -> { System.out.println(motor.getHorsePower()); }); Car skoda = new Car( null ); skoda.getMotor().ifPresent(motor -> { System.out.println(motor.getHorsePower()); }); Car peugeot = new Car(); peugeot.getMotor().ifPresent(motor -> { System.out.println(motor.getHorsePower()); }); } } Programmer is now forced to think about what happens if the result is null! 79

Slide 80

Slide 80 text

ifPresent 80

Slide 81

Slide 81 text

Consumer 81

Slide 82

Slide 82 text

Using Inner Class class Main { public static void main(String[] args) { Car datsun = new Car( new Motor(40) ); datsun.getMotor().ifPresent(new java.util.function.Consumer() { public void accept(Motor m) { System.out.println(m.getHorsePower()); } }); } } 82

Slide 83

Slide 83 text

Alert: Information Alert alert = new Alert(Alert.AlertType.INFORMATION); alert.setTitle("Information Dialog"); alert.setHeaderText("Look, a Information Dialog"); alert.setContentText("Are you ok with this?"); Optional result = alert.showAndWait(); if(result.isPresent()) { System.out.println("Ok button was pressed"); } else { System.out.println("Ok button was not pressed."); } 83

Slide 84

Slide 84 text

Alert: Warning Alert alert = new Alert(Alert.AlertType.WARNING); alert.setTitle("Warning Dialog"); alert.setHeaderText(null); alert.setContentText("I have a warning message"); Optional result = alert.showAndWait(); result.ifPresent((buttonType) -> System.out.println("Ok was pressed")); 84

Slide 85

Slide 85 text

Alert: Confirmation Alert alert = new Alert(Alert.AlertType.CONFIRMATION); alert.setTitle("Information Dialog"); alert.setHeaderText("Look, a Confirmation Dialog"); alert.setContentText("Are you ok with this?"); Optional result = alert.showAndWait(); // If a value is present in this Optional, returns the value, // otherwise throws NoSuchElementException. // In the case of Confirmation alert, it will always return non - // null value! // When closing the dialog, we will get cancel buttontype. ButtonType buttonType = result.get(); if(buttonType == ButtonType.OK) { System.out.println("Ok!"); } else { System.out.println("Cancel"); } 85

Slide 86

Slide 86 text

Text Input Dialog TextInputDialog dialog = new TextInputDialog(""); dialog.setTitle("Text Input Dialog"); dialog.setHeaderText(null); dialog.setContentText("Please enter your name:"); Optional result = dialog.showAndWait(); result.ifPresent(name -> System.out.println("Your name: " + name)); 86 Notice now that the Optional type is String!

Slide 87

Slide 87 text

List Input List choices = new ArrayList<>(); choices.add("a"); choices.add("b"); choices.add("c"); ChoiceDialog dialog = new ChoiceDialog<>("b", choices); dialog.setTitle("Choice Dialog"); dialog.setHeaderText("Look, a Choice Dialog"); dialog.setContentText("Choose your letter:"); Optional result = dialog.showAndWait(); result.ifPresent(letter -> System.out.println("Your choice: " + letter)); 87

Slide 88

Slide 88 text

Lab 08 88

Slide 89

Slide 89 text

Java FX Concurrency 89

Slide 90

Slide 90 text

JavaFX Platform and Concurrency • JavaFX has different threads • Application thread • Event thread • Animation thread • Prism render thred • Media thread • You can launch more threads if you like • And you should for any slow operations • You can't access GUI from worker thread! • Platform.runLater() 90

Slide 91

Slide 91 text

Platform • javafx.application.Platform is a utility class that has four important static methods • void exit() • boolean isFxApplicationThread() • boolean isSupported(ConditionalFeature f) • void runLater(Runnable runnable) 91

Slide 92

Slide 92 text

Basic Thread • Pass a Runnable – object to the thread (run() method) • Thread thread = new Thread(() -> doSomething()); • thread.start(); 92

Slide 93

Slide 93 text

Example -> Leads to Exception public void buttonClicked(ActionEvent e) { Thread thread = new Thread(this::runInThread); thread.start(); } public void runInThread() { int i = 0; while(i < 10) { simulateSlow(); System.out.println(i++); } button.setText("Done"); // java.lang.IllegalStateException: Not on FX application thread.. } public void simulateSlow() { try { Thread.sleep(100); } catch(InterruptedException e) { e.printStackTrace(); } } 93

Slide 94

Slide 94 text

Solution public void buttonClicked(ActionEvent e) { Thread thread = new Thread(this::runInThread); thread.start(); } public void runInThread() { int i = 0; while(i < 10) { simulateSlow(); System.out.println(i++); } Platform.runLater(() -> button.setText("Done")); } public void simulateSlow() { try { Thread.sleep(100); } catch(InterruptedException e) { e.printStackTrace(); } } 94

Slide 95

Slide 95 text

Updating UI constantly public void buttonClicked(ActionEvent e) { Thread thread = new Thread(this::runInThread); thread.start(); } public void runInThread() { int i = 0; while(i < 10) { simulateSlow(); final int number = i; i++; Platform.runLater(() -> button.setText("i = " + (number))); } Platform.runLater(() -> button.setText("Done")); } public void simulateSlow() { try { Thread.sleep(500); } catch(InterruptedException e) { e.printStackTrace(); } } 95

Slide 96

Slide 96 text

With One Method: can be confusing? public void buttonClicked(ActionEvent e) { Thread thread = new Thread(() -> { int i = 0; while(i < 10) { simulateSlow(); final int number = i; i++; Platform.runLater(() -> button.setText("i = " + (number))); } Platform.runLater(() -> button.setText("Done")); }); thread.start(); } 96

Slide 97

Slide 97 text

Problems • Double nesting Runnables, can be hard to read • Lot of Runnables in the event queue • Let's see alternative API for this 97

Slide 98

Slide 98 text

JavaFX: Task, Service • Task and Service implements a Worker interface • Task extends FutureTask that implements Runnable • So you can just • class MyTask extends Task<..> { .. } • Thread t = new Thread(new MyTask()); • In MyTask update a property. In UI, bind the property to some UI component • More about binding • http://docs.oracle.com/javafx/2/binding/jfxpub-binding.htm 98

Slide 99

Slide 99 text

Example public void buttonClicked(ActionEvent e) { class MyTask extends Task { @Override protected Void call() throws Exception { int i=0; int max = 10; while(i < max) { simulateSlow(); updateMessage("i = " + i); i++; } return null; } } MyTask task = new MyTask(); // Bind button's title to the task's message property! button.textProperty().bind(task.messageProperty()); Thread thread = new Thread(task); thread.start(); } 99

Slide 100

Slide 100 text

Task implements Worker • Worker interface provides lifecycle • Every Worker begins with READY state • When starting the thread, it goes SCHEDULED • When doing the work, it's RUNNING • When canceled, it's CANCELLED • When completed, it's SUCCEEDED • If exception, then FAILED • The result of the worker execution can be seen from value property • Possible to cancel the Worker via cancel() method • Worker's progress can be monitored • workDone, totalWork, progress • When workDone == totalWork, the progress is 100% • When READY or SCHEDULED, workDone and progress are -1 • When SUCCEEDED, workDone == totalWork • You can have listeners to the Worker 100

Slide 101

Slide 101 text

Example class MyTask extends Task { @Override protected Integer call() throws Exception { int i=0; int max = 10; int sum = 0; while(i <= max) { simulateSlow(); if(isCancelled()) { updateMessage("Cancelled"); break; } updateProgress(i, max); updateMessage("i = " + i); i++; sum += i; } return sum; } } public void observeTask(ActionEvent e) { System.out.println("State = " + task.getState()); System.out.println("Progress = " + task.getProgress()); System.out.println("Work Done = " + task.getWorkDone()); System.out.println("Total Work = " + task.getTotalWork()); } public void stopTask(ActionEvent e) { task.cancel(); } public void startTask(ActionEvent e) { if(task.getState() != Worker.State.RUNNING || task.getState() != Worker.State.SCHEDULED) { task = new MyTask(); task.setOnSucceeded(new EventHandler() { @Override public void handle(WorkerStateEvent event) { startTask.setText("SUM = " + task.getValue()); } }); window.titleProperty().bind(task.messageProperty()); Thread thread = new Thread(task); thread.start(); } } 101

Slide 102

Slide 102 text

Service • Service also implements Worker • Observe the state, cancel it etc • Task is a one off thing. You need to create it again if needed. • Service is a reusable Worker, can be reset and restarted • By Default uses Thread Pool Executor 102

Slide 103

Slide 103 text

Lab 09 103

Slide 104

Slide 104 text

Java FX CSS 104

Slide 105

Slide 105 text

CSS • JavaFX CSS provides ability to customize the UI • Based on W3C CSS 2.1 • JavaFX CSS Extensions, prefix of –fx- • CSS can be applied to any node • JavaFX 8 uses modena.css • https://gist.github.com/maxd/63691840fc372f22f470 • Can be found in jfxrt.jar • We can define your own css • We can give custom css to just one node 105

Slide 106

Slide 106 text

Example 106

Slide 107

Slide 107 text

Setting Styles in Code Button buttonColor = new Button("Color"); buttonColor.setStyle("-fx-text-fill: white; -fx- background-color:gray; -fx-border-color:blue;"); 107

Slide 108

Slide 108 text

Load External CSS Scene scene = new Scene(box, 640, 480); scene.getStylesheets().add(getClass().getResource("./theme .css").toExternalForm()); 108

Slide 109

Slide 109 text

Sample Definition .custom-button { -fx-font: 16px "Serif"; -fx-padding: 10; -fx-background-color: #CCFF99; } // mybutton.getStyleClass().add("custom-button"); 109

Slide 110

Slide 110 text

Overriding .button { -fx-font: 16px "Serif"; -fx-padding: 10; -fx-background-color: #CCFF99; } 110

Slide 111

Slide 111 text

Setting Colors .custom1 { -fx-text-fill: #000000; -fx-background-color: skyblue; -fx-border-color: rgb(255,0,0); -fx-border-width: 3; } 111

Slide 112

Slide 112 text

Java FX Media 112

Slide 113

Slide 113 text

Support • Audio • MP3 • WAV • AIFF • AAC • Video • FLV • MPEG-4 H.264/AVC 113

Slide 114

Slide 114 text

Features • HTTP, File support • Progressive download • Seeking • Buffer progress • Playback functions 114

Slide 115

Slide 115 text

Core components • Media • A media resource, containing information about the media, such as its source, resolution, and metadata • MediaPlayer • The key component providing the controls for playing media • MediaView • A Node object to support animation, translucency, and effects 115

Slide 116

Slide 116 text

Structure 116

Slide 117

Slide 117 text

Usage // Source must be valid URI String mediaURI = getClass().getResource("soundfile.mp3").toExternalForm(); Media media = new Media(mediaURI); MediaPlayer mediaPlayer = new MediaPlayer(media); mediaPlayer.setAutoPlay(true); MediaView mediaView = new MediaView(mediaPlayer); 117

Slide 118

Slide 118 text

Lab 10 118

Slide 119

Slide 119 text

Java FX Effects 119

Slide 120

Slide 120 text

JavaFX Effects • Enhance the Look and Feel • javax.scene.effect • Bloom, Blur, Drop Shadow, Inner Shadow, Reflection, Lightning Effect, Perspective • And you can also chain these 120

Slide 121

Slide 121 text

Bloom /* The bloom effect makes brighter portions an image appear to glow, based on a configurable threshold. The threshold varies from 0.0 to 1.0. By default, the threshold is set to 0.3 */ Bloom bloom = new Bloom(); bloom.setThreshold(0.1); 121

Slide 122

Slide 122 text

Box Blur /* The BoxBlur is a blur effect that uses a simple box filter kernel, with separately configurable sizes in both dimensions that control the amount of blur applied to an object, and an Iterations parameter that controls the quality of the resulting blur. */ BoxBlur boxblur = new BoxBlur(); boxblur.setWidth(5); boxblur.setHeight(5); boxblur.setIterations(3); 122

Slide 123

Slide 123 text

Motion Blur /* A motion blur effect uses a Gaussian blur, with a configurable radius and angle to create the effect of a moving object. */ MotionBlur motionBlur = new MotionBlur(); motionBlur.setRadius(25.0f); motionBlur.setAngle(45.0f); 123

Slide 124

Slide 124 text

Gaussian Blur // The Gaussian blur is an effect that uses a Gaussian algorithm with a configurable radius to blur objects. GaussianBlur gaussianBlur = new GaussianBlur(); gaussianBlur.setRadius(10.0f); 124

Slide 125

Slide 125 text

Drop Shadow /* A drop shadow is an effect that renders a shadow of the content to which it is applied. You can specify the color, the radius, the offset, and some other parameters of the shadow.*/ DropShadow ds1 = new DropShadow(); ds1.setOffsetY(4.0f); ds1.setOffsetX(4.0f); ds1.setColor(Color.GRAY); 125

Slide 126

Slide 126 text

Inner Shadow /* An inner shadow is an effect that renders a shadow inside the edges of the given content with the specified color, radius, and offset. */ InnerShadow is = new InnerShadow(); is.setOffsetX(2.0f); is.setOffsetY(2.0f); 126

Slide 127

Slide 127 text

Reflection // Reflection is an effect that renders a reflected version of the object below the actual object. Reflection r = new Reflection(); r.setFraction(0.5); 127

Slide 128

Slide 128 text

Lightning /* The lighting effect simulates a light source shining on the given content, which can be used to give flat objects a more realistic three-dimensional appearance. */ Light.Distant light = new Light.Distant(); light.setAzimuth(-135.0f); Lighting l = new Lighting(); l.setLight(light); l.setSurfaceScale(5.0f); 128

Slide 129

Slide 129 text

Perspective // The perspective effect creates a three-dimensional effect of otherwise two- dimensional object. PerspectiveTransform pt = new PerspectiveTransform(); pt.setUlx(10.0f); pt.setUly(10.0f); pt.setUrx(210.0f); pt.setUry(40.0f); pt.setLrx(210.0f); pt.setLry(60.0f); pt.setLlx(10.0f); pt.setLly(90.0f); 129

Slide 130

Slide 130 text

Chaing /* Some of the effects have an input property that you can use to create a chain of effects. The chain of effects can be a tree-like structure, because some effects have two inputs and some do not have any. */ DropShadow ds = new DropShadow(); ds.setOffsetY(5.0); ds.setOffsetX(5.0); ds.setColor(Color.GRAY); Reflection reflection = new Reflection(); // AS INPUT! ds.setInput(reflection); 130

Slide 131

Slide 131 text

Java FX Transitions 131

Slide 132

Slide 132 text

JavaFX Transitions and Animations • Transitions • Fade • Fill • Rotate • Scale • Stroke • Translate • Path • Timeline Animation • Interpolators 132

Slide 133

Slide 133 text

Fade FadeTransition fadeTransition = new FadeTransition(); fadeTransition.setDuration(Duration.millis(1000)); fadeTransition.setFromValue(1.0); fadeTransition.setToValue(0.0); fadeTransition.setCycleCount(2); fadeTransition.setAutoReverse(true); fadeTransition.setNode(someNode); fadeTransition.play(); 133

Slide 134

Slide 134 text

Rotate RotateTransition rotateTransition = new RotateTransition(); //Setting the duration for the transition rotateTransition.setDuration(Duration.millis(1000)); //Setting the angle of the rotation rotateTransition.setByAngle(360); rotateTransition.setNode(someNode); 134

Slide 135

Slide 135 text

Scale ScaleTransition scaleTransition = new ScaleTransition(); scaleTransition.setDuration(Duration.millis(1000)); scaleTransition.setToX(2.0); scaleTransition.setToY(2.0); scaleTransition.setCycleCount(2); scaleTransition.setAutoReverse(true); 135

Slide 136

Slide 136 text

Translate TranslateTransition translateTransition = new TranslateTransition(); translateTransition.setDuration(Duration.millis(1000)); translateTransition.setToX(50); translateTransition.setCycleCount(2); translateTransition.setAutoReverse(true); 136

Slide 137

Slide 137 text

Lab 12 - 13 137

Slide 138

Slide 138 text

Java FX Drawing and Shapes 138

Slide 139

Slide 139 text

Basic Drawing public class TreeViewExample extends Application { public static void main(String[] args) { launch(args); } @Override public void start(Stage primaryStage) { Canvas canvas = new Canvas(300, 250); Group group = new Group(canvas); draw(canvas); primaryStage.setScene(new Scene(group, 300, 250)); primaryStage.show(); } private void draw(Canvas canvas) { GraphicsContext gc = canvas.getGraphicsContext2D(); gc.setFill(Color.GREEN); gc.setStroke(Color.BLUE); gc.setLineWidth(5); gc.strokeLine(40, 10, 10, 40); gc.fillOval(10, 60, 30, 30); } } 139

Slide 140

Slide 140 text

Shapes public class TreeViewExample extends Application { public static void main(String[] args) { launch(args); } @Override public void start(Stage primaryStage) { Line line = new Line(100, 10, 10, 110); Rectangle rect = new Rectangle(100, 100, 50, 50); Polygon polygon = new Polygon(); polygon.getPoints().addAll(new Double[]{ 0.0, 0.0, 20.0, 10.0, 10.0, 20.0 }); Group group = new Group(); group.getChildren().addAll(line, rect, polygon); primaryStage.setScene(new Scene(group, 300, 250)); primaryStage.show(); } } 140

Slide 141

Slide 141 text

Shapes • Line • Rectangle • Rounded Rectangle • Circle • Ellipse • Polygon • Polyline • Cubic Curve • Quad Curve • Arc 141

Slide 142

Slide 142 text

Operations on 2D Objects • Union • Intersection • Subtraction 142

Slide 143

Slide 143 text

Union Shape shape = Shape.union(circle1, circle2); 143

Slide 144

Slide 144 text

Intersection Shape shape = Shape.intersect(circle1, circle2); 144

Slide 145

Slide 145 text

Subtraction Shape shape = Shape.subtract(circle1, circle2); 145

Slide 146

Slide 146 text

Lab 14 146

Slide 147

Slide 147 text

Best Practices Localization, MVC, Properties and Bindings 147

Slide 148

Slide 148 text

MVC 148

Slide 149

Slide 149 text

MVC • Model View Controller in JavaFX is easy • For clean separation of the View, use FXML • You can define your own controller class for the view • And the Model can be whatever 149

Slide 150

Slide 150 text

FXML Example 150

Slide 151

Slide 151 text

FXML and Java public class MyApp extends Application { public static void main(String[] args) { launch(args); } @Override public void start(Stage primaryStage) throws Exception { Pane myPane = (Pane) FXMLLoader.load(getClass().getResource("myxml.xml")); Scene myScene = new Scene(myPane); primaryStage.setScene(myScene); primaryStage.show(); } } 151

Slide 152

Slide 152 text

Example of Event Handling in FXML 152

Slide 153

Slide 153 text

And the code.. public class MyApp extends Application { public static void main(String[] args) { launch(args); } @Override public void start(Stage primaryStage) throws Exception { Pane myPane = (Pane) FXMLLoader.load(getClass().getResource("myxml.xml")); Scene myScene = new Scene(myPane); primaryStage.setScene(myScene); primaryStage.show(); } @FXML private Text myText; @FXML protected void handleButtonClick(ActionEvent event) { myText.setText("Clicked!"); } } 153

Slide 154

Slide 154 text

Scene Builder 154

Slide 155

Slide 155 text

Localization 155

Slide 156

Slide 156 text

Localization Locale locale = new Locale("fi", "FI"); ResourceBundle bundle = ResourceBundle.getBundle("strings", locale); Parent root = FXMLLoader.load(getClass().getResource("myxml.fxml"), bundle); Scene myScene = new Scene(root); primaryStage.setScene(myScene); primaryStage.show(); 156

Slide 157

Slide 157 text

strings.fi_FI.properties title = Painoindeksilaskuri mass = Paino height = Pituus calculate = Laske result = Painoindeksisi on 157

Slide 158

Slide 158 text

fxml 158

Slide 159

Slide 159 text

Properties and Bindings 159

Slide 160

Slide 160 text

Properties and Bindings? • In JavaFX (and JavaBeans) you can listen to changes of properties (attributes) of some object • All properties in JavaFX are observable • Property can be a value or a collection of values • In JavaFX properties are objects • Abstract class IntegerProperty, concrete implementations for read/write (SimpleIntegerProperty) and for read only (ReadOnlyIntegerWrapper) • IntegerProperty counter = new SimpleIntegerProperty(100); 160

Slide 161

Slide 161 text

Example public class Main extends Application { public static void main(String[] args) { launch(args); } @Override public void start(Stage primaryStage) { primaryStage.setTitle("Hello World!"); TextArea tx; primaryStage.setScene(new Scene(tx = new TextArea(), 300, 250)); primaryStage.show(); IntegerProperty counter = new SimpleIntegerProperty(1); int counterValue = counter.get(); tx.appendText("Counter: " + counterValue + "\n"); counter.set(2); counterValue = counter.get(); tx.appendText("Counter: " + counterValue + "\n"); } } 161

Slide 162

Slide 162 text

Different Properties (also others available) Type Properties type int IntegerProperty double DoubleProperty short ShortProperty String StringProperty Object ObjectProperty 162

Slide 163

Slide 163 text

Using Property in Class class Book { private StringProperty title = new SimpleStringProperty(this, "title", "Unknown"); public StringProperty titleProperty() { return title; } public final String getTitle() { return title.get(); } public final void setTitle(String title) { this.title.set(title); } } 163

Slide 164

Slide 164 text

Testing Book b = new Book(); b.titleProperty().set("My Book"); System.out.println(b.titleProperty().get()); // My Book b.setTitle("Hello"); System.out.println(b.getTitle()); // Hello StringProperty sp = b.titleProperty(); System.out.println(sp.getValue().equals("Hello")); // true System.out.println(sp.getName().equals("title")); // true System.out.println(sp.getBean() == b); // true 164

Slide 165

Slide 165 text

JavaFX TextArea 165 public class Main extends Application { public static void main(String[] args) { launch(args); } @Override public void start(Stage primaryStage) { primaryStage.setTitle("Hello World!"); TextArea tx; primaryStage.setScene(new Scene(tx = new TextArea(), 300, 250)); primaryStage.show(); tx.textProperty().set("Hello World"); StringProperty sp = tx.textProperty(); System.out.println(sp.getValue().equals("Hello World")); // true System.out.println(sp.getName().equals("text")); // true System.out.println(sp.getBean() == tx); // true } }

Slide 166

Slide 166 text

class Point { private IntegerProperty xPos = new SimpleIntegerProperty(this, "xPos", 0); private IntegerProperty yPos = new SimpleIntegerProperty(this, "yPos", 0); public IntegerProperty xPosProperty() { return xPos; } public IntegerProperty yPosProperty() { return yPos; } public final int getX() { return xPos.get(); } public final int getY() { return yPos.get(); } public String toString() { return "" + getX() + ", " + getY(); } } 166 If you build 1000 array of Point objects, you will end up a lot of objects in memory!

Slide 167

Slide 167 text

Lazy Loading 1 class Point { private static final int DEFAULT_VALUE = 0; private IntegerProperty xPos; public IntegerProperty xPosProperty() { if(xPos == null) { xPos = new SimpleIntegerProperty(this, "xPos", DEFAULT_VALUE); } return xPos; } public final void setX(int x) { if(xPos != null || x != DEFAULT_VALUE) { xPosProperty().set(x); } } public final int getX() { if(xPos == null) { return DEFAULT_VALUE; } else { return xPos.get(); } } } 167 Will be created if the need for the xPos value. By default 0 is returned

Slide 168

Slide 168 text

Lazy Loading 2 class Point { private int xPosValue; private IntegerProperty xPosProperty; public final void setX(int x) { if(xPosProperty == null) { xPosValue = x; } else { xPosProperty.set(x); } } public final int getX() { if(xPosProperty == null) { return xPosValue; } else { return xPosProperty.get(); } } public IntegerProperty xPosProperty() { if(xPosProperty == null) { xPosProperty = new SimpleIntegerProperty(this, "xPos", xPosValue); } return xPosProperty; } } 168 The IntegerProperty is created when this method is called.

Slide 169

Slide 169 text

Events • All the properties, like IntegerProperty, implements ObservableValue, so a value that we can observe • The ObservableValue supports Change Events – when value has changed 169

Slide 170

Slide 170 text

ChangeListener public class Main extends Application implements ChangeListener { public static void main(String[] args) { launch(args); } @Override public void start(Stage primaryStage) { ... IntegerProperty property = new SimpleIntegerProperty(0); property.addListener(this); property.set(9); property.set(10); } @Override public void changed(ObservableValue extends Number> observable, Number oldValue, Number newValue) { System.out.println(newValue); } } 170

Slide 171

Slide 171 text

Binding • Possible to bind properties • Binding of properties in beans • High-level binding with the Fluent API • Low-level binding 171

Slide 172

Slide 172 text

Binding Properties • Bidirectional • someTextField.textProperty().bindBidirectional(someOtherTextFie ld.textProperty()); • Directional • someTextField.textProperty().bind(someOtherTextField.textProper ty()); • Possible to cast from String property to Number and vice versa • someTextField.textProperty().bindBidirectional(scene.widthPrope rty(), new NumberStringConverter()); 172

Slide 173

Slide 173 text

High Level Binding: Bindings - class IntegerProperty num1 = new SimpleIntegerProperty(1); IntegerProperty num2 = new SimpleIntegerProperty(2); NumberBinding sum = Bindings.add(num1,num2); System.out.println(sum.getValue()); num1.setValue(2); System.out.println(sum.getValue()); 173

Slide 174

Slide 174 text

High Level Binding: Using Properties IntegerProperty num1 = new SimpleIntegerProperty(1); IntegerProperty num2 = new SimpleIntegerProperty(2); NumberBinding sum = num1.add(num2); System.out.println(sum.getValue()); num1.setValue(2); System.err.println(sum.getValue()); 174

Slide 175

Slide 175 text

High Level Binding: Example // Create new NumberBinding that is updated with height * width; NumberBinding nb = myScene.heightProperty().multiply(myScene.widthProperty()); // The bind expects a StringBinding and you can cast it textField.textProperty().bind(nb.asString()); 175

Slide 176

Slide 176 text

Different Bindings • NumberBinding (Interface) • DoubleBinding, FloatBinding, LongBinding, IntegerBinding • BooleanBinding • StringBinding 176

Slide 177

Slide 177 text

Implementing Own Binding public class BmiLogicBinding extends StringBinding { private StringProperty mass; private StringProperty height; public BmiLogicBinding(TextField mass, TextField height) { bind(this.mass = mass.textProperty(), this.height = height.textProperty()); } @Override protected String computeValue() { try { double h = Double.parseDouble(height.getValue()); double m = Double.parseDouble(mass.getValue()); return "" + (m / (h * h)); } catch(Exception e) { return ""; } } } 177

Slide 178

Slide 178 text

Lab 15 178

Slide 179

Slide 179 text

Java FX Charts 179

Slide 180

Slide 180 text

Charts! 180

Slide 181

Slide 181 text

JavaFX Charts • With JavaFX you can build charts • When defining the data model to chart you must distinguish between two-axis charts and charts that do not use axes • Two-axis chart • XYChart superclass and XYData to specify data model • area, line, bar, scatter, bubble charts • With two-axis chart you can define series of data using XYChart.series • Non-two-axis chart • PieChart • You can specify title, title location, position of chart legend • You can listen to events in charts • You can animate charts 181

Slide 182

Slide 182 text

Pie Chart import javafx.application.Application; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.scene.Scene; import javafx.stage.Stage; import javafx.scene.chart.*; public class Main extends Application { @Override public void start(Stage stage) { stage.setTitle("Imported Fruits"); stage.setWidth(500); stage.setHeight(500); ObservableList 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"); stage.setScene(new Scene(chart, 640, 480)); stage.show(); } public static void main(String[] args) { launch(args); } } 182

Slide 183

Slide 183 text

LineChart • LineChart with X and Y axis • Presents data as a series of points connected by straight lines • Create LineChart and use XYChart.Series to create the data 183

Slide 184

Slide 184 text

Define Axis • LineChart constructor • LineChart lineChart = new LineChart(Axis xAxis, Axis yAxis); • Axis is abstract and a base class for • CategoryAxis extends Axis • NumberAxis extends ValueAxis (which extends Axis) • For numbers, use NumberAxis, for Strings, use CategoryAxis 184

Slide 185

Slide 185 text

Creating ListChart NumberAxis monthAxis = new NumberAxis(); NumberAxis numberOfIceCreamsAxis = new NumberAxis(); monthAxis.setLabel("Number of Month"); LineChart lineChart = new LineChart(monthAxis, numberOfIceCreamsAxis); lineChart.setTitle("Monitoring Ice Cream Amount"); 185

Slide 186

Slide 186 text

Series XYChart.Series data = new XYChart.Series(); data.setName("Number of Ice Creams"); //populating the series with data data.getData().add(new XYChart.Data(1, 1)); data.getData().add(new XYChart.Data(2, 4)); data.getData().add(new XYChart.Data(3, 10)); data.getData().add(new XYChart.Data(4, 11)); data.getData().add(new XYChart.Data(5, 20)); data.getData().add(new XYChart.Data(6, 200)); data.getData().add(new XYChart.Data(7, 200)); data.getData().add(new XYChart.Data(8, 50)); data.getData().add(new XYChart.Data(9, 43)); data.getData().add(new XYChart.Data(10, 3)); data.getData().add(new XYChart.Data(11, 2)); data.getData().add(new XYChart.Data(12, 1)); lineChart.getData().add(data); 186

Slide 187

Slide 187 text

• import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.chart.CategoryAxis; import javafx.scene.chart.LineChart; import javafx.scene.chart.NumberAxis; import javafx.scene.chart.XYChart; import javafx.stage.Stage; public class Main extends Application { @Override public void start(Stage stage) { stage.setTitle("Line Chart Sample"); final CategoryAxis monthAxis = new CategoryAxis(); final NumberAxis numberOfIceCreamsAxis = new NumberAxis(); monthAxis.setLabel("Number of Month"); numberOfIceCreamsAxis.setLabel("Amount"); final LineChart lineChart = new LineChart(monthAxis, numberOfIceCreamsAxis); lineChart.setTitle("Monitoring Ice Cream Amount"); XYChart.Series data = new XYChart.Series(); data.setName("Number of Ice Creams"); //populating the series with data data.getData().add(new XYChart.Data("Jan", 1)); data.getData().add(new XYChart.Data("Feb", 4)); data.getData().add(new XYChart.Data("Mar", 10)); data.getData().add(new XYChart.Data("Apr", 11)); data.getData().add(new XYChart.Data("May", 20)); data.getData().add(new XYChart.Data("Jun", 200)); data.getData().add(new XYChart.Data("Jul", 200)); data.getData().add(new XYChart.Data("Aug", 50)); data.getData().add(new XYChart.Data("Sep", 43)); data.getData().add(new XYChart.Data("Oct", 3)); data.getData().add(new XYChart.Data("Nov", 2)); data.getData().add(new XYChart.Data("Dec", 1)); lineChart.getData().add(data); Scene scene = new Scene(lineChart,800,600); stage.setScene(scene); stage.show(); } public static void main(String[] args) { launch(args); } } 187

Slide 188

Slide 188 text

Series XYChart.Series iceCreamSeries = new XYChart.Series(); iceCreamSeries.setName("Number of Ice Creams"); //populating the series with data iceCreamSeries.getData().add(new XYChart.Data("Jan", 1)); iceCreamSeries.getData().add(new XYChart.Data("Feb", 4)); iceCreamSeries.getData().add(new XYChart.Data("Mar", 10)); iceCreamSeries.getData().add(new XYChart.Data("Apr", 11)); iceCreamSeries.getData().add(new XYChart.Data("May", 20)); iceCreamSeries.getData().add(new XYChart.Data("Jun", 200)); iceCreamSeries.getData().add(new XYChart.Data("Jul", 200)); iceCreamSeries.getData().add(new XYChart.Data("Aug", 50)); iceCreamSeries.getData().add(new XYChart.Data("Sep", 43)); iceCreamSeries.getData().add(new XYChart.Data("Oct", 3)); iceCreamSeries.getData().add(new XYChart.Data("Nov", 2)); iceCreamSeries.getData().add(new XYChart.Data("Dec", 1)); XYChart.Series temperatureSeries = new XYChart.Series(); temperatureSeries.setName("Temperature "); temperatureSeries.getData().add(new XYChart.Data("Jan", -10)); temperatureSeries.getData().add(new XYChart.Data("Feb", -2)); temperatureSeries.getData().add(new XYChart.Data("Mar", 2)); temperatureSeries.getData().add(new XYChart.Data("Apr", 4)); temperatureSeries.getData().add(new XYChart.Data("May", 12)); temperatureSeries.getData().add(new XYChart.Data("Jun", 16)); temperatureSeries.getData().add(new XYChart.Data("Jul", 22)); temperatureSeries.getData().add(new XYChart.Data("Aug", 17)); temperatureSeries.getData().add(new XYChart.Data("Sep", 14)); temperatureSeries.getData().add(new XYChart.Data("Oct", 8)); temperatureSeries.getData().add(new XYChart.Data("Nov", 2)); temperatureSeries.getData().add(new XYChart.Data("Dec", -2)); lineChart.getData().addAll(iceCreamSeries, temperatureSeries); 188

Slide 189

Slide 189 text

BarChart import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.chart.BarChart; import javafx.scene.chart.CategoryAxis; import javafx.scene.chart.NumberAxis; import javafx.scene.chart.XYChart; import javafx.stage.Stage; public class Main extends Application { final static String austria = "Austria"; final static String brazil = "Brazil"; final static String france = "France"; final static String italy = "Italy"; final static String usa = "USA"; @Override public void start(Stage stage) { stage.setTitle("Bar Chart Sample"); final CategoryAxis xAxis = new CategoryAxis(); final NumberAxis yAxis = new NumberAxis(); final BarChart bc = new BarChart(xAxis,yAxis); bc.setTitle("Country Summary"); xAxis.setLabel("Country"); yAxis.setLabel("Value"); XYChart.Series series1 = new XYChart.Series(); series1.setName("2003"); series1.getData().add(new XYChart.Data(austria, 25601.34)); series1.getData().add(new XYChart.Data(brazil, 20148.82)); series1.getData().add(new XYChart.Data(france, 10000)); series1.getData().add(new XYChart.Data(italy, 35407.15)); series1.getData().add(new XYChart.Data(usa, 12000)); Scene scene = new Scene(bc,800,600); bc.getData().addAll(series1); stage.setScene(scene); stage.show(); } public static void main(String[] args) { launch(args); } } 189

Slide 190

Slide 190 text

StackedBarChart import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.chart.*; import javafx.stage.Stage; public class Main extends Application { final static String austria = "Austria"; final static String brazil = "Brazil"; final static String france = "France"; final static String italy = "Italy"; final static String usa = "USA"; @Override public void start(Stage stage) { stage.setTitle("Bar Chart Sample"); final CategoryAxis xAxis = new CategoryAxis(); final NumberAxis yAxis = new NumberAxis(); final StackedBarChart bc = new StackedBarChart(xAxis,yAxis); bc.setTitle("Country Summary"); xAxis.setLabel("Country"); yAxis.setLabel("Value"); XYChart.Series series1 = new XYChart.Series(); series1.setName("2003"); series1.getData().add(new XYChart.Data(austria, 1)); series1.getData().add(new XYChart.Data(brazil, 2)); XYChart.Series series2 = new XYChart.Series(); series2.setName("2004"); series2.getData().add(new XYChart.Data(austria, 1)); series2.getData().add(new XYChart.Data(brazil, 2)); Scene scene = new Scene(bc,800,600); bc.getData().addAll(series1, series2); stage.setScene(scene); stage.show(); } public static void main(String[] args) { launch(args); } } 190

Slide 191

Slide 191 text

Lab 16 191

Slide 192

Slide 192 text

JavaFX Packaging 192

Slide 193

Slide 193 text

Packaging App • JavaFX apps are just .jar files, you can package the app to jar • Can be opened via double-click • Can be opened from command-line: java -jar MyApp.jar • The jar tool can be used for packaging, but for more advanced options you can use JavaFX Packager tool • Also it's possible to generate native package • Mac OS X: MyApp.app • Windows: MyApp.exe 193

Slide 194

Slide 194 text

javapackager • Synopsis • javapackager –taskcommand [-options] • Where –taskcommand • - createjar • - deploy • - makeall • ... • Where –options • -createjar –srcdir . –outfile MyFile.jar • -deploy –native • .. 194

Slide 195

Slide 195 text

Examples • Create jar • javapackager -createjar -appclass fi.company.Main -srcdir classes -outdir out -outfile MyApp.jar • Create self-contained native bundle • javapackager -deploy - Bruntime="/Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Con tents/Home/jre" -outdir outdir -outfile LottoApp -appclass fi.company.Main -native -srcdir out • In Windows, also install • Inno Setup – for generating .exe • WiX Setup – for generating .msi 195