Kurs Java od podstaw Tydzień 8

Tworzenie interfejsu graficznego przy użyciu SceneBuildera

SceneBuilder…

jest narzędziem, które pozwala w łatwy sposób „wyklikać” interfejs graficzny dla aplikacji desktopowej lub mobilnej. My oczywiście potrzebujemy interfejsu dla aplikacji desktopowej, dlatego skorzystamy z tego narzędzia.

W przeciwieństwe do interfejsu z poprzedniej lekcji, tym razem nasz interfejs graficzny będzie opisany w pliki .fxml zamiast na sztywno w kodzie aplikacji.

Co nam to daje? Z pewnościa w przypadku dużych aplikacji nie musimy budować całej aplikacji od nowa, aby zmienić interfejs. Wystarczy tylko podmienić pliki .fxml.

Dodatkowym atutem jest to, że interfejs może wyklikać osoba nie mająca w ogóle nic wspólnego z programowaniem.

Najważniejszym aututem jest to, że nie mieszamy warstwy widoku wartswą logiczną!

Instalacja

Oczywiste, że musimy zaczać od instalacji programu. Wchodzimy, więc na tą stronę. Przechodzimy do sekcji Java 8 (można spróbować na Java 10, jednka trzeba uważać, ponieważ w „dziesiątce” weszło trochę zmian do JavaFx).

Po pobraniu instalatora na odpowiednią platformę i zainstalowaniu możemy w końcu uruchomić aplikację.

Pierwsze uruchomienie

Po uruchomieniu aplikacja powinna przywitać nas takim okienkiem:

Są tutaj umieszczone podstawowe szablony interfejsów (więcej szablonów można poszukać w internecie – my na początek wybieramy Empty project.

Po wybraniu szablonu zostajemy przekierowani do całej aplikacji, która prezentuje się tak:

1 – sekcja komponentów, które możemy wykorzystać do budowania interfejsów – coś na zasadzie klocków, które ze sobą ukłamy. Znajdziemy tu m.in. znany nam już GridPane, Button, Label – choć znajdziesz tu również wykresy, mapy, menu, obiekty 3D i multimedia. W internecie prawdopodobnie znajdziesz wiele, wiele innych komponentów.

2 – drzewo interfejsu, w tej sekcji możemy podejrzeć całą strukturę interfejsu, wszystkie zależności między komponentami – kto jest czyim rodzicem, dzieckiem itd.

3 – interfejs, w tym oknie będziemy budować z klocków nasz cały interfejs

4 – okno properties, pozwala na stylowanie komponentów, układanie ich, nadawanie nazw (ID) oraz ustawianie triggerów na konkretne akcje (np. wywołaj to -> gdy wcisnę przycisk)

Cel

Warto mieć zawsze jakiś cel, naszym celem jest zbudowanie interfejsu dla kalkulatora – prostego kalkulatora z operacjami na liczbach zmiennoprzecinkowych – czyli: dodawanie, odejmowanie, mnożenie i dzielenie.

Ja wymyśliłem sobie, że mój kalkulator będzie wyglądał jak najpopularniejsze kalkulatory:

Dodałem również legendę z jakich komponentów skorzystałem do ułożenia ich dzieci. Głównym komponentem to SplitPane, który dzieli nam rodzica na dwie części, w górnej części umieściłem label na wynik, zaś na dole do ułożenia buttonów skorzystałem już nam znanego GridPane.

Realizacja!

Choć możesz stworzyć całkiem interfejs (spełniający tylko te warunki co wyżej) to i tak pokażę Ci jak ustawić najważniejsze dla nas cechy.

Rozpocząłem od wstawienia Labela dla wyników – aby go lekko wyróżnić ustawiłem jego tło. Na screenie zaznaczone jest gdzie można ustawiać style, skąd je znać?

Albo z dokumentacji, albo z głowy jeśli kiedykolwiek korzystałeś z CSS. 😉

Po zmianie tła dodałem GridPane w dolnej części dla Buttonów.

Po dodaniu GridPane automatycznie skorzystałem z opcji Fit to parent.

Następnym krokiem jest dodanie dodatkowych kolumn i wierszy – tak, aby wstawić 16 buttonów – czyli siatka 4×4.

Klikamy prawym przypiskiem na Grid, wybieramy opcję GridPane i odpowiednią opcję ADD.

Mając już siatkę, mozemy do każdego okienka dodać button i ustawić w nim odpowiedni tekst w taki sposób:

Następnie w drzewie projektu zaznaczamy wszystkie buttonu przy użyciu SHIFT + LPM. Następnie możemy zmienić ich pozycję względem komórki – wyśrodkujmy je.

Kolejnym krokiem jest nazwać każdy przycisk i przypisać mu trigger na akcję.

Powtórz tę czynność dla każdego przycisku, dla labela nadaj  tylko id.

Na koniec musimy dodać nazwę Controllera dla naszego interfejsu (tak naprawdę jest to scena, którą możemy wstawiać w okienko), aby w ogóle mógł się uruchomić. Robimy to pod drzewem projektu w zakładce Controller.

U mnie controller ma nazwę Controller, który znajduje się w pakiecie sample.

Na koniec zapisujemy interfejs jako plik .fxml.

Uruchomienie

Mając już cały interfejs możemy przejść do jego uruchomienia. W tym celu tworzymy prosty projekt JavaFx – pamiętając, aby nazwa pakietu i controllera zgadzała się z tą pliku .fxml.

Skopiujmy nasz interfejs – u mnie jest to calculator.fxml – do głównej paczki i uruchommy nasze okienko.

@Override
public void start(Stage primaryStage) throws Exception{
    Parent root = FXMLLoader.load(getClass().getResource("calculator.fxml"));
    primaryStage.setTitle("Calculator - 1024kb.pl");
    primaryStage.setScene(new Scene(root));
    primaryStage.sizeToScene();
    primaryStage.show();
}

Ta część kodu:

primaryStage.setScene(new Scene(root));
primaryStage.sizeToScene();

Pozwala na automatyczne tworzenie wysokości i szerokości okienka.

Po uruchomieniu…

Exception in Application start method
java.lang.reflect.InvocationTargetException
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  at java.lang.reflect.Method.invoke(Method.java:498)
  at com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:389)
  at com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:328)
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  at java.lang.reflect.Method.invoke(Method.java:498)
  at sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:767)
Caused by: java.lang.RuntimeException: Exception in Application start method
  at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:917)
  at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$154(LauncherImpl.java:182)
  at java.lang.Thread.run(Thread.java:748)
Caused by: javafx.fxml.LoadException: Error resolving onAction='#clickButtonAdd', either the event handler is not in the Namespace or there is an error in the script.
/C:/Users/Klimek/IdeaProjects/calculatorFx/out/production/calculatorFx/sample/calculator.fxml:38

Powinniśmy otrzymać mniej więcej taki błąd, co teraz zrobić?

Controller

Problem tkwi w tym, że nasz Controller nie ma zadeklarowanych triggerów, które są przypisane do buttonów – pamiętasz jak ustawiałeś nazwę np. clickButtonOne? Musi ona znaleźć teraz odwzorowanie w kontrollerze, który został podpiętym.

Teraz mój kontroler wygląda tak:

package sample;

public class Controller {


    public void clickButtonAdd() {

    }

    public void clickButtonMinus() {

    }

    public void clickButtonSeven() {

    }

    public void clickButtonEight() {

    }

    public void clickButtonFour() {

    }

    public void clickButtonFive() {

    }

    public void clickButtonOne() {

    }

    public void clickButtonTwo() {

    }

    public void clickButtonMultiply() {

    }

    public void clickButtonDive() {

    }

    public void clickButtonNine() {

    }

    public void clickButtonClear() {

    }

    public void clickButtonSix() {

    }

    public void clickButtonDot() {

    }

    public void clickButtonThree() {

    }

    public void clickButtonZero() {

    }


}

Co prawda nie mamy tutaj jeszcze żadnej logiki to i tak okienko się otwiera.

Podsumowanie

Mam nadzieję, że doceniłeś, że stworzenie już bardziej skomplikowanego interfejsu niż ten z poprzedniej lekcji było prostsze przy użyciu SceneBuilder. Niestety tworzenie interfejsu z poziomu kodu jest ciężkie, więc i nieopłacalne. Można to zrobić szybciej, prościej i czytelniej z poziomu dedykowanej do tego aplikacji.

Czytelniej – też jest ważnym aspektem – to dzięki umieszczeniu widoku w pliku .fxml kod naszej aplikacji jest czytelniejszy.

Co prawda nasz kalkulator na razie tylko wygląda, to już w następnej lekcji go oprogramujemy. 😉

Jeśli chcesz poćwiczyć tworzenie interfejsów w narzędziu jakim jest SceneBuilder to wykonaj prosty interfejs graficzny:

  1. 6 wierszy na 4 kolumny
  2. Pierwsza kolumna ma mieć tekst: Z jednostki X do Y
  3. Druga kolumna ma być odpowiedzialna za wprowadzanie wartości
  4. W trzeciej kolumnie ma być przycisk „Convert”
  5. W czwartej kolumnie ma się pojawić wynik konwersji
  6. Każdy wiersz odpowiednio ma odpowiadać z konwersję:
    • tona -> gramy
    • metr -> milimetr
    • kilometry -> mila morska
    • celsjusza -> fahrenheit
    • galon -> litry
    • funt -> kilogram

Logiką tego interfejsu zajmiemy się w kolejnej lekcji. 😉

Subscribe
Powiadom o
guest
0 komentarzy
Inline Feedbacks
View all comments