~~NOCACHE~~ ~~REVEAL theme=simple&disableLayout=0&transition=none&controls=1&show_progress_bar=1&build_all_lists=0&show_image_borders=0&horizontal_slide_level=2&enlarge_vertical_slide_headers=0&show_slide_details=1&open_in_new_window=1&size=1024x768~~ ====== JavaFX i OpenJFX ====== ===== JavaFX - historia i pozycja w ekosystemie ===== * **JavaFX** - zestaw bibliotek do tworzenia nowoczesnych aplikacji desktopowych w Javie * Od JDK 8 wbudowany w Oracle JDK jako nowoczesna alternatywa dla AWT/Swing * Od JDK 11 nie jest już częścią JDK, rozwijany osobno jako OpenJFX * **OpenJFX** - otwartoźródłowy projekt rozwijający JavaFX przez społeczność, Oracle i firmę Gluon * Aktualne wydania: [[https://gluonhq.com/products/javafx/|Gluon OpenJFX]] ===== Cechy JavaFX ===== * architektura oparta o graf ''Scene Graph'' * deklaratywne UI (FXML) * stylowanie CSS * multimedia, wsparcie dla animacji * obsługa grafiki 2D i 3D oraz renderowania sprzętowego (akceleracja GPU) * duża liczba wbudowanych kontrolek i możliwość rozbudowy * WebView, silnik WebKit do osadzania treści webowej * integracja z Swing (''SwingNode'') * mechanizm danych reaktywnych (''Observable'', ''Property'', ''Binding'') ===== Architektura JavaFX ===== {{ zajecia:java_2026_1:136_1.jpg?600 | }} ===== Warstwy JavaFX ===== * **Prism** - akcelerowany potok renderowania (GPU: DirectX/OpenGL). \\ W przypadku braku wsparcia sprzętowego JavaFX przechodzi w tryb renderowania programowego. * **Glass Windowing Toolkit** - warstwa okien, zdarzeń i timerów; interfejs między JavaFX a systemem operacyjnym. * **WebView** - kontrolka osadzająca HTML/JS (silnik WebKit) umożliwiająca renderowanie i interakcję z treścią webową. * **Media Engine** - silnik multimediów (audio/video) obsługujący różne formaty i kodeki. * **Quantum Toolkit** - łączy warstwy niskopoziomowe z API JavaFX. * **Scene Graph** - drzewo węzłów UI i grafiki * **JavaFX API** - publiczne klasy i interfejsy do budowy interfejsu graficznego ===== JavaFX SDK API ===== * [[https://openjfx.io/javadoc/26/|JavaFX API Documentation]] * ''javafx.base'' - podstawowe klasy, kolekcje, properties * ''javafx.graphics'' - grafika 2D/3D, scena, renderowanie * ''javafx.controls'' - gotowe kontrolki UI * ''javafx.fxml'' - FXML, loader, kontrolery * ''javafx.media'' - multimedia * ''javafx.web'' - WebView, silnik WebKit * ''javafx.swing'' - integracja z Swing (''SwingNode'') ===== Struktura aplikacji JavaFX ===== {{ zajecia:java_2026_1:141_1.jpg }} * **Stage** - okno aplikacji - scena teatralna, gdzie odbywa się przedstawienie * **Scene** - zawartość okna - konkretna scenografia, rekwizyty i aktorzy ustawieni na scenie, zawiera hierarchię węzłów (''Scene Graph'') * **Node** - elementy UI, grafiki ===== Scene Graph ===== {{zajecia:java_2026_1:137_1.jpg}} * Każdy element UI (obiekty 2D/3D, kontrolki UI, kontenery, elementy multimedialne) jest węzłem grafu (''Node'') * Renderowanie, transformacje i zdarzenia propagują się po drzewie * Zmiana stanu węzła natychmiast widoczna w interfejsie ===== Elementy Scene Graph ===== * ''Scene'' to główny kontener, w którym umieszczamy hierarchię węzłów * Korzeń (''Root'') - główny węzeł sceny, zwykle layout (np. ''VBox'', ''BorderPane'') * Węzły rodzicielskie (''Parent'') - zawierają inne węzły (dzieci) * elementy grupujące (''Group''), * układy (''Pane'', ''HBox'', ''StackPane'', ''GridPane'') * kontrolki (''Button'', ''TextField'', ''Label''), też są rodzicami i mogą zawierać wewnętrzne węzły * Liście - elementy graficzne 2D/3D (''Shape'', ''ImageView'', ''Text'', ''SwingNode'') VBox root = new VBox(); Label title = new Label("Kurs JavaFX"); Button button = new Button("Kliknij"); root.getChildren().addAll(title, button); Scene scene = new Scene(root, 600, 400); ===== Cykl życia aplikacji ===== * Punkt wejścia: klasa dziedzicząca po ''Application'' * Kluczowa metoda: ''start(Stage stage)'' udostępniająca główny ''Stage''. \\ W metodzie ''start()'': * przygotowujemy scenę (tworzymy węzły, układamy je w layoutach) * ustawiamy ''Stage'' (tytuł, rozmiar, scenę) * wywołujemy ''show()'', aby wyświetlić okno. * Uruchomienie: ''launch(args)'' w ''main()'' import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.control.Label; import javafx.stage.Stage; public class HelloFxApp extends Application { @Override public void start(Stage stage) { Scene scene = new Scene(new Label("Witaj JavaFX"), 400, 200); stage.setTitle("Hello FX"); stage.setScene(scene); stage.show(); } public static void main(String[] args) { launch(args); } } ===== Konfiguracja JavaFX w IntelliJ ===== JavaFX nie jest już częścią JDK. Istnieje kilka sposobów na dodanie JavaFX do projektu: * instalacja ręczna - pobierz OpenJFX, dodaj biblioteki do projektu, ustaw VM options * z użyciem Maven lub Gradle - dodaj zależności do ''pom.xml'' lub ''build.gradle'' * szablon projektu JavaFX w IntelliJ (plugin JavaFX, używa Maven) - brakujące zależności powinny zostać pobrane automatycznie [[https://openjfx.io/openjfx-docs/|Dokumentacja OpenJFX]] zawiera szczegółowe instrukcje dla różnych IDE i systemów budowania. ===== Ręczna konfiguracja JavaFX ===== * Pobierz SDK JavaFX z [[https://gluonhq.com/products/javafx/|Gluon]] lub [[https://www.oracle.com/java/technologies/downloads/javafx/|Oracle]] zgodny z wersją JDK * Dodaj biblioteki JavaFX do projektu \\ ''File'' -> ''Project Structure'' -> ''Libraries'' * Ustaw ścieżkę do modułu w VM options przy uruchamianiu: \\ ''Build'' -> ''Edit Configurations'' -> ''VM options'' \\ --module-path "ścieżka/do/javafx-sdk-XX/lib" --add-modules javafx.controls,javafx.fxml ===== Konfiguracja JavaFX z użyciem Maven ===== Maven - system zarządzania projektem i budowania, który automatycznie pobiera zależności i konfiguruje projekt. Jak skonfigurować JavaFX z Maven: - Utwórz projekt Maven (lub użyj archetypu JavaFX) - Wyszukaj JavaFX w repozytorium Maven [[https://search.maven.org/search?q=javafx|Maven Central]] lub [[https://mvnrepository.com/search?q=javafx|https://mvnrepository.com/]] - Dodaj zależności ''javafx-controls'' (opcjonalnie ''javafx-fxml'') do pliku ''pom.xml'' \\ - Skonfiguruj plugin ''javafx-maven-plugin'' do uruchamiania (zdarzenie ''javafx:run'') oraz ''maven-compiler-plugin'' - Uruchamiaj (z CLI) przez zadanie Maven, z okna narzędzi Maven IDE albo skonfiguruj IDE \\ mvn javafx:run [[https://www.javaspring.net/blog/how-to-create-a-javafx-maven-project-in-intellij-idea/|JavaFX Maven Project in IntelliJ IDEA from Scratch]] ===== Przykładowa konfiguracja Maven dla JavaFX ===== org.openjfx javafx-controls 26 org.openjfx javafx-fxml 26 compile ===== Pluginy Maven dla JavaFX ===== org.apache.maven.plugins maven-compiler-plugin 3.15.0 25 25 org.openjfx javafx-maven-plugin 0.0.8 default-cli MyJavaFXApp ===== Uruchamianie aplikacji JavaFX z IDE ===== * Opcja 1: Okno narzędzi Maven * ''Lifecycle'' -> ''clean'' * ''Plugins'' -> ''javafx'' -> ''javafx:run'' * Opcja 2: Dodaj konfigurację uruchomienia w IntelliJ * ''Run'' -> ''Edit Configurations'' * Dodaj ''+'' -> ''Maven'' * W polu ''Command line'' wpisz: ''clean javafx:run'' ===== Wątki i JavaFX ===== * JavaFX ma własny wątek UI (''JavaFX Application Thread'') uruchamiany automatycznie przy starcie aplikacji * Wszystkie operacje na węzłach muszą być wykonywane w tym wątku * Aby zachować responsywność, długotrwałe zadania powinny być wykonywane w osobnych wątkach, np. przez ''Task'' lub ''Service'', a aktualizacje UI przez ''Platform.runLater()'' ===== Układy ===== {{ https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmdscoc82nafwdz6xzh4j.png?600 |Układy JavaFX}} {{https://dev.to/alex_ricciardi/gui-design-with-javafx-layout-managers-54gj|GUI Design with JavaFX Layout Managers}} ===== Layouty ===== * ''javafx.scene.layout'' - układy (''layout'') - specjalne kontenery, które automatycznie rozmieszczają swoje dzieci według określonych reguł * ''HBox'', ''VBox'', ''ButtonBar'' - układ poziomy/pionowy, rozmieszcza dzieci w linii * ''BorderPane'' - układ z pięcioma regionami (top, bottom, left, right, center) * ''SplitPane'' - układ dzielący przestrzeń na panele o regulowanej wielkości * ''GridPane'' - układ siatkowy, rozmieszcza dzieci w wierszach i kolumnach * ''FlowPane'' - układ przepływowy, rozmieszcza dzieci w linii, zawija do następnego wiersza * ''AnchorPane'' - układ kotwiczący, pozwala przypiąć dzieci do krawędzi * ''StackPane'' - nakłada dzieci jedno na drugie, centrowanie StackPane stackPane = new StackPane(); Ellipse ellipse = new Ellipse(110, 70); ellipse.setFill(Color.LIGHTBLUE); Text text = new Text("Hello World"); text.setFont(new Font("Arial Bold", 24)); stackPane.getChildren().addAll(ellipse, text); Scene scene = new Scene(stackPane, 350, 230, Color.LIGHTYELLOW); ===== Efekty graficzne ===== * [[https://download.java.net/java/GA/javafx26/docs/api/javafx.graphics/javafx/scene/effect/Effect.html|Effect]] - wbudowane efekty graficzne do stylizacji węzłów: * [[https://download.java.net/java/GA/javafx26/docs/api/javafx.graphics/javafx/scene/effect/DropShadow.html|DropShadow]] - efekt cienia, można dostosować kolor, rozmycie i przesunięcie * [[https://download.java.net/java/GA/javafx26/docs/api/javafx.graphics/javafx/scene/effect/Reflection.html|Reflection]] - efekt odbicia, można dostosować wysokość i rozmycie * Wypełnienie kształtu: * ''Color'', ''ImagePattern'', ''RadialGradient'' * [[https://download.java.net/java/GA/javafx26/docs/api/javafx.graphics/javafx/scene/paint/LinearGradient.html|LinearGradient]] - gradient liniowy, definiowany przez punkty początkowy i końcowy oraz zestaw ''Stop'' (pozycja + kolor) Stop[] stops = new Stop[] { new Stop(0, Color.DODGERBLUE), new Stop(0.5, Color.LIGHTBLUE), new Stop(1.0, Color.LIGHTGREEN) }; LinearGradient gradient = new LinearGradient(0, 0, 1, 1, true, CycleMethod.NO_CYCLE, stops); ellipse.setFill(gradient); ellipse.setEffect(new DropShadow(30, 10, 10, Color.GRAY)); ===== Animacje ===== * System animacji oparty na klasie ''[[https://openjfx.io/javadoc/26/javafx.graphics/javafx/animation/Transition.html|Transition]]'' i ''[[https://openjfx.io/javadoc/26/javafx.graphics/javafx/animation/Timeline.html|Timeline]]'' * Można animować właściwości węzłów (pozycja, rozmiar, kolor) oraz tworzyć sekwencje animacji * Animacje są płynne dzięki renderowaniu sprzętowemu * ''[[https://openjfx.io/javadoc/26/javafx.graphics/javafx/animation/FadeTransition.html|FadeTransition]]'', ''[[https://openjfx.io/javadoc/26/javafx.graphics/javafx/animation/RotateTransition.html|RotateTransition]]'', ''[[https://openjfx.io/javadoc/26/javafx.graphics/javafx/animation/ScaleTransition.html|ScaleTransition]]'', ''[[https://openjfx.io/javadoc/26/javafx.graphics/javafx/animation/TranslateTransition.html|TranslateTransition]] '' - gotowe klasy do animacji określonych właściwości * ''[[https://openjfx.io/javadoc/26/javafx.graphics/javafx/animation/Timeline.html|Timeline]]'' - bardziej elastyczna klasa do animowania dowolnych właściwości w określonych punktach czasowych * ''[[https://openjfx.io/javadoc/26/javafx.graphics/javafx/animation/ParallelTransition.html|ParallelTransition]]'' i ''[[https://openjfx.io/javadoc/26/javafx.graphics/javafx/animation/SequentialTransition.html|SequentialTransition]]'' - do łączenia wielu animacji * ''play()'' - uruchamia animację, ''stop()'' - zatrzymuje, ''pause()'' - wstrzymuje, ''getStatus()'' - sprawdza status animacji RotateTransition rotate = new RotateTransition(Duration.millis(2500), stackPane); rotate.setToAngle(360); rotate.setFromAngle(0); rotate.setInterpolator(Interpolator.LINEAR); rotate.play(); ===== Obsługa zdarzeń ===== * [[https://openjfx.io/javadoc/26/javafx.base/javafx/event/Event.html|Event]] - obsługa zdarzeń (myszy, klawiatury, akcji) * Można rejestrować nasłuchiwacze zdarzeń na węzłach grafu * Zdarzenia propagują się po drzewie, rodzic może przechwycić zdarzenie dziecka * ''setOnAction(EventHandler)'', ''setOnMouseClicked(EventHandler)'' dla kontrolek (węzłów) obsługujących konkretne zdarzenia, * ''addEventHandler(EventType, EventHandler)'' dla ogólnych zdarzeń stackPane.setOnMouseClicked(mouseEvent -> { if (rotate.getStatus().equals(Animation.Status.RUNNING)) { rotate.pause(); } else { rotate.play(); } }); ===== Obserwowanie i wiązanie właściwości ===== * JavaFX posiada wbudowany mechanizm danych reaktywnych, możemy wiązać właściwości węzłów z innymi właściwościami lub źródłami danych, tak aby zmiany były automatycznie odzwierciedlane w interfejsie * właściwości węzłów są obserwowalne np. ''textProperty()'' dla ''Label'' czy ''TextField'', możemy ustawić nasłuchiwacz reagujący na zmiany lub powiązać je z innymi właściwościami * [[https://openjfx.io/javadoc/26/javafx.base/javafx/beans/Observable.html|Observable]] oraz [[https://openjfx.io/javadoc/26/javafx.base/javafx/beans/value/ObservableValue.html|ObservableValue]] - interfejsy reprezentujące obserwowalną wartość, posiadają metody do dodawania nasłuchiwaczy ''addListener()'' i pobierania aktualnej wartości * [[https://openjfx.io/javadoc/26/javafx.base/javafx/beans/InvalidationListener.html|InvalidationListener]] - reaguje na zmianę * [[https://openjfx.io/javadoc/26/javafx.base/javafx/beans/value/ChangeListener.html|ChangeListener]] - reaguje na zmianę wartości, dostarcza starą i nową wartość ===== Przykład ===== rotate.statusProperty().addListener(new InvalidationListener() { @Override public void invalidated(Observable observable) { text.setText("Animation status: " + ((ObservableObjectValue)observable).getValue()); } }); lub krócej rotate.statusProperty().addListener(observable -> { text.setText("Animation status: " + rotate.getStatus()); }); ===== Binding ===== * Binding pozwala na tworzenie dynamicznych powiązań między właściwościami implementującymi interfejs [[https://openjfx.io/javadoc/26/javafx.base/javafx/beans/property/Property.html|Property]] bez potrzeby dodawania ręcznych nasłuchiwaczy * ''bind()'' - tworzy jednokierunkowe powiązanie, gdzie jedna właściwość jest zależna od drugiej text.rotateProperty().bind(stackPane.rotateProperty()); * przekształcanie wartości do tworzenia złożonych powiązań, np. matematycznych operacji, warunków logicznych, formatowania tekstu text2.textProperty().bind(stackPane.rotateProperty().asString("%.1f")); * łączenie wielu właściwości i operacji na nich, np. konkatenacja tekstu z dwóch ''TextField'' do ''Label'' TextField firstName = new TextField(); TextField lastName = new TextField(); Label fullName = new Label(); fullName.textProperty().bind( firstName.textProperty().concat(" ").concat(lastName.textProperty()) ); ===== Wiązanie dwukierunkowe ===== * ''bindBidirectional()'' - dwukierunkowe powiązanie, zmiana jednej właściwości automatycznie aktualizuje drugą i odwrotnie * przydatne w formularzach, gdzie chcemy, aby zmiany w UI były odzwierciedlane w modelu danych i na odwrót firstName.textProperty().bindBidirectional(model.firstNameProperty()); ===== FXML - deklaratywny język UI ===== * FXML to XML opisujący hierarchię UI, pozwala na oddzielenie logiki od warstwy prezentacji * [[https://openjfx.io/javadoc/26/javafx.fxml/javafx/fxml/doc-files/introduction_to_fxml.html|Introduction to FXML]] * ''FXMLLoader'' wczytuje i parsuje plik FXML, tworzy obiekty UI i ustawia je w hierarchii * Własności statyczne, np. ''GridPane.rowIndex'' \\ ===== ===== * Element '''' jest używany do definiowania listy dzieci \\