Wyślij zapytanie Dołącz do Sii

Ponad rok temu stanąłem przed problemem wyboru odpowiedniej technologii dla zbudowania aplikacji desktopowej. Musiałem szybko przygotować sporo ekranów, które byłbym gotów zaprezentować naszemu klientowi jako prototyp działającego rozwiązania.

Ponieważ do tamtej pory zajmowałem się tylko i wyłącznie tworzeniem systemów dostępnych przez przeglądarkę internetową w JAVA-ie, zacząłem szukać porad w Internecie, krążąc wokół tego języka programowania. Byłem wręcz przekonany, że w 2015 roku istnieją już biblioteki, narzędzia i przykłady, w jaki sposób szybko zbudować aplikacje standalone w tej właśnie technologii.

Jak zbudować aplikacje standalone? Poszukiwanie rozwiązania

Wiedziałem od dawna o tym, że istnieje Swing (ponieważ Swing istnieje od dawna :)), ale sposób tworzenia aplikacji w Swingu wydawał się dość toporny. Szybko natrafiłem na JavaFX, który został dołączony do JDK już od wersji 7. Po bliższym przyjrzeniu się temu frameworkowi doszedłem do wniosku, że jest to właśnie to, czego szukałem.

JavaFX umożliwia budowanie widoków w XML-u, obsługuje style pisane w CSS-ach, a na dodatek istnieje JavaFX Scene Builder, z pomocą którego w miarę szybko przygotuję to, czego potrzebuję. Z doświadczenia wiedziałem, że każda świeża technologia niesie ze sobą także i problemy, ale chęć poznania czegoś nowego przyćmiewała migającą czerwoną lampkę w mojej głowie. Zabrałem się do pracy…

Czym jest JavaFX i jak działa?

JavaFX została opracowana jako następca Swinga i jest obecnie rekomendowana przez dostawcę tego oprogramowania – firmę Oracle – do tworzenia GUI między innymi w samodzielnych aplikacjach. Interfejs użytkownika od początku do końca możemy tworzyć w „czystej” JAVA-ie, ale istnieje także możliwość wykorzystania w tym celu plików FXML.

Pierwszy sposób jest bardzo podobny do pisania aplikacji w Swingu, gdzie krok po kroku, linijka po linijce, kładziemy kontrolki na zdefiniowanych wcześniej panelach.

Dużo ciekawszym podejściem jest drugi sposób, pozwalający na wyraźniejsze oddzielenie warstwy widoku od kontrolera.

Pliki FXML to nic innego, jak XML z odpowiednimi znacznikami wewnątrz. Inicjalizacją obiektów naszego widoku, ustawieniem ich właściwości oraz stworzeniem zależności między nimi zajmuje się wówczas za nas klasa FXMLoader.

Pomimo, że użycie i zaprojektowanie widoku w plikach FXML jest znacznie szybsze i wygodniejsze, nie da się uniknąć tworzenia kontrolek w klasach obsługujących widoki (Controlers). Wszędzie tam, gdzie będziecie chcieli dynamicznie zarządzać położeniem i ilością kontrolek na ekranie, trzeba będzie w mniejszym lub większym stopniu obsługę takich przypadków zaimplementować w klasach. Warto przemyśleć na początku projektowania aplikacji, gdzie i ile będzie takich miejsc, ponieważ mogą kosztować trochę więcej nakładu pracy.

Lepiej używać JavaFX od JDK 8

Choć JavaFX pojawiła się już od JDK 7, to należy zwrócić uwagę na fakt, że w wersji 8 została znacząco poprawiona i ulepszona. Oprócz poprawy kilku istotnych błędów, odświeżony został całkowicie podstawowy wygląd.

Dla mnie istotny wpływ miały właściwie trzy rzeczy, jeśli chodzi o różnicę pomiędzy JDK 7 i 8:

  • w starszej wersji JAVA-y nie mogłem użyć biblioteki zewnętrznej ControlsFX, którą chciałem wykorzystać do walidacji,
  • błąd skalowania czcionek na różnych systemach operacyjnych w konsekwencji wymusił określanie explicite rozmiaru czcionki przy każdym użyciu chociażby obiektu javafx.scene.control.Label,
  • błędy związane z odświeżaniem styli CSS przypisanych do danej kontrolki spowodowały konieczność kasowania określonej klasy stylu i ustawiania go ponownie.

