Twitter: @grzegg
Kategoria: java, Tagi: - - - - .

Java [33] – JavaFX cz. 3: FXML i Scene Builder

W poprzednich lekcjach poświęconych JavieFX pokazałem jak tworzyć proste aplikacje przy użyciu czystego kodu Javy. Możliwe jest jednak inne podejście, w którym interfejs graficzny jest zdefiniowany w osobnym pliku FXML. Co prawda, można taki plik edytować ręcznie, ale można sobie też pomóc Scene Builderem, który pozwala na budowanie interfejsu w sposób „wizualny”.

Aplikacja JavaFX FXML

Zaczynamy od utworzenia w NetBeans nowego projektu, wybierając tym razem w okienku „JavaFX FXML Application”.


Nadajemy projektowi nazwę AplikacjaFXML i zatwierdzamy.

Zauważ, że teraz zostały w pakiecie utworzone trzy pliki:


Można uruchomić program, pojawi się okienko z przyciskiem:


Po naciśnięciu przycisku pojawi się napis:


Z poprzednich lekcji poświęconych JavieFX zapewne wiesz wystarczająco dużo, żeby się domyślić jaka jest struktura tej aplikacji. Przyjrzyjmy się jednak w jaki sposób taki rezultat został osiągnięty z użyciem pliku FXML. Zacznijmy od analizy trzech plików:

AplikacjaFXML.java

Jak widać w tym pliku znajdują się metody main() i start(). Ich zawartość powinna być zrozumiała, nowością jest w zasadzie tyko linia:


Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));

Można jednak się domyślić, że chodzi tu o pobranie struktury interfejsu graficznego z pliku o nazwie FXMLDocument.fxml, który znajduje się w naszym projekcie.

FXMLDocument.fxml

Jeśli miałeś dotychczas do czynienia z plikami XML, na przykład z HTML struktura powyższego pliku będzie z grubsza zrozumiała. Nie będę tu omawiał jej dokładnie, zwrócę jedynie uwagę na kilka charakterystycznych cech tego typu plików. Zauważ, że występują w nim znaczniki ograniczone znakami < i >. Para znaczników wyznacza początek i koniec elementu. Znacznik otwierający go wygląda tak: <element> a zamykający tak: </element>. W powyższym pliku taką parą jest np. <children> i </children>. W znaczniku otwierającym mogą się także znaleźć atrybuty: <element nazwaAtrybutu="Wartość atrybutu">. Dobrym przykładem jest znacznik otwierający element AnchorPane, który zawiera szereg atrybutów:


<AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320" xmlns:fx="http://javafx.com/fxml/1" fx:controller="aplikacjafxml.FXMLDocumentController">

Przy okazji nie trudno zauważyć, że element ten odpowiada panelowi AnchorPane a atrybuty wyznaczają jego cechy, jak identyfikator, czy preferowane rozmiary. Znajduje się tam także odwołanie do trzeciego pliku w naszej aplikacji: fx:controller="aplikacjafxml.FXMLDocumentController" ale do tego wrócimy za chwilę. Element AnchorPane obejmuje, albo jak w takich sytuacjach mówimy, jest rodzicem, elementu children a ten z kolei zawiera dwa kolejne elementy odpowiadające kontrolkom Button i Label. Zauważ, że w obu przypadkach mamy do czynienia nie z parami znaczników, ale z pojedynczym znacznikiem, zawierającym znak /. To jest tak zwany "znacznik pusty", co oznacza, że nie ma "dziecka" czyli, że nie obejmuje elementu niższego rzędu. Tak więc znacznik <element /> odpowiada parze znaczników: <element></element>.

Elementy odpowiadające dwóm kontrolkom także zawierają serie atrybutów odpowiadających za ich położenie, wyświetlany tekst etc.. Interesujący jest zwłaszcza jeden, przypisany przyciskowi: onAction="#handleButtonAction", odpowiada on metodzie wywoływanej przy wciśnięciu przycisku. Nie było tej metody w pierwszym z omawianych plików, zatem znajdziemy ją za chwilę w trzecim.

Zwróć teraz uwagę na górną część pliku:


<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
...

Znów, nie jest trudno wpaść na ich przeznaczenie. Odpowiadają one za import odpowiednich klas. Zauważ, że o ile w plikach z kodem Javy nie musieliśmy importować klas z pakietu java.lang, w przypadku plików FXML jest to konieczne.

FXMLDocumentController.java

To jest plik kontrolera (jak sama nazwa wskazuje) czyli plik zawierający kod obsługujący elementy interfejsu graficznego zdefiniowanego w pliku FXML. Przypominam, że w poprzednio omawianym pliku FXMLDocument.fxml znajduje się odwołanie do pliku FXMLDocumentController.java w elemencie odpowiadającym panelowi AnchorPane, które jasno wskazuje gdzie szukać właściwego kodu.

Jak widać plik wygląda jak "normalny" plik z kodem Javy, zwraca jedynie uwagę mnogość adnotacji "@FXML", które wskazują na elementy interfejsu zdefiniowane w pliku FXML a także na metody, które będą przez nie wykorzystywane. Tu jest jedna taka metoda, handleButtonAction(), do której odwołanie, jak pamiętamy, znalazło się w znaczniku odpowiadającemu przyciskowi.

Małe modyfikacje

Spróbujmy teraz zrobić małą modyfikację, podobną do tej jaką wykonaliśmy przy okazji naszej pierwszej aplikacji w JavieFX, czyli dołożymy do interfejsu czerwone koło. Dopisz zatem do pliku FXMLDocument.fxml, zaraz po znaczniku dla kontrolki Label znacznik dla koła


<Circle layoutX="162" layoutY="150" radius="30" fill="red" fx:id="kolko" />

Nie zapomnij też zaimportować odpowiedniej klasy:


<?import javafx.scene.shape.Circle?>

Teraz, zgodnie z oczekiwaniami pojawia się czerwone kółko:


Spróbuj teraz pozmieniać parametry kontrolek, obserwując wpływ zmian na wygląd interfejsu.

Pobranie i instalacja Scene Buildera

Firma Oracle jakiś czas temu zaprzestała udostępniania nowszych wersji Scene Buildera. Na szczęście, inicjatywę przejęła firma Gluon, która obecnie udostępnia odpowiednie pliki instalacyjne a także plik .jar tutaj. Możemy pobrać plik instalacyjny odpowiedni dla używanego systemu albo jeśli nie chcemy instalować programu, wybieramy plik .jar, który umieszczamy w wygodnym miejscu.

Po instalacji uruchom program, pojawi się takie okno:


Możesz zamknąć program.

Używamy Scene Buildera

Teraz kliknij prawym klawiszem myszy na pliku FXMLDocument.fxml w ramce "Projects", powinno się pojawić menu a w nim pozycja Open Jeśli jej nie ma a zainstalowałeś Scene Buildera to trzeba NetBeans wskazać, gdzie się on znajduje. W tym celu wejdź w menu NetBeans -> Preferences…. W oknie, które się pokaże wybierz zakładkę JavaFX. Zaznacz Save all modified files… i wybierz miejsce zainstalowania Scene Buildera.


Niestety, może się okazać, że otrzymasz taki komunikat:


Przyczyną jest zapewne niedostosowanie NetBeans do plików rozpowszechnionych przez firmę Gluon.
Udało mi się znaleźć w internecie obejście tego problemu dla systemu Windows tutaj, ale nie próbowałem go zastosować. Jeśli ktoś ma inny pomysł proszę śmiało pisać w komentarzach.

Innym rozwiązaniem, które sam zastosowałem, jest pobranie i zainstalowanie developerskiej wersji NetBeans ze strony: http://bits.netbeans.org/dev/nightly/, gdzie wybieramy najnowszą wersję oprogramowania (wg. daty). Trzeba jednak pamiętać, że taka wersja najprawdopodobniej nie jest całkiem stabilna. Miejmy nadzieję że w kolejnej stabilnej wersji NetBeans wszystko już będzie działało bez zakłóceń.

Jeśli tym razem po kliknięciu prawym klawiszem na plik FXMLDocument.fxml w menu pojawiła się opcja Open, to wybierz ją. Teraz zresztą podwójne kliknięcie na tym pliku powinno otworzyć go domyślnie w Scene Builderze. Jeśli chcesz go edytować tradycyjnie należy z menu wybrać Edit. Powinieneś zobaczyć taki widok:


Jak widać znajduje się tam interfejs graficzny naszej aplikacji, przy czym jest on edytowalny. Kliknij na przycisku. Teraz okno wygląda tak:


Po lewej stronie u góry znajduje się paleta kontrolek i paneli. Poniżej widać strukturę aplikacji. W centralnej części widać projekt interfejsu. Po lewej mamy trzy zakładki w których możemy edytować właściwości, ułożenie i kod związany z obecnie zaznaczonym elementem interfejsu, teraz jest to kontrolka Button. Przyjrzyj się im i spróbuj poeksperymentować zmieniając ich wartości. Zauważ, że można też edytować takie rzeczy jak rozmiary czy położenie elementu, bezpośrednio w części centralnej aplikacji odpowiednio przeciągając krawędzie czy całe kontrolki.


Jeśli teraz zapiszesz plik (menu: File -> Save) to w NetBeans możesz zauważyć, że kod w pliku FXMLDocument.fxml również się zmienił.

Wróć teraz do Scene Buildera, wybierz z lewej strony zakładkę Controls i znajdź tam kontrolkę TextField. Przeciągnij ją na projekt interfejsu.


Dostosuj jej rozmiar, a następnie w Properties po prawej najpierw ustaw wartość pola Prompt Text na "wpisz coś" a pola Id (poniżej) na "poleTextowe".


Teraz jeszcze trzeba ustawić odpowiednie parametry kontrolki Label, która nie jest widoczna na projekcie interfejsu, ale możemy ją łatwo znaleźć w oknie hierarchii dokumentu (po lewej na dole, klikając w odpowiednią pozycję. Teraz kontrolka będzie zaznaczona.


Możemy ją ułożyć bardziej sensownie, zmienić wymiary, a przy okazji przesunąć trochę koło.


Zapisz plik. Teraz wygląda on tak:

Zauważ, że pojawił się element font zagnieżdżony w elemencie Button (zmieniłem czcionkę przycisku) a także element odpowiadający kontrolce TextField. Zwróć uwagę na atrybut id: id="poleTekstowe". Uwaga, należy go zmienić tak: fx:id="poleTekstowe".
Można też było od razu ustawić wartość fx:id w SceneBuilderze w zakłądce Code inspektora.
Teraz zajmijmy się edycją pliku FXMLDocumentController.java.

Dopisz:


@FXML
private TextField poleTekstowe;

@FXML
private Circle kolko;

Do importów dodaj:


import javafx.scene.control.TextField;
import javafx.scene.shape.Circle;

A metodę handleButtonAction() zmodyfikuj w ten sposób:


    private void handleButtonAction(ActionEvent event) {
        label.setText(poleTekstowe.getText());
        kolko.setFill(Color.GREEN);
    }

Teraz po uruchomieniu programu możemy coś wpisać do pola tekstowego i kliknąć na przycisk, efekt może wyglądać tak:


Leave a Reply