{"id":2023,"date":"2016-04-06T15:04:24","date_gmt":"2016-04-06T13:04:24","guid":{"rendered":"https:\/\/sii.pl\/blog\/?p=2023"},"modified":"2023-01-02T14:47:33","modified_gmt":"2023-01-02T13:47:33","slug":"mocne-i-slabe-strony-javafx","status":"publish","type":"post","link":"https:\/\/sii.pl\/blog\/mocne-i-slabe-strony-javafx\/","title":{"rendered":"Mocne i s\u0142abe strony JavaFX"},"content":{"rendered":"\n<p>Ponad rok temu stan\u0105\u0142em przed problemem wyboru odpowiedniej technologii dla zbudowania aplikacji desktopowej.&nbsp;Musia\u0142em szybko przygotowa\u0107 sporo ekran\u00f3w, kt\u00f3re by\u0142bym got\u00f3w zaprezentowa\u0107 naszemu klientowi jako prototyp dzia\u0142aj\u0105cego rozwi\u0105zania.<\/p>\n\n\n\n<p>Poniewa\u017c do tamtej pory zajmowa\u0142em si\u0119 tylko i wy\u0142\u0105cznie tworzeniem system\u00f3w dost\u0119pnych przez przegl\u0105dark\u0119 internetow\u0105 w JAVA-ie, zacz\u0105\u0142em szuka\u0107 porad w Internecie, kr\u0105\u017c\u0105c wok\u00f3\u0142 tego j\u0119zyka programowania. By\u0142em wr\u0119cz przekonany, \u017ce w 2015 roku istniej\u0105 ju\u017c biblioteki, narz\u0119dzia i przyk\u0142ady, w jaki spos\u00f3b szybko zbudowa\u0107 aplikacje standalone w tej w\u0142a\u015bnie technologii.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Jak zbudowa\u0107 aplikacje standalone? Poszukiwanie rozwi\u0105zania<\/strong><\/h2>\n\n\n\n<p>Wiedzia\u0142em od dawna o tym, \u017ce istnieje Swing (poniewa\u017c Swing istnieje od dawna :)), ale spos\u00f3b tworzenia aplikacji w Swingu wydawa\u0142 si\u0119 do\u015b\u0107 toporny. Szybko natrafi\u0142em na JavaFX, kt\u00f3ry zosta\u0142 do\u0142\u0105czony do JDK ju\u017c od wersji 7. Po bli\u017cszym przyjrzeniu si\u0119 temu frameworkowi doszed\u0142em do wniosku, \u017ce jest to w\u0142a\u015bnie to, czego szuka\u0142em.<\/p>\n\n\n\n<p>JavaFX umo\u017cliwia budowanie widok\u00f3w w XML-u, obs\u0142uguje style pisane w CSS-ach, a na dodatek istnieje&nbsp;<em>JavaFX Scene Builder,&nbsp;<\/em>z pomoc\u0105 kt\u00f3rego w miar\u0119 szybko przygotuj\u0119 to, czego potrzebuj\u0119. Z do\u015bwiadczenia wiedzia\u0142em, \u017ce ka\u017cda \u015bwie\u017ca technologia niesie ze sob\u0105 tak\u017ce i problemy, ale ch\u0119\u0107 poznania czego\u015b nowego przy\u0107miewa\u0142a migaj\u0105c\u0105 czerwon\u0105 lampk\u0119 w mojej g\u0142owie. Zabra\u0142em si\u0119 do pracy\u2026<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Czym jest JavaFX i jak dzia\u0142a?<\/strong><\/h2>\n\n\n\n<p>JavaFX zosta\u0142a opracowana jako nast\u0119pca Swinga i jest obecnie rekomendowana przez dostawc\u0119 tego oprogramowania \u2013 firm\u0119 Oracle \u2013 do tworzenia GUI mi\u0119dzy innymi w samodzielnych aplikacjach. Interfejs u\u017cytkownika od pocz\u0105tku do ko\u0144ca mo\u017cemy tworzy\u0107 w \u201eczystej\u201d JAVA-ie, ale istnieje tak\u017ce mo\u017cliwo\u015b\u0107 wykorzystania w tym celu plik\u00f3w FXML.<\/p>\n\n\n\n<p><strong>Pierwszy spos\u00f3b<\/strong> jest bardzo podobny do pisania aplikacji w Swingu, gdzie krok po kroku, linijka po linijce, k\u0142adziemy kontrolki na zdefiniowanych wcze\u015bniej panelach.<\/p>\n\n\n\n<p>Du\u017co ciekawszym podej\u015bciem jest <strong>drugi spos\u00f3b<\/strong>, pozwalaj\u0105cy na wyra\u017aniejsze oddzielenie warstwy widoku od kontrolera.<\/p>\n\n\n\n<p>Pliki FXML to nic innego, jak XML z odpowiednimi znacznikami wewn\u0105trz. Inicjalizacj\u0105 obiekt\u00f3w naszego widoku, ustawieniem ich w\u0142a\u015bciwo\u015bci oraz stworzeniem zale\u017cno\u015bci mi\u0119dzy nimi zajmuje si\u0119 w\u00f3wczas za nas klasa&nbsp;<em>FXMLoader<\/em>.<\/p>\n\n\n\n<p>Pomimo, \u017ce u\u017cycie i zaprojektowanie widoku w plikach FXML jest znacznie szybsze i wygodniejsze, nie da si\u0119 unikn\u0105\u0107 tworzenia kontrolek w klasach obs\u0142uguj\u0105cych widoki (<em>Controlers<\/em>). Wsz\u0119dzie tam, gdzie b\u0119dziecie chcieli dynamicznie zarz\u0105dza\u0107 po\u0142o\u017ceniem i ilo\u015bci\u0105 kontrolek na ekranie, trzeba b\u0119dzie w mniejszym lub wi\u0119kszym stopniu obs\u0142ug\u0119 takich przypadk\u00f3w zaimplementowa\u0107 w klasach. <strong>Warto przemy\u015ble\u0107 na pocz\u0105tku projektowania aplikacji<\/strong>, gdzie i ile b\u0119dzie takich miejsc, poniewa\u017c mog\u0105 kosztowa\u0107 troch\u0119 wi\u0119cej nak\u0142adu pracy.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Lepiej u\u017cywa\u0107 JavaFX od JDK 8<\/strong><\/h2>\n\n\n\n<p>Cho\u0107 JavaFX pojawi\u0142a si\u0119 ju\u017c od JDK 7, to nale\u017cy zwr\u00f3ci\u0107 uwag\u0119 na fakt, \u017ce w wersji 8 zosta\u0142a znacz\u0105co poprawiona i ulepszona. Opr\u00f3cz poprawy kilku istotnych b\u0142\u0119d\u00f3w, od\u015bwie\u017cony zosta\u0142 ca\u0142kowicie podstawowy wygl\u0105d.<\/p>\n\n\n\n<p>Dla mnie istotny wp\u0142yw mia\u0142y w\u0142a\u015bciwie trzy rzeczy, je\u015bli chodzi o r\u00f3\u017cnic\u0119 pomi\u0119dzy JDK 7 i 8:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>w starszej wersji JAVA-y nie mog\u0142em u\u017cy\u0107 biblioteki zewn\u0119trznej <a href=\"http:\/\/fxexperience.com\/controlsfx\/\" rel=\"nofollow\" ><em>ControlsFX<\/em><\/a>, kt\u00f3r\u0105 chcia\u0142em wykorzysta\u0107 do walidacji,<\/li><li>b\u0142\u0105d skalowania czcionek na r\u00f3\u017cnych systemach operacyjnych w konsekwencji wymusi\u0142 okre\u015blanie&nbsp;<em>explicite<\/em>&nbsp;rozmiaru czcionki przy ka\u017cdym u\u017cyciu chocia\u017cby obiektu&nbsp;<em>javafx.scene.control.Label<\/em>,<\/li><li>b\u0142\u0119dy zwi\u0105zane z od\u015bwie\u017caniem styli CSS przypisanych do danej kontrolki spowodowa\u0142y konieczno\u015b\u0107 kasowania okre\u015blonej klasy stylu i ustawiania go ponownie.<\/li><\/ul>\n\n\n\n<p>Przed wdro\u017ceniem aplikacji na stacjach roboczych (np. w \u015brodowisku klienta) proponuj\u0119 jednak najpierw <strong>upewni\u0107 si\u0119, jaka wersja JRE b\u0119dzie zainstalowana na komputerach<\/strong>. W wielu korporacjach istniej\u0105 standardy zainstalowanego oprogramowania i mo\u017ce okaza\u0107 si\u0119, \u017ce nie b\u0119dziemy mogli w og\u00f3le uruchomi\u0107 aplikacji.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Wieloj\u0119zyczno\u015b\u0107 UI<\/strong><\/h2>\n\n\n\n<p>W JavaFX nie znajdziemy gotowych mechanizm\u00f3w wspieraj\u0105cych przygotowanie UI dla wielu j\u0119zyk\u00f3w. Aplikacje, kt\u00f3re uda\u0142o mi si\u0119 zbudowa\u0107, nie mia\u0142y takiego wymagania, ale nale\u017cy to wzi\u0105\u0107 pod uwag\u0119 przy tworzeniu nowego programu.<\/p>\n\n\n\n<p>Wy\u015bwietlane teksty mo\u017cna definiowa\u0107 zar\u00f3wno w plikach FXML jak i klasach je obs\u0142uguj\u0105cych. O ile zastosowanie mechanizmu properties (podobnego do tego w&nbsp;<em>Spring MVC<\/em>) w klasach \u0142atwo mo\u017cna sobie wyobrazi\u0107 i zrealizowa\u0107, to zamiana tekst\u00f3w w plikach FXML, b\u0119dzie wymaga\u0142a najprawdopodobniej rozszerzenia standardowych kontrolek.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Przygotowanie modelu danych<\/strong><\/h2>\n\n\n\n<p>Kolejnym istotnym elementem w projektowaniu naszej aplikacji jest zamodelowanie klas b\u0119d\u0105cych no\u015bnikiem danych i zwi\u0105zanie ich z kontrolkami u\u017cywanymi na ekranie. Przez zwi\u0105zanie mam na my\u015bli u\u017cycie np. interfejsu&nbsp;<em>javafx.beans.value.ChangeListener<\/em>, s\u0142u\u017c\u0105cego do aktualizowania warto\u015bci w modelu. Takie podej\u015bcie b\u0119dzie mia\u0142o zastosowanie wsz\u0119dzie tam, gdzie warstwa backendu czy serwisowa b\u0119dzie przetwarza\u0107 te dane w bardziej z\u0142o\u017conych algorytmach.<\/p>\n\n\n\n<p>Na prostych ekranach z prost\u0105 logik\u0105 mo\u017cemy spokojnie wykorzystywa\u0107 klas\u0119&nbsp;<em>javafx.scene.Scene<\/em>&nbsp;i jej przydatn\u0105 metod\u0119&nbsp;<em>lookup<\/em>&nbsp;do wyszukiwania obiekt\u00f3w na aktywnej formatce. Nale\u017cy jednak pami\u0119ta\u0107 o tym, \u017ce metoda&nbsp;<em>getScene<\/em>&nbsp;dost\u0119pna przy ka\u017cdej kontrolce lub panelu b\u0119dzie zwraca\u0142a warto\u015b\u0107&nbsp;<em>null<\/em>&nbsp;w przypadku, w kt\u00f3rym u\u017cywana kontrolka nie b\u0119dzie znajdowa\u0142a si\u0119 na aktualnie wy\u015bwietlanym\/aktywnym ekranie.<\/p>\n\n\n\n<p>Z tak\u0105 sytuacj\u0105 b\u0119dziemy mieli do czynienia <strong>przy przechowywaniu ca\u0142ych ekran\u00f3w wraz z wype\u0142nionymi warto\u015bciami w pami\u0119ci programu<\/strong>. Dost\u0119p do danych zawartych na takich elementach b\u0119dzie w\u00f3wczas utrudniony.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>JavaFX Scene Builder<\/strong><\/h2>\n\n\n\n<p>Bardzo przydatnym narz\u0119dziem s\u0142u\u017c\u0105cym do projektowania interfejsu u\u017cytkownika jest aplikacja&nbsp;<em>JavaFX Scene Builder<\/em>. Dzi\u0119ki niej przygotujemy szybko odpowiedni plik FXML.<\/p>\n\n\n\n<p>Je\u015bli chodzi o \u201erapid development\u201d \u015brednio z\u0142o\u017conych ekran\u00f3w to w\u0142a\u015bnie to oprogramowanie <strong>pozwala na szybkie przygotowanie kompletnych makiet<\/strong>. Mo\u017cna sobie wyobrazi\u0107, \u017ce takim samym narz\u0119dziem b\u0119dzie pos\u0142ugiwa\u0142 si\u0119 analityk pracuj\u0105cy z klientem nad uszczeg\u00f3\u0142owieniem wymaga\u0144 odno\u015bnie aplikacji. Opracowywa\u0107 mo\u017ce gotowe kawa\u0142ki UI u\u017cywane potem przez programist\u00f3w do spi\u0119cia wszystkiego w ca\u0142o\u015b\u0107.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2022\/10\/Ryc.-1-6.png\"><img decoding=\"async\" width=\"1024\" height=\"661\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2022\/10\/Ryc.-1-6-1024x661.png\" alt=\"Ekran g\u0142\u00f3wny programu JavaFX Scene Builder\" class=\"wp-image-16532\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2022\/10\/Ryc.-1-6-1024x661.png 1024w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2022\/10\/Ryc.-1-6-300x194.png 300w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2022\/10\/Ryc.-1-6-768x495.png 768w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2022\/10\/Ryc.-1-6.png 1240w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption><em>Ryc. 1 Ekran g\u0142\u00f3wny programu JavaFX Scene Builder<\/em><\/figcaption><\/figure><\/div>\n\n\n\n<p>W JavaFX standardowe kontrolki mo\u017cemy rozszerza\u0107 o dodatkowe w\u0142a\u015bciwo\u015bci wykorzystywane w aplikacji. Mo\u017cemy to zrobi\u0107 poprzez dziedziczenie po ich klasie bazowej. Przyk\u0142ad rozszerzenia elementu&nbsp;<em>javafx.scene.control.TextField<\/em>&nbsp;pokazuje poni\u017cszy fragment kodu:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: javafx; title: ; notranslate\" title=\"\">\npublic class TextFieldWithError extends TextField {\n    private String errorMag;\n\tpublic String getErrorMsg() {\n\t    return errorMag;\n\t}\n\tpublic void setErrorMag( String errorMag ) {\n\t    this errorMag = errorMag;\n\t}\n}\n<\/pre><\/div>\n\n\n<p>Zdefiniowane przez nas nowe pole b\u0119dzie widoczne w&nbsp;<em>JavaFX Scene Builder<\/em>&nbsp;na li\u015bcie&nbsp;<em>Properties<\/em>&nbsp;po prawej stronie ekranu w sekcji&nbsp;<em>Custom<\/em>.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2022\/10\/Ryc.-2-1.jpg\"><img decoding=\"async\" width=\"189\" height=\"142\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2022\/10\/Ryc.-2-1.jpg\" alt=\"Dodanie nowego pola do standardowej kontrolki TextField\" class=\"wp-image-16534\"\/><\/a><figcaption><em>Ryc. 2 Dodanie nowego pola do standardowej kontrolki TextField<\/em><\/figcaption><\/figure><\/div>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Wady JavaFX Scene Builder<\/strong><\/h2>\n\n\n\n<p>Obok wielu zalet oprogramowanie to posiada tak\u017ce wady. Przede wszystkim <strong>nie potrafi dok\u0142adnie odwzorowywa\u0107 styli CSS zdefiniowanych w pliku zewn\u0119trznym<\/strong>. Mia\u0142em problem z pod\u0142\u0105czeniem styli w taki spos\u00f3b, aby wygl\u0105d projektowanego interfejsu odpowiada\u0142 temu w skompilowanej i uruchomionej aplikacji.<\/p>\n\n\n\n<p>W przypadku, w kt\u00f3rym plik FXML jest wi\u0119kszy lub gdy chcemy podzieli\u0107 ekrany na sta\u0142e kawa\u0142ki, mo\u017cemy zastosowa\u0107 klauzul\u0119&nbsp;<em>include<\/em>&nbsp;jak na poni\u017cszym przyk\u0142adzie.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: javafx; title: ; notranslate\" title=\"\">\n&lt;fx:include source=\u201dFirstTab.fxml\u201d \/&gt;\n<\/pre><\/div>\n\n\n<p>Problem w tym, \u017ce w\u00f3wczas <strong>stracimy mo\u017cliwo\u015b\u0107 pe\u0142nej edycji takiego pliku<\/strong> w programie&nbsp;<em>JavaFX Scene Builder<\/em>. Plik FXML, kt\u00f3ry sk\u0142ada si\u0119 z plik\u00f3w podrz\u0119dnych zostanie wy\u015bwietlony w narz\u0119dziu bez mo\u017cliwo\u015bci edycji zagnie\u017cd\u017conych element\u00f3w. Je\u015bli chcemy edytowa\u0107 zagnie\u017cd\u017cony kawa\u0142ek powinni\u015bmy plik otworzy\u0107 w osobnym oknie programu. <strong>Jest to bardzo du\u017ca wada<\/strong>, kt\u00f3ra mocno utrudnia budowanie bardziej z\u0142o\u017conych ekran\u00f3w i aplikacji.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Wydajno\u015b\u0107 oraz zu\u017cycie pami\u0119ci<\/strong><\/h2>\n\n\n\n<p>Je\u015bli chodzi o kwestie wydajno\u015bciowe, to pami\u0119ta\u0107 nale\u017cy o jednym istotnym elemencie przy budowaniu skomplikowanych ekran\u00f3w. Wczytanie pliku FXML oraz powo\u0142anie do \u017cycia wszystkich obiekt\u00f3w i komponent\u00f3w z nim zwi\u0105zanych, potrafi zaj\u0105\u0107 zauwa\u017caln\u0105 chwil\u0119 (w opracowanej przeze mnie produkcyjnej aplikacji nawet do ok. 1 sek.). Trzeba wzi\u0105\u0107 to pod uwag\u0119 przy projektowaniu przep\u0142ywu ekran\u00f3w. Je\u017celi chcemy pod\u0142\u0105czy\u0107 tworzenie ekranu, tzn. wczytanie pliku FXML, pod zaznaczany komponent&nbsp;<em>CheckBox<\/em>, <strong>op\u00f3\u017anienia we wczytywaniu mog\u0105 by\u0107 irytuj\u0105ce<\/strong> dla u\u017cytkownika.<\/p>\n\n\n\n<p>JavaFX ma spore zapotrzebowanie na pami\u0119\u0107, a niewielkie aplikacje mog\u0105 zajmowa\u0107 ju\u017c sporo pami\u0119ci operacyjnej. Nawet takie funkcje jak prze\u0142\u0105czanie ekran\u00f3w (przy za\u0142o\u017ceniu, \u017ce zbudowane ekrany trzymamy w pami\u0119ci i jedynie zmieniamy \u201edzieci\u201d jednego z paneli g\u0142\u00f3wnych) potrafi znacz\u0105co podbija\u0107 zu\u017cycie pami\u0119ci. Osobom zainteresowanym polecam dog\u0142\u0119bne zapoznanie si\u0119 z wieloma wpisami w sieci na temat&nbsp;<em>Memory leaks in JavaFX<\/em>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Dystrybucja aplikacji w ramach organizacji klienta<\/strong><\/h2>\n\n\n\n<p>Na pewno, pr\u0119dzej czy p\u00f3\u017aniej, <strong>staniecie przed zagadnieniem dystrybucji Waszej aplikacji w organizacji klienta<\/strong>. Mo\u017cna to zrobi\u0107 na dwa sposoby, kt\u00f3re by\u0142y brane przeze mnie pod uwag\u0119. \u017baden z nich nie jest niestety pozbawiony wad.<\/p>\n\n\n\n<p>Pierwszy spos\u00f3b to dystrybucja naszej aplikacji jako <strong>biblioteki uruchamialnej JAR<\/strong>. Tego typu aplikacje s\u0105 rzadko spotykane, poniewa\u017c nasz kod mo\u017ce zosta\u0107 w bardzo \u0142atwy spos\u00f3b rozpakowany, zdekompilowany i u\u017cyty przez kogo\u015b innego. Oczywi\u015bcie, mo\u017cna u\u017cy\u0107 program\u00f3w do zaciemniania kodu aplikacji, ale i tak pozostaj\u0105 pliki FXML, czy inne zasoby, kt\u00f3re musz\u0105 pozosta\u0107 w niezmienionej formie.<\/p>\n\n\n\n<p>Drugi spos\u00f3b to <strong>dystrybucja naszej aplikacji w pliku EXE<\/strong>. Determinuje to od razu rodzin\u0119 system\u00f3w operacyjnych, na kt\u00f3rych aplikacj\u0119 da si\u0119 uruchomi\u0107 \u2013 w tym przypadku to Windows. W moim wdro\u017ceniu sprawdzi\u0142o si\u0119 w\u0142a\u015bnie takie podej\u015bcie.<\/p>\n\n\n\n<p>Wygodnym <strong>narz\u0119dziem do zamiany JAR na EXE<\/strong> jest oprogramowanie&nbsp;<a href=\"http:\/\/launch4j.sourceforge.net\/\" rel=\"nofollow\" ><em>Launch4J<\/em><\/a>. Jest prosty w obs\u0142udze i posiada wszystkie niezb\u0119dne funkcjonalno\u015bci, z kt\u00f3rych bardzo przydatn\u0105 jest mo\u017cliwo\u015b\u0107 zdefiniowania komunikat\u00f3w pokazywanych w zale\u017cno\u015bci od wyst\u0105pienia problem\u00f3w tj. b\u0142\u0119dy uruchomienia, brak wymaganej wersji JRE, b\u0142\u0119dy instalacji itp.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Podsumowanie<\/strong><\/h2>\n\n\n\n<p>Reasumuj\u0105c, JavaFX to technologia, w kt\u00f3rej szybko mo\u017cna stworzy\u0107 \u015brednio skomplikowan\u0105 aplikacj\u0119, ale zalecam jej u\u017cywanie dopiero od wersji JDK 8. Na dzie\u0144 dzisiejszy jest m\u0142od\u0105 technologi\u0105, kt\u00f3ra ma jeszcze kilka istotnych ogranicze\u0144. Mam nadziej\u0119, \u017ce w kolejny wersjach JAVA-y zostanie mocno rozwini\u0119ta i poprawiona. Na pewno chcia\u0142bym jeszcze zbada\u0107 w niej realizacj\u0119 obs\u0142ugi grafiki 3D.<\/p>\n\n\n<div class=\"kk-star-ratings kksr-auto kksr-align-left kksr-valign-bottom\"\n    data-payload='{&quot;align&quot;:&quot;left&quot;,&quot;id&quot;:&quot;2023&quot;,&quot;slug&quot;:&quot;default&quot;,&quot;valign&quot;:&quot;bottom&quot;,&quot;ignore&quot;:&quot;&quot;,&quot;reference&quot;:&quot;auto&quot;,&quot;class&quot;:&quot;&quot;,&quot;count&quot;:&quot;8&quot;,&quot;legendonly&quot;:&quot;&quot;,&quot;readonly&quot;:&quot;&quot;,&quot;score&quot;:&quot;3.7&quot;,&quot;starsonly&quot;:&quot;&quot;,&quot;best&quot;:&quot;5&quot;,&quot;gap&quot;:&quot;11&quot;,&quot;greet&quot;:&quot;&quot;,&quot;legend&quot;:&quot;3.7\\\/5 ( votes: 8)&quot;,&quot;size&quot;:&quot;18&quot;,&quot;title&quot;:&quot;Mocne i s\u0142abe strony JavaFX&quot;,&quot;width&quot;:&quot;101.8&quot;,&quot;_legend&quot;:&quot;{score}\\\/{best} ( {votes}: {count})&quot;,&quot;font_factor&quot;:&quot;1.25&quot;}'>\n            \n<div class=\"kksr-stars\">\n    \n<div class=\"kksr-stars-inactive\">\n            <div class=\"kksr-star\" data-star=\"1\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"2\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"3\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"4\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"5\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n    <\/div>\n    \n<div class=\"kksr-stars-active\" style=\"width: 101.8px;\">\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n    <\/div>\n<\/div>\n                \n\n<div class=\"kksr-legend\" style=\"font-size: 14.4px;\">\n            3.7\/5 ( votes: 8)    <\/div>\n    <\/div>\n","protected":false},"excerpt":{"rendered":"<p>Ponad rok temu stan\u0105\u0142em przed problemem wyboru odpowiedniej technologii dla zbudowania aplikacji desktopowej.&nbsp;Musia\u0142em szybko przygotowa\u0107 sporo ekran\u00f3w, kt\u00f3re by\u0142bym got\u00f3w &hellip; <a class=\"continued-btn\" href=\"https:\/\/sii.pl\/blog\/mocne-i-slabe-strony-javafx\/\">Continued<\/a><\/p>\n","protected":false},"author":89,"featured_media":16538,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_editorskit_title_hidden":false,"_editorskit_reading_time":0,"_editorskit_is_block_options_detached":false,"_editorskit_block_options_position":"{}","inline_featured_image":false,"footnotes":""},"categories":[1314],"tags":[1553,1552,330],"class_list":["post-2023","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-development-na-twardo","tag-fxml","tag-javafx","tag-java"],"acf":[],"aioseo_notices":[],"republish_history":[],"featured_media_url":"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2016\/04\/Jak-zaimplementowac-Unscripted-Testing.png","category_names":["Development na twardo"],"_links":{"self":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/2023"}],"collection":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/users\/89"}],"replies":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/comments?post=2023"}],"version-history":[{"count":3,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/2023\/revisions"}],"predecessor-version":[{"id":18140,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/2023\/revisions\/18140"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/media\/16538"}],"wp:attachment":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/media?parent=2023"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/categories?post=2023"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/tags?post=2023"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}