javafx - baresi.faculty.polimi.it · –a javafx application can have multiple windows open –each...
TRANSCRIPT
JavaFX
Java and JavaFX
• You must have a new version of Java• And install JavaFX
– Stable JavaFX11 but also JavaFX14– https://openjfx.io/openjfx-docs/#install-java– https://gluonhq.com/products/javafx/
• Removed from JDK 11– JavaFX 11 is now a standalone module– Developers must now explicitly include JavaFX modules
in applications
JavaFX
• JavaFX is somewhat inspired by Flash/Flex• Provides a client application platform for desktop,
mobile, and embedded systems• Is a runtime available as platform-specific SDK, as
jmod files, and as a set of Maven artifacts
Main modules
Architecture
JavaFX Public API’s and Scene Graph
Quantum Toolkit
PrismGlass Windowing
ToolkitMedia Engine
Web EngineJava
2DOpen
GL D3D
Java Virtual Machine
Structure
Scene graph
• Directed acyclic graph • Parent and child • Representation of the GUI component
11 | © 2011 Oracle Corporation – Proprietary and Confidential
Scene Graph
● Directed acyclic graph ● Parent and child ● Representation of the GUI component
Main concepts
• The stage is the outer frame for a JavaFX application– A JavaFX application can have multiple windows open– Each window has its own stage
• To display anything on a stage in a JavaFX application, you need a scene– A stage can only show one scene at a time, but it is possible
to exchange the scene at runtime
• All visual components (controls, layouts etc.) must be attached to a scene to be displayed– The scene must be attached to a stage for the whole scene
to be visible– The total object graph of all the controls, layouts etc.
attached to a scene is called the scene graph
Nodes
• All components attached to the scene graph are called nodes– Branch nodes can contain other nodes– Leaf nodes cannot contain other nodes
• Controls are components that provide some kind of control functionality– For a control to be visible it must be attached to
a Scene object
• Controls are usually nested inside a layout component that manages the layout of controls relative to each other
Layouts
• JavaFX layouts are components that contain other components inside them and manage their layout– A layout component must be attached to the scene
graph of a Scene object– It is possible to nest layout components inside other
layout components
Other elements
• Charts• 2D Graphics• 3D Graphics• Audio• Video• WebView
Node
Parent
Control
Shapes
Just a Stage
public class Main extends Application {@Overridepublic void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("My First JavaFX App");primaryStage.show();
}
public static void main(String[] args) {Application.launch(args);
}}
… and Scene
public class Main extends Application {@Overridepublic void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("My First JavaFX App");
Label label = new Label("Hello World, JavaFX !");Scene scene = new Scene(label, 400, 200);primaryStage.setScene(scene); primaryStage.show();
}
public static void main(String[] args) {Application.launch(args);
}}
… and another Stage
public class Main extends Application {public static void main(String[] args) {
launch(args);}
@Overridepublic void start(Stage primaryStage) {
primaryStage.setTitle("JavaFX App");
Stage stage = new Stage();stage.initModality(Modality.APPLICATION_MODAL);//stage.initModality(Modality.WINDOW_MODAL);//stage.initModality(Modality.NONE);
primaryStage.show();stage.showAndWait();
}}
Stage Style
• Decorated: a standard window with OS decorations (title bar and minimize / maximize / close buttons), and a white background
• Undecorated: a standard window without OS decorations, but still with a white background
• Transparent: an undecorated window with transparent background
• Unified: like a decorated stage, with no border between the decoration area and the main content
• Utility: a decorated window, but with minimal decorations
stage.initStyle(StageStyle.DECORATED);
2D elements
public class Main extends Application {@Overridepublic void start(Stage stage) {
Group root = new Group();Scene scene = new Scene(root,100,100);stage.setScene(scene);
Circle c1 = new Circle(50.0f, 50.0f, 40.0f, Color.RED);
root.getChildren().add(c1);stage.show();
}
public static void main(String[] args) {Application.launch(args);
} }
ImageViewpublic class Main extends Application {
@Overridepublic void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("ImageView Experiment 1");
FileInputStream input = new FileInputStream("…/mario.jpg");Image image = new Image(input);ImageView imageView = new ImageView(image);
HBox hbox = new HBox(imageView);Scene scene = new Scene(hbox, 220, 300);primaryStage.setScene(scene);primaryStage.show();
}
public static void main(String[] args) {Application.launch(args);
}}
Frills
• Margin• Node Alignment
– Pos.BASELINE_LEFT/Pos.BASELINE_CENTER/Pos.BASELINE_RIGHT/Pos.BOTTOM_LEFT/Pos.BOTTOM_CENTER/Pos.BOTTOM_RIGHT/Pos.CENTER_LEFT/Pos.CENTER/Pos.CENTER_RIGHT/Pos.TOP_LEFT/Pos.TOP_CENTER/Pos.TOP_RIGHT/
• Hgrow– To define how a child node can grow horizontally to fill
any space available inside the Hbox– Priority.ALWAYS/ Priority.SOMETIMES/ Priority.NEVER
• FillHeight– To tell the HBox control whether it should expand the
height of its children to fill out the whole height of the Hbox
– True/False
public class Main3 extends Application {@Overridepublic void start(Stage primaryStage) throws Exception {primaryStage.setTitle("HBox Experiment");
Button button1 = new Button("Button 1");
HBox hbox = new HBox(button1);button1.setMaxHeight(99999.0D);HBox.setMargin(button1, new Insets(10, 10, 10, 10));HBox.setHgrow(button1, Priority.ALWAYS);
hbox.setAlignment(Pos.CENTER);hbox.setFillHeight(true);
Scene scene = new Scene(hbox, 200, 100);primaryStage.setScene(scene);primaryStage.show();
}
public static void main(String[] args) {Application.launch(args);
}}
Button
public void start(Stage primaryStage) throws Exception {primaryStage.setTitle("HBox Experiment 1");
Label label = new Label("Not clicked");Button button = new Button("Click");
button.setOnAction(value -> {label.setText("Clicked!");
});
HBox hbox = new HBox(button, label);
Scene scene = new Scene(hbox, 200, 100);primaryStage.setScene(scene);primaryStage.show();
}
Styled buttons@Overridepublic void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("Button Experiment 1");
Button button1 = new Button("Button 1");Button button2 = new Button("Button 2");Button button3 = new Button("Button 3");Button button4 = new Button("Button 4");
button1.setStyle("-fx-border-color: #ff0000; -fx-border-width: 5px;");button2.setStyle("-fx-background-color: #00ff00");button3.setStyle("-fx-font-size: 2em; ");button4.setStyle("-fx-text-fill: #0000ff");
HBox hbox = new HBox(button1, button2, button3, button4);
Scene scene = new Scene(hbox, 400, 100);primaryStage.setScene(scene);primaryStage.show();
}
ListViewpublic class Main extends Application {
@Overridepublic void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("ListView Experiment 1");
ListView listView = new ListView();listView.getItems().add("Item 1");listView.getItems().add("Item 2");listView.getItems().add("Item 3");
Button button = new Button("Read Selected Value");
button.setOnAction(event -> {ObservableList selectedIndices =
listView.getSelectionModel().getSelectedIndices();
for(Object o : selectedIndices){System.out.println("o = " + o + " (" + o.getClass() + ")");
}});
VBox vBox = new VBox(listView, button);
Scene scene = new Scene(vBox, 300, 120);primaryStage.setScene(scene);primaryStage.show();
}
TextField
public void start(Stage primaryStage) throws Exception {primaryStage.setTitle("HBox Experiment 1");
TextField textField = new TextField();Button button = new Button("Click to get text");
button.setOnAction(action -> {System.out.println(textField.getText());
});
HBox hbox = new HBox(textField, button);
Scene scene = new Scene(hbox, 200, 100);primaryStage.setScene(scene);primaryStage.show();
}
WebView
• Pay attention to including the proper modules
public void start(Stage primaryStage) {primaryStage.setTitle("JavaFX WebView Example");
WebView webView = new WebView();webView.getEngine().load("http://google.com");
VBox vBox = new VBox(webView);Scene scene = new Scene(vBox, 960, 600);
primaryStage.setScene(scene);primaryStage.show();
}
Media
public void start(Stage primaryStage) {final String name = "file:////.../video.mp4";
primaryStage.setTitle("Embedded Media Player");Group root = new Group();Scene scene = new Scene(root, 540, 210);
Media media = new Media(name);MediaPlayer mediaPlayer = new MediaPlayer(media);mediaPlayer.setAutoPlay(true);
MediaView mediaView = new MediaView(mediaPlayer);((Group)scene.getRoot()).getChildren().add(mediaView);
primaryStage.setScene(scene);primaryStage.show();
}
FXML
• JavaFX FXML is an XML format– GUIs similar to web GUIs in HTML or in Android– Allows you to separate your JavaFX layout code from
the rest of your application code
• Can be used to compose the layout of– a whole application GUI– just part of an application GUI
• CSS styling
FXML
<FXML />
Controller.java
public class Controller {…}
FXApplication.java
public class FXApplicationextends Application {…}
Java API and FXML
• Java API for JavaFX– End-to-end Java development– Leverage Java language features– Fluent style API for UI construction– Alternative JVM languages support (eg Groovy, Scala)
with JavaFX– Leverage sophisticated IDEs, deduggers and profiles
• FXML – Scriptable, XML based language for defining UI – Convenient alternative to developing UI
programmatically – Easy to learn and intuitive for developers familiar with
web or markup-based UI technologies
First example
<?xml version="1.0" encoding="UTF-8"?><?import javafx.scene.layout.VBox?><?import javafx.scene.control.Label?>
<VBox><children>
<Label text="Hello world FXML"/></children>
</VBox>
How to load an FXML file
@Overridepublic void start(Stage primaryStage) throws Exception {
VBox root = (VBox) FXMLLoader.load(getClass().getResource("example.fxml"));
Scene scene = new Scene(root);primaryStage.setScene(scene);primaryStage.setTitle("A simple FXML Example");primaryStage.show();
}
Properties in FXML
<?xml version="1.0" encoding="UTF-8"?><?import javafx.scene.layout.VBox?><?import javafx.scene.control.Label?>
<VBox spacing="20"><children>
<Label text="Line 1"/><Label text="Line 2"/>
</children></VBox>
Event handlers
<?xml version="1.0" encoding="UTF-8"?><?language JavaScript?>
<?import javafx.scene.layout.VBox?><?import javafx.scene.control.Button?><?import javafx.scene.control.Label?>
<VBox xmlns:fx="http://javafx.com/fxml"><Label fx:id="label1" text="Button not clicked"/><Button fx:id="button1" text="Click me!" onAction="reactToClick()"/>
<fx:script>function reactToClick() {
label1.setText("Button clicked");}
</fx:script></VBox>
Controller Classes
• An FXML controller binds the GUI components declared in the FXML file together– The controller object acts as mediator
• There are two ways to set a controller– We can specify it inside the FXML file– We can set an instance of the controller class on
the FXMLLoader instance used to load the FXML document
Controllers
• Are instantiated by the FXML loader– method initialize() called after loading of the FXML
document– initialize() takes no arguments and returns void
• Must have a public no-args constructor– If it does not exist, an exception at load time is thrown
• Can have accessible methods (event handlers)• The FXML loader will automatically look for
accessible instance variables of the controller– If the name matches the fx:id attribute of an element,
the object reference from FXML is automatically copied into the controller instance variable
Example (I)
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.VBox?><?import javafx.scene.control.Button?><?import javafx.scene.control.Label?>
<VBox xmlns:fx="http://javafx.com/fxml" spacing="20"><children>
<Label fx:id="label1" text="Line 1"/><Label fx:id="label2" text="Line 2"/><Button fx:id="button1" text="Click me!"
onAction="#buttonClicked"/></children>
</VBox>
Example (II)
import javafx.event.Event;import javafx.fxml.FXML;
public class MyFXMLController {
@FXMLpublic void buttonClicked(Event e){
System.out.println("Button clicked");}
}
Example (III)public void start(Stage primaryStage) throws Exception {
MyFXMLController controller = new MyFXMLController();FXMLLoader loader = new FXMLLoader();loader.setController(controller);
String fxmlDocPath = "…/example.fxml";FileInputStream fxmlStream = new FileInputStream(fxmlDocPath);
VBox root = (VBox) loader.load(fxmlStream);Scene scene = new Scene(root);primaryStage.setScene(scene);primaryStage.setTitle("A simple FXML Example");primaryStage.show();
}
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?><?import javafx.scene.layout.*?>
<VBox fx:id="vbox" layoutX="10.0" layoutY="10.0" prefHeight="250.0"prefWidth="300.0" spacing="10" xmlns:fx="http://javafx.com/fxml/1"xmlns="http://javafx.com/javafx/2.2"><style>-fx-padding: 10;-fx-border-style: solid inside;-fx-border-width: 2;-fx-border-insets: 5;-fx-border-radius: 5;-fx-border-color: blue;
</style><children><Label fx:id="inputLbl" alignment="CENTER_LEFT" cache="true"
cacheHint="SCALE" prefHeight="30.0" prefWidth="200.0"text="Please insert Your Input here:" textAlignment="LEFT" />
<TextField fx:id="inputText" prefWidth="100.0" /><Button fx:id="okBtn" alignment="CENTER_RIGHT" contentDisplay="CENTER"
mnemonicParsing="false" text="OK" textAlignment="CENTER" /><Label fx:id="outputLbl" alignment="CENTER_LEFT" cache="true"
cacheHint="SCALE" prefHeight="30.0" prefWidth="200.0" text="Your Input:"textAlignment="LEFT" />
<TextArea fx:id="outputText" prefHeight="100.0" prefWidth="200.0"wrapText="true" />
</children></VBox>
public class Main extends Application {public static void main(String[] args) {
Application.launch(args);}
@Overridepublic void start(Stage stage) throws IOException {
FXMLLoader loader = new FXMLLoader();
String fxmlDocPath = "/Users/luciano/data/example.fxml";FileInputStream fxmlStream = new FileInputStream(fxmlDocPath);
VBox root = (VBox) loader.load(fxmlStream);
Scene scene = new Scene(root);stage.setScene(scene);stage.setTitle("A simple FXML Example");stage.show();
}}
Button
<Button fx:id="okBtn"alignment="CENTER_RIGHT"contentDisplay="CENTER"mnemonicParsing="false"onAction="#printOutput"text="OK"textAlignment="CENTER"
/>
<?xml version="1.0" encoding="UTF-8"?><?language JavaScript?>
<?import javafx.scene.control.*?><?import javafx.scene.layout.*?>
<VBox …<fx:script>
function printOutput() {outputText.setText(inputText.getText());
}</fx:script>
</children></VBox>
New Controllerpublic class MyController {
@FXMLprivate TextField inputText;
@FXMLprivate TextArea outputText;
@FXMLprivate URL location;
@FXMLprivate ResourceBundle resources;
public MyController() {}
@FXMLprivate void initialize() {}
@FXMLprivate void printOutput() {
outputText.setText(inputText.getText());}
}
Method start()
…MyController controller = new MyController();FXMLLoader loader = new FXMLLoader();loader.setController(controller);String fxmlDocPath = "…/example.fxml";FileInputStream fxmlStream = new FileInputStream(fxmlDocPath);…
How can we get this?
public void start(Stage primaryStage) {primaryStage.setTitle("JavaFX Welcome!");GridPane grid = new GridPane();grid.setAlignment(Pos.CENTER);grid.setHgap(10);grid.setVgap(10);grid.setPadding(new Insets(25, 25, 25, 25));Text scenetitle = new Text("Welcome");scenetitle.setFont(Font.font("Tahoma", FontWeight.NORMAL, 20));grid.add(scenetitle, 0, 0, 2, 1);Label userName = new Label("User Name:");grid.add(userName, 0, 1);TextField userTextField = new TextField();grid.add(userTextField, 1, 1);Label pw = new Label("Password:");grid.add(pw, 0, 2);PasswordField pwBox = new PasswordField();grid.add(pwBox, 1, 2);Button btn = new Button("Sign in");HBox hbBtn = new HBox(10);hbBtn.setAlignment(Pos.BOTTOM_RIGHT);hbBtn.getChildren().add(btn);grid.add(hbBtn, 1, 4);final Text actiontarget = new Text();grid.add(actiontarget, 1, 6);
btn.setOnAction( new EventHandler<ActionEvent>() {@Overridepublic void handle(ActionEvent e) {
actiontarget.setFill(Color.FIREBRICK);actiontarget.setId("actiontarget");actiontarget.setText("Sign in button pressed");
}});Scene scene = new Scene(grid, 300, 275);primaryStage.setScene(scene); primaryStage.show();
}
Screen builder
https://gluonhq.com/products/scene-builder/
ColorfulCircles
Concurrency
• The graphical user interface is not thread-safe– It can only be accessed and modified from the UI thread
also known as the JavaFX Application thread– Implementing long-running tasks on the JavaFX
Application thread inevitably makes an application UI unresponsive
• A best practice is to do these tasks on one or more background threads– and let the JavaFX Application thread process user
events
Communication
• JavaFX provides javafx.concurrent to take care of multithreaded code that interacts with the UI– and ensures that this interaction happens on the correct
thread– The package leverages the existing API by considering
the JavaFX Application thread and other constraints faced by GUI developers
Main elements
• Interface Worker defines an object that performs some work on one or more background threads– The state of the Worker object is observable and usable
from the JavaFX Application thread
• Class Task enables developers to implement asynchronous tasks in JavaFX applications
• Class Service executes tasks
import javafx.concurrent.Task;
public class Fibonacci extends Task<Long> {private final int n;
public Fibonacci(int n) {this.n = n;
}
@Overrideprotected Long call() throws Exception {
updateMessage("Processing");long result = fibonacci(n);updateMessage("Done");return result;
}
public long fibonacci(long number) {if (number == 0 || number == 1)
return number;else
return fibonacci(number - 1) + fibonacci(number - 2);}
}
btnStart.setOnAction(new EventHandler<ActionEvent>() {@Overridepublic void handle(ActionEvent event) {
try {int ival = Integer.parseInt(tf1.getText());Fibonacci task = new Fibonacci(ival);lbl1.textProperty().bind(task.messageProperty());
task.setOnRunning((succeesesEvent) -> {btnStart.setDisable(true);lbl2.setText("");
});
task.setOnSucceeded((succeededEvent) -> {lbl2.setText(task.getValue().toString());btnStart.setDisable(false);
});
ExecutorService executorService = Executors.newFixedThreadPool(1);
executorService.execute(task);executorService.shutdown();
} catch (NumberFormatException e) {