Upgrade to Pro — share decks privately, control downloads, hide ads and more …

JavaFX Overview

JavaFX Overview

JavaFX Overview

Jussi Pohjolainen

March 11, 2017
Tweet

More Decks by Jussi Pohjolainen

Other Decks in Technology

Transcript

  1. 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
  2. 4

  3. 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
  4. 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
  5. 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
  6. 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
  7. 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
  8. 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
  9. 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
  10. 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
  11. Layouts • Layout containers for arrangements of UI controls •

    Lot of options • BorderPane • HBox, VBox • StackPane • GridPane • FlowPane • TilePane • AnchorPane 14
  12. 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
  13. Transformations and Effects • For transformations • translate • scale

    • rotate • ... • For Effects • Drop shadow • Reflection • Lightning 16
  14. 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
  15. 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
  16. 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
  17. 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
  18. 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
  19. 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.
  20. 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.
  21. 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
  22. 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.
  23. 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.
  24. 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
  25. 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
  26. 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
  27. 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
  28. 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
  29. 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
  30. 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
  31. 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
  32. 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
  33. 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
  34. 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
  35. 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
  36. 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
  37. 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
  38. 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
  39. 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
  40. 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
  41. 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
  42. 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
  43. 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.
  44. 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
  45. TreeView public class TreeViewExample extends Application { public static void

    main(String[] args) { launch(args); } @Override public void start(Stage primaryStage) { TreeItem<String> rootItem = new TreeItem<String> ("Inbox"); rootItem.setExpanded(true); for (int i = 1; i < 6; i++) { TreeItem<String> item = new TreeItem<String>("Message" + i); rootItem.getChildren().add(item); } TreeView<String> tree = new TreeView<String>(rootItem); primaryStage.setScene(new Scene(tree, 300, 250)); primaryStage.show(); } } 59
  46. 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
  47. 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
  48. 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
  49. 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
  50. 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<ActionEvent> { @Override public void handle(ActionEvent event) { Button b = (Button) event.getSource(); b.setText("Clicked!"); } } 66
  51. Example 2: With One Class public class Test extends Application

    implements EventHandler<ActionEvent> { 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
  52. Example 3: Inner Class public class Test extends Application {

    private Button button; class Listener implements EventHandler<ActionEvent> { @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
  53. 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<ActionEvent> { @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
  54. 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<ActionEvent>() { @Override public void handle(ActionEvent event) { button.setText("Clicked!"); } }); Scene scene = new Scene(button, 640, 480); primaryStage.setScene(scene); primaryStage.show(); } } 70
  55. 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
  56. 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
  57. 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
  58. 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
  59. Different options, uses Java 8 Optional API • Option 1

    Optional<ButtonType> 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
  60. 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<T> to handle this • Single-value container that either contains a value or not (null) 78
  61. class Car { private Optional<Motor> motor; public Car(Motor motor) {

    // motor may hold value or null this.motor = Optional.ofNullable(motor); } public Car() { this.motor = Optional.empty(); } public Optional<Motor> 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
  62. 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<Motor>() { public void accept(Motor m) { System.out.println(m.getHorsePower()); } }); } } 82
  63. 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<ButtonType> result = alert.showAndWait(); if(result.isPresent()) { System.out.println("Ok button was pressed"); } else { System.out.println("Ok button was not pressed."); } 83
  64. Alert: Warning Alert alert = new Alert(Alert.AlertType.WARNING); alert.setTitle("Warning Dialog"); alert.setHeaderText(null);

    alert.setContentText("I have a warning message"); Optional<ButtonType> result = alert.showAndWait(); result.ifPresent((buttonType) -> System.out.println("Ok was pressed")); 84
  65. 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<ButtonType> 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
  66. Text Input Dialog TextInputDialog dialog = new TextInputDialog(""); dialog.setTitle("Text Input

    Dialog"); dialog.setHeaderText(null); dialog.setContentText("Please enter your name:"); Optional<String> result = dialog.showAndWait(); result.ifPresent(name -> System.out.println("Your name: " + name)); 86 Notice now that the Optional type is String!
  67. List Input List<String> choices = new ArrayList<>(); choices.add("a"); choices.add("b"); choices.add("c");

    ChoiceDialog<String> dialog = new ChoiceDialog<>("b", choices); dialog.setTitle("Choice Dialog"); dialog.setHeaderText("Look, a Choice Dialog"); dialog.setContentText("Choose your letter:"); Optional<String> result = dialog.showAndWait(); result.ifPresent(letter -> System.out.println("Your choice: " + letter)); 87
  68. 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
  69. 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
  70. Basic Thread • Pass a Runnable – object to the

    thread (run() method) • Thread thread = new Thread(() -> doSomething()); • thread.start(); 92
  71. 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
  72. 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
  73. 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
  74. 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
  75. Problems • Double nesting Runnables, can be hard to read

    • Lot of Runnables in the event queue • Let's see alternative API for this 97
  76. 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
  77. Example public void buttonClicked(ActionEvent e) { class MyTask extends Task<Void>

    { @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
  78. 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
  79. Example class MyTask extends Task<Integer> { @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<WorkerStateEvent>() { @Override public void handle(WorkerStateEvent event) { startTask.setText("SUM = " + task.getValue()); } }); window.titleProperty().bind(task.messageProperty()); Thread thread = new Thread(task); thread.start(); } } 101
  80. 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
  81. 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
  82. Load External CSS Scene scene = new Scene(box, 640, 480);

    scene.getStylesheets().add(getClass().getResource("./theme .css").toExternalForm()); 108
  83. Sample Definition .custom-button { -fx-font: 16px "Serif"; -fx-padding: 10; -fx-background-color:

    #CCFF99; } // mybutton.getStyleClass().add("custom-button"); 109
  84. Support • Audio • MP3 • WAV • AIFF •

    AAC • Video • FLV • MPEG-4 H.264/AVC 113
  85. Features • HTTP, File support • Progressive download • Seeking

    • Buffer progress • Playback functions 114
  86. 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
  87. 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
  88. 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
  89. 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
  90. 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
  91. 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
  92. 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
  93. 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
  94. 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
  95. 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
  96. 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
  97. 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
  98. 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
  99. JavaFX Transitions and Animations • Transitions • Fade • Fill

    • Rotate • Scale • Stroke • Translate • Path • Timeline Animation • Interpolators 132
  100. 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
  101. 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
  102. 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
  103. Shapes • Line • Rectangle • Rounded Rectangle • Circle

    • Ellipse • Polygon • Polyline • Cubic Curve • Quad Curve • Arc 141
  104. 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
  105. FXML Example <?xml version="1.0" encoding="UTF-8"?> <?import javafx.scene.layout.*?> <?import javafx.scene.control.*?> <VBox

    alignment="CENTER" xmlns:fx="http://javafx.com/fxml"> <Label style="-fx-font: NORMAL 20 Tahoma;" text="Hello"> </Label> <Label style="-fx-font: NORMAL 20 Tahoma;" text="World"> </Label> </VBox> 150
  106. 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
  107. Example of Event Handling in FXML <?xml version="1.0" encoding="UTF-8"?> <?import

    javafx.scene.layout.*?> <?import javafx.scene.control.*?> <?import javafx.scene.text.*?> <VBox alignment="CENTER" xmlns:fx="http://javafx.com/fxml" fx:controller="mycompany.MyApp" > <Text fx:id="myText" text="Hello World"/> <Button text="Change Text" onAction="#handleButtonClick"/> </VBox> 152
  108. 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
  109. 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
  110. 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
  111. 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
  112. Different Properties (also others available) Type Properties type int IntegerProperty

    double DoubleProperty short ShortProperty String StringProperty Object ObjectProperty<T> 162
  113. 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
  114. 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
  115. 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 } }
  116. 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!
  117. 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
  118. 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.
  119. 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
  120. ChangeListener public class Main extends Application implements ChangeListener<Number> { 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
  121. Binding • Possible to bind properties • Binding of properties

    in beans • High-level binding with the Fluent API • Low-level binding 171
  122. 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
  123. 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
  124. 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
  125. 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
  126. 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
  127. 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
  128. 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<PieChart.Data> pieChartData = FXCollections.observableArrayList( new PieChart.Data("Grapefruit", 13), new PieChart.Data("Oranges", 25), new PieChart.Data("Plums", 10), new PieChart.Data("Pears", 22), new PieChart.Data("Apples", 30)); final PieChart chart = new PieChart(pieChartData); chart.setTitle("Imported Fruits"); stage.setScene(new Scene(chart, 640, 480)); stage.show(); } public static void main(String[] args) { launch(args); } } 182
  129. 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
  130. Define Axis • LineChart constructor • LineChart<X, Y> lineChart =

    new LineChart(Axis<X> xAxis, Axis<Y> yAxis); • Axis<T> is abstract and a base class for • CategoryAxis extends Axis<String> • NumberAxis extends ValueAxis<Number> (which extends Axis<Number>) • For numbers, use NumberAxis, for Strings, use CategoryAxis 184
  131. Creating ListChart NumberAxis monthAxis = new NumberAxis(); NumberAxis numberOfIceCreamsAxis =

    new NumberAxis(); monthAxis.setLabel("Number of Month"); LineChart<Number,Number> lineChart = new LineChart<Number,Number>(monthAxis, numberOfIceCreamsAxis); lineChart.setTitle("Monitoring Ice Cream Amount"); 185
  132. 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
  133. • 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<String,Number> lineChart = new LineChart<String,Number>(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
  134. 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
  135. 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<String,Number> bc = new BarChart<String,Number>(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
  136. 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<String,Number> bc = new StackedBarChart<String,Number>(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
  137. 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
  138. javapackager • Synopsis • javapackager –taskcommand [-options] • Where –taskcommand

    • - createjar • - deploy • - makeall • ... • Where –options • -createjar –srcdir . –outfile MyFile.jar • -deploy –native • .. 194
  139. 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