FXML tutorial (1) – wprowadzenie
FXML
FXML jest językiem znaczników, opartym na XML-u, pozwalającym na używanie języka skryptowego, służącym do konstruowania scenografu lub jego fragmentów w JavaFX.
Zaletą FXML-u, podobnie jak innych rodzajów XML-u, jest bezpośredni dostęp do pliku, co daje możliwość dynamicznego zmieniania zarówno układu elementów jak i wartości atrybutów.
Kod JavaFX, odwołujący się do pliku FXML, nie musi być kompilowany, gdy zmieni się treść plików.
Układ projektu
W projekcie użyłem JDK 19, JavaFX 19, Groovy 4.0.8, IntelliJ IDEA v. Community.
Układ pakietów w module:
Wspólna klasa module-info.java dla wszystkich kodów w tutorialu.
module-info.java
module fxmlgroovyscript { requires java.scripting; requires java.sql; requires javafx.base; requires javafx.controls; requires javafx.fxml; requires javafx.graphics; exports codes to javafx.graphics, javafx.fxml; opens codes to javafx.fxml, javafx.base; opens resources; }
Aplikacja JavaFX bez FXML
Aplikacja jest prosta. Zawiera etykietkę i trzy przyciski, które na razie nie wykonują żadnego zadania.
Listing01_hello_groovy.java
package codes; import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; import javafx.stage.Stage; public class Listing01_hello_groovy extends Application { public static void main(String[] args) { Application.launch(args); } @Override public void start(Stage stage) { try { VBox root = new VBox(); HBox hbox = new HBox(); Label lab1 = new Label(); lab1.setText("Twoja decyzja?"); Button but1 = new Button("Tak"); Button but2 = new Button("Nie"); Button but3 = new Button("Anuluj"); hbox.getChildren().addAll(but1, but2, but3); root.getChildren().addAll(lab1, hbox); Scene scene = new Scene(root, 150, 80); stage.setScene(scene); stage.show(); } catch (Exception e) { e.printStackTrace(); } } }
Po uruchomieniu klasy zobaczymy:
Aplikacja JavaFX z FXML
Aplikacja jest prosta. Zawiera etykietkę i trzy przyciski, które na razie nie wykonują żadnego zadania.
Tym razem mamy klase oraz plik FXML zawierający scenograf aplikacji.
listing02_fxml
<?xml version="1.0" encoding="UTF-8"?> <?import javafx.scene.layout.VBox?> <?import javafx.scene.layout.HBox?> <?import javafx.scene.control.Label?> <?import javafx.scene.control.Button?> <VBox xmlns:fx="http://javafx.com/fxml"> <Label fx:id="lab1" text="Twoja decyzja?" /> <HBox fx:id="hbox"> <Button fx:id="but1" text="Tak" /> <Button fx:id="but2" text="Nie" /> <Button fx:id="but3" text="Anuluj" /> </HBox> </VBox>
Zwróć uwagę na sposób importowania klas <?import javafx.scene.layout.VBox?>
, wszechobecne elementy fx:id
, identyfikujące poszczególne instancje klas, oraz narzuconą przestrzeń nazw xmlns:fx="http://javafx.com/fxml
. Atrybut przestrzeni nazw zawsze znajduje się w elemencie root, czyli w korzeniu scenografu.
Dozwolony, choć odradzany ze względu na niepotrzebne obciążanie pamięci, jest też import <?import javafx.scene.layout.*?>
. Import statyczny nie jest dozwolony.
Listing02_hello_groovy_fxml.java
package codes; import javafx.application.Application; import javafx.fxml.FXMLLoader; import javafx.scene.Scene; import javafx.scene.layout.VBox; import javafx.stage.Stage; import java.net.URL; public class Listing02__hello_groovy_fxml extends Application { public static void main(String[] args) { Application.launch(args); } @Override public void start(Stage stage) { try { URL fxmlUrl = this.getClass().getClassLoader().getResource("resources/listing02.fxml"); VBox root = fxmlUrl != null ? FXMLLoader.load(fxmlUrl) : new VBox(); Scene scene = new Scene(root, 150, 80); stage.setScene(scene); stage.show(); } catch (Exception e) { e.printStackTrace(); } } }
Klasa wywołuje FXMLLoader, który pobiera zasoby, określa klasę korzenia scenografu, buduje ‘stage’ i scenę, na której umieszcza utworzony scenograf.
Należy zwrócić uwagę, że obiekty Stage i Scene nie są listowane w pliku FXML.
W znacznikach lab1, but1, but2 i but3 widzimy atrybuty text
oraz umieszczoną w nich wartość.
Po uruchomieniu klasy otrzymamy identyczne okno aplikacji jak przedstawione na obrazku powyżej.