Przed wdrożeniem aplikacji na stacjach roboczych (np. w środowisku klienta) proponuję jednak najpierw upewnić się, jaka wersja JRE będzie zainstalowana na komputerach. W wielu korporacjach istnieją standardy zainstalowanego oprogramowania i może okazać się, że nie będziemy mogli w ogóle uruchomić aplikacji.

Wielojęzyczność UI

W JavaFX nie znajdziemy gotowych mechanizmów wspierających przygotowanie UI dla wielu języków. Aplikacje, które udało mi się zbudować, nie miały takiego wymagania, ale należy to wziąć pod uwagę przy tworzeniu nowego programu.

Wyświetlane teksty można definiować zarówno w plikach FXML jak i klasach je obsługujących. O ile zastosowanie mechanizmu properties (podobnego do tego w Spring MVC) w klasach łatwo można sobie wyobrazić i zrealizować, to zamiana tekstów w plikach FXML, będzie wymagała najprawdopodobniej rozszerzenia standardowych kontrolek.

Przygotowanie modelu danych

Kolejnym istotnym elementem w projektowaniu naszej aplikacji jest zamodelowanie klas będących nośnikiem danych i związanie ich z kontrolkami używanymi na ekranie. Przez związanie mam na myśli użycie np. interfejsu javafx.beans.value.ChangeListener, służącego do aktualizowania wartości w modelu. Takie podejście będzie miało zastosowanie wszędzie tam, gdzie warstwa backendu czy serwisowa będzie przetwarzać te dane w bardziej złożonych algorytmach.

Na prostych ekranach z prostą logiką możemy spokojnie wykorzystywać klasę javafx.scene.Scene i jej przydatną metodę lookup do wyszukiwania obiektów na aktywnej formatce. Należy jednak pamiętać o tym, że metoda getScene dostępna przy każdej kontrolce lub panelu będzie zwracała wartość null w przypadku, w którym używana kontrolka nie będzie znajdowała się na aktualnie wyświetlanym/aktywnym ekranie.

Z taką sytuacją będziemy mieli do czynienia przy przechowywaniu całych ekranów wraz z wypełnionymi wartościami w pamięci programu. Dostęp do danych zawartych na takich elementach będzie wówczas utrudniony.

JavaFX Scene Builder

Bardzo przydatnym narzędziem służącym do projektowania interfejsu użytkownika jest aplikacja JavaFX Scene Builder. Dzięki niej przygotujemy szybko odpowiedni plik FXML.

Jeśli chodzi o „rapid development” średnio złożonych ekranów to właśnie to oprogramowanie pozwala na szybkie przygotowanie kompletnych makiet. Można sobie wyobrazić, że takim samym narzędziem będzie posługiwał się analityk pracujący z klientem nad uszczegółowieniem wymagań odnośnie aplikacji. Opracowywać może gotowe kawałki UI używane potem przez programistów do spięcia wszystkiego w całość.

Ekran główny programu JavaFX Scene Builder
Ryc. 1 Ekran główny programu JavaFX Scene Builder

W JavaFX standardowe kontrolki możemy rozszerzać o dodatkowe właściwości wykorzystywane w aplikacji. Możemy to zrobić poprzez dziedziczenie po ich klasie bazowej. Przykład rozszerzenia elementu javafx.scene.control.TextField pokazuje poniższy fragment kodu:

public class TextFieldWithError extends TextField {
    private String errorMag;
	public String getErrorMsg() {
	    return errorMag;
	}
	public void setErrorMag( String errorMag ) {
	    this errorMag = errorMag;
	}
}

Zdefiniowane przez nas nowe pole będzie widoczne w JavaFX Scene Builder na liście Properties po prawej stronie ekranu w sekcji Custom.

Dodanie nowego pola do standardowej kontrolki TextField
Ryc. 2 Dodanie nowego pola do standardowej kontrolki TextField

Wady JavaFX Scene Builder

Obok wielu zalet oprogramowanie to posiada także wady. Przede wszystkim nie potrafi dokładnie odwzorowywać styli CSS zdefiniowanych w pliku zewnętrznym. Miałem problem z podłączeniem styli w taki sposób, aby wygląd projektowanego interfejsu odpowiadał temu w skompilowanej i uruchomionej aplikacji.

W przypadku, w którym plik FXML jest większy lub gdy chcemy podzielić ekrany na stałe kawałki, możemy zastosować klauzulę include jak na poniższym przykładzie.

<fx:include source=”FirstTab.fxml” />

Problem w tym, że wówczas stracimy możliwość pełnej edycji takiego pliku w programie JavaFX Scene Builder. Plik FXML, który składa się z plików podrzędnych zostanie wyświetlony w narzędziu bez możliwości edycji zagnieżdżonych elementów. Jeśli chcemy edytować zagnieżdżony kawałek powinniśmy plik otworzyć w osobnym oknie programu. Jest to bardzo duża wada, która mocno utrudnia budowanie bardziej złożonych ekranów i aplikacji.

Wydajność oraz zużycie pamięci

Jeśli chodzi o kwestie wydajnościowe, to pamiętać należy o jednym istotnym elemencie przy budowaniu skomplikowanych ekranów. Wczytanie pliku FXML oraz powołanie do życia wszystkich obiektów i komponentów z nim związanych, potrafi zająć zauważalną chwilę (w opracowanej przeze mnie produkcyjnej aplikacji nawet do ok. 1 sek.). Trzeba wziąć to pod uwagę przy projektowaniu przepływu ekranów. Jeżeli chcemy podłączyć tworzenie ekranu, tzn. wczytanie pliku FXML, pod zaznaczany komponent CheckBox, opóźnienia we wczytywaniu mogą być irytujące dla użytkownika.

JavaFX ma spore zapotrzebowanie na pamięć, a niewielkie aplikacje mogą zajmować już sporo pamięci operacyjnej. Nawet takie funkcje jak przełączanie ekranów (przy założeniu, że zbudowane ekrany trzymamy w pamięci i jedynie zmieniamy „dzieci” jednego z paneli głównych) potrafi znacząco podbijać zużycie pamięci. Osobom zainteresowanym polecam dogłębne zapoznanie się z wieloma wpisami w sieci na temat Memory leaks in JavaFX.

Dystrybucja aplikacji w ramach organizacji klienta

Na pewno, prędzej czy później, staniecie przed zagadnieniem dystrybucji Waszej aplikacji w organizacji klienta. Można to zrobić na dwa sposoby, które były brane przeze mnie pod uwagę. Żaden z nich nie jest niestety pozbawiony wad.

Pierwszy sposób to dystrybucja naszej aplikacji jako biblioteki uruchamialnej JAR. Tego typu aplikacje są rzadko spotykane, ponieważ nasz kod może zostać w bardzo łatwy sposób rozpakowany, zdekompilowany i użyty przez kogoś innego. Oczywiście, można użyć programów do zaciemniania kodu aplikacji, ale i tak pozostają pliki FXML, czy inne zasoby, które muszą pozostać w niezmienionej formie.

Drugi sposób to dystrybucja naszej aplikacji w pliku EXE. Determinuje to od razu rodzinę systemów operacyjnych, na których aplikację da się uruchomić – w tym przypadku to Windows. W moim wdrożeniu sprawdziło się właśnie takie podejście.

Wygodnym narzędziem do zamiany JAR na EXE jest oprogramowanie Launch4J. Jest prosty w obsłudze i posiada wszystkie niezbędne funkcjonalności, z których bardzo przydatną jest możliwość zdefiniowania komunikatów pokazywanych w zależności od wystąpienia problemów tj. błędy uruchomienia, brak wymaganej wersji JRE, błędy instalacji itp.

Podsumowanie

Reasumując, JavaFX to technologia, w której szybko można stworzyć średnio skomplikowaną aplikację, ale zalecam jej używanie dopiero od wersji JDK 8. Na dzień dzisiejszy jest młodą technologią, która ma jeszcze kilka istotnych ograniczeń. Mam nadzieję, że w kolejny wersjach JAVA-y zostanie mocno rozwinięta i poprawiona. Na pewno chciałbym jeszcze zbadać w niej realizację obsługi grafiki 3D.

3.7/5 ( głosy: 8)
Ocena:
3.7/5 ( głosy: 8)
Autor
Avatar
Tomasz Czerwonka

Pracuję na stanowisku Architekta rozwiązań w SII. Jestem odpowiedzialny za rozwój i utrzymanie systemów budowanych w oparciu o język JAVA. Prywatnie szczęśliwy mąż i ojciec oraz początkujący gitarzysta :)

Zostaw komentarz

Anuluj pisanie odpowiedzi

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *

    1. W moim przypadku właśnie chodziło o uproszczenie aplikacji na tyle, żeby dało się ją szybko wdrożyć na standardowych stacjach roboczych w środowisku klienta. Dostęp do jar i wgląd w kod nie miał aż takiego znaczenia, ze względu na to, że aplikacja jest używana przez użytkowników wewnętrznych w organizacji. W artykule celowo nie wchodziłem w temat ukrywania kodu, ale rzeczywiście jest to istotny element w przypadku, w którym udostępniamy aplikację na zewnątrz.

  • Panie Tomku,
    wsparcie dla i18n w plikach FXML jest i sprawdza się całkiem w porządku (zarówno z poziomu kodu jak i SceneBuilder’a) – problemy są, ale szczątkowe – nie ma na przykład prostego sposobu na przetłumaczenie menu kontekstowego kontrolki pola tekstowego. Poza tym – jest okej.

    Jak wspomniał Michał w poprzednim komentarzu – Java to Java i kod można co najwyżej mniej lub bardziej skutecznie zaciemnić (np. proguard)/szyfrować (przy okazji – HASP jest tutaj arcyciekawym rozwiązaniem).

    Jeśli zaś chodzi o dystrybucje, to warto także wspomnieć o czymś takim jak fxlauncher i podobne, które bardzo skutecznie dostarczają mechanizmy auto-update. Mamy także Java Web Start – z tego Oracle się niestety wycofuje, ale nadal jest wspierane.

    No i najważniejsze – najbezpieczniejszą dla aplikacji dystrybucją jest jej dystrybucja razem z JRE – znajdzie się to w prawie każdym komercyjnym projekcie (oprócz tego nawet JavaFX Packager w domyślnej konfiguracji także pakuje JRE do paczki z aplikacją).

    JavaFX ma już całkiem nieźle rozwinięte comminity oraz bazę kodu open-source – warto poczytać o Griffon, afterburner i wielu innych, które znakomicie upraszczają tworzenie dużych, komercyjnych aplikacji – tutaj seria przykładów https://dlemmermann.wordpress.com/2015/10/22/javafx-real-world-apps-emirates-airlines-network-capacity-optimization/.

    1. Panie Macieju,
      Dziękuję za uzupełnienie mojego artykułu swoim merytorycznym komentarzem – jest to cenna wiedza. Ma Pan rację jeśli chodzi o wsparcie dla i18n w plikach FXML. Akapit „Wielojęzyczność UI” w tym kontekście jest mylący. Mam nadzieję, że ktoś kto będzie czytał ten artykuł dojdzie także i do komentarzy 🙂

Może Cię również zainteresować

Pokaż więcej artykułów

Bądź na bieżąco

Zasubskrybuj naszego bloga i otrzymuj informacje o najnowszych wpisach.

Otrzymaj ofertę

Jeśli chcesz dowiedzieć się więcej na temat oferty Sii, skontaktuj się z nami.

Wyślij zapytanie Wyślij zapytanie

Natalia Competency Center Director

Get an offer

Dołącz do Sii

Znajdź idealną pracę – zapoznaj się z naszą ofertą rekrutacyjną i aplikuj.

Aplikuj Aplikuj

Paweł Process Owner

Join Sii

ZATWIERDŹ

This content is available only in one language version.
You will be redirected to home page.

Are you sure you want to leave this page?