Wprawki w JavaFX

post_img

Rośnie popularność aplikacji RIA. Powstaje coraz więcej narzędzi i języków do tworzenia takich aplikacji. W tym artykule postaram się przedstawić podstawy JavaFX – języka skryptowego ze stajni SUNa.

JavaFX na początku zniechęcała mnie od siebie reklamując się jako język skryptowy – miałem zbyt dużo złych skojarzeń z Javasciptem, a konkretnie z brakiem statycznego typowania argumentów. Jednak już po lekturze paru artykułów i pierwszej prostej aplikacji okazuje się, że nie jest tak źle – powiedziałbym nawet, że jest całkiem nieźle.

Jako narzędzie do developmentu wybrałem NetBeans IDE for JavaFX – wtyczka do eclipse jest również dostępna, jednak dopiero dla wersji 3.5.

Przejdźmy do konkretów. Stwórzmy prosty kalkulator by poznać semantykę języka. Uruchamiamy NetBeans, i wybieramy New Project

Z kategorii wybieramy JavaFX, klikamy next

Uzupełniamy nazwę projektu, zaznaczamy „Empty Project”, „Set as Main Project” oraz odznaczamy „Create Main File”. Klikamy Finish – NetBeans wygeneruje dla nas projekt kalkulatora.

Po utworzeniu projektu dodajemy naszą klasę „Calculator”. Klikamy prawym na projekcie, wybieramy „New” -> „Empty JavaFX File” i uzupełniamy nazwę klasy. Opcjonalnie można uzupełnić nazwę pakietu, ale w tym przykładzie nie jest to konieczne. Następnie uzupełniamy ciało klasy – aby było to bardziej czytelne. pozwolę sobie nieco skrócić opis. Cały projekt można pobrać tutaj

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.TextBox;
import javafx.scene.control.Button;
import javafx.scene.input.MouseEvent;

var currResult:Number = 0;
var firstElem:Number;
var secondElem:Number;
var funcToRun:function();
var funcDefined = false;

Stage {
    title: "JavaFX quick calculator!"
    scene: Scene {
        width: 130
        height: 150
        content: [
             ......
        ] //Content
    } //Scene
}

Pierwsze co rzuca się w oczy to

1
import

, który znany jest wszystkim programistom Javy i nie tylko. Okazuje się, że JavaFX mimo że jest językiem skryptowym jest kompilowana do bytecode maszyny wirtualnej i tam uruchamiana. Dalej mamy definicje zmiennych, gdzie obserwujemy ciekawą właściwość JavyFX, a mianowicie możliwość (ale nie konieczność!) określenia typu danych jakie reprezentuje dana zmienna. Kompilator sam domyślnie jest w stanie nadać typ na podstawie pierwszej przypisanej zmiennej. A zatem obie konstrukcje –

1
2
var funcDefined = true;
var funcDefined:Boolean = true;

– są jak najbardziej poprawne i akceptowane przez kompilator. JavaFX udostępnia sporo wbudowanych typów danych jednak na potrzeby kalkulatora wystarczy nam Boolean, Number (liczby zmiennoprzecinkowe) i function(). Function() nie jest w ścisłym znaczeniu typem danych, ale pozwala zdefiniować zmienną, której użyjemy w dość ciekawy sposób później.

Stage definiuje nam nasze „okno robocze”, czyli obszar w którym będziemy dodawać i wyświetlać nasze komponenty. Scena to element właściwy w którym pojawia się zawartość.

Struktura elementów w JavaFX nieodzownie kojarzy się mi z DOM – chodzi o rozrastające się ku dołowi drzewo. W każdym elemencie możemy definiować kolejne elementy coraz bardziej rozgałęziając drzewo. Dodajmy parę gałęzi do sceny – niech to będzie pole tekstowe, w którym będą pojawiać się wyniki oraz przyciski funkcyjne kalkulatora.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
var currResult:Number = 0;
var firstElem:Number;
var secondElem:Number;
var funcToRun:function();
var funcDefined = false;

Stage {
    title: "JavaFX quick calculator!"
    scene: Scene {
        width: 130
        height: 150
        content: [
            TextBox{
                layoutX:2;
                layoutY:2;
                height:20;
                width:120;
                text: bind currResult.toString();
         editable:false;
            },
         …
            Button{
                layoutX:2;
                layoutY:75;
                text:"+";
                width:55;
                height:20;
                onMouseClicked:function (e:MouseEvent){
                       if(funcDefined){
                          funcToRun();
                       }
                       funcToRun=function(){
                          currResult=firstElem+secondElem;
                          firstElem=currResult;
                          secondElem = 0;
                       }
                       funcDefined = true;

                }
            },  //... kolejne przyciski dla -, *, /, =
        ] //Content
    } //Scene
}

Każdy element jak widać jest dość mocno zbliżony do siebie w definicji – posiada koordynaty położenia, dane dotyczące wymiaru i tekst jaki ma się pojawiać.
Warte zauważenia jest słówko

1
bind

– określna ono wiązanie pomiędzy naszą zmienną currResult a polem tekstowym TextBox. Wykorzystanie bind
pozwala nam nie martwić się o aktualizowanie pola tekstowego gdy zmieni się wynik przechowywany w zmiennej currResult – bind
sprawia, że zmiana currResult jest automatycznie propagowana do elementu

1
text

TextBoxa. Drugą istotną rzeczą jest element

1
onMousceClicked

JavaFX pozwala definiować funkcje listenerów na dane zdarzenia (tu kliknięcie myszką na przycisk) w prosty sposób. W naszym przykładzie nadpisujemy zdefiniowaną wcześniej zmienną:

1
funcToRun

przez podanie nowego ciała metody. Zostaje dodać nam przyciski cyfr, przycisk CE i „=”, by kalkulator mógł zacząć działać

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
var currResult:Number = 0;
var firstElem:Number;
var secondElem:Number;
var funcToRun:function();
var funcDefined = true;

Stage {
    title: "JavaFX quick calculator!"
    scene: Scene {
        width: 130
        height: 150
        content: [
            TextBox{
                layoutX:2;
                layoutY:2;
                height:20;
                width:120;
                text: bind currResult.toString();
         editable:false;
            },
            Button{
                layoutX:2;
                layoutY:25;
                text:"1";
                width:20;
                height:20;
                onMouseClicked:function (e:MouseEvent){
                        if(not funcDefined){
                           firstElem=firstElem*10+1;
                           currResult=firstElem;
                        }else{
                           secondElem=secondElem*10+1;
                        }
                }
            },//... kolejne przyciski dla pozostałych cyfr
            Button{
                layoutX:2;
                layoutY:75;
                text:"+";
                width:55;
                height:20;
                onMouseClicked:function (e:MouseEvent){
                       if(funcDefined){
                          funcToRun();
                       }
                       funcToRun=function(){
                          currResult=firstElem+secondElem;
                          firstElem=currResult;
                          secondElem = 0;
                       }
                       funcDefined = true;

                }
},  //... kolejne przyciski dla -, *, /
Button{
                layoutX:2;
                layoutY:125;
                text:"CE";
                width:55;
                height:20;
                onMouseClicked:function (e:MouseEvent){
                       funcToRun=function(){}
                       funcDefined = false;
                       currResult = 0;
                       firstElem = 0;
                       secondElem = 0;
                }
            },
            Button{
                layoutX:67;
                layoutY:125;
                text:"=";
                width:55;
                height:20;
                onMouseClicked:function (e:MouseEvent){
                       if(funcDefined){
                          funcToRun();
                       }
                       funcToRun=function(){}
                       funcDefined = false;
                       firstElem = 0;
                       secondElem = 0;
                }
            }
        ] //Content
    } //Scene
}

Jak widać struktura przycisków z cyframi niczym nie różni się od przycisków funkcyjnych. W ramach eventu onMouseClicked ustawiamy parametry i ewentualnie wywołujemy funkcję zdefiniowaną w przycisku funkcyjnym. I to już cały kod – wystarczy uruchomić projekt klikając F6 w IDE. W efekcie dostajemy okienko w którym możemy przetestować nasz kalkulator

To tyle jeżeli chodzi o pierwsze wprawki w JavaFX.

Podsumowując – czego dziś dowiedziałem się o JavaFX?
• Jest językiem skryptowym który umożliwia, ale nie wymusza określanie typu zmiennych
• Struktura budowanego widoku opiera się na drzewie
• Najważniejsze elementy tego drzewa to Stage i Scene
• Pozwala tworzyć wiązania między zmiennymi a elementami GUI
• Umożliwia proste zarządzanie zdarzeniami (zwane eventami)
Język rozwija się dynamicznie – kolejne jego wersje wzbogacane są nie tylko o nowe komponenty lecz także o konstrukcje składniowe języka, a wszystko po to, by maksymalnie uprościć pisanie aplikacji z efektownym GUI.
Biorąc pod uwagę możliwość uruchamiania aplikacji JavaFX zarówno jako aplikacji desktopowych, serwerowych oraz mobilnych wróżę temu językowi dość jasną przyszłość.

Pozostaje zgłębiać dostępne klasy i mechanizmy, a gdy uda mi się stworzyć prostą aplikację web i uruchomić ją na serwerze nie omieszkam podzielić się tym doświadczeniem

Materiały dodatkowe:


Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *

2 komentarzy do “Wprawki w JavaFX

  • Aras

    Dobry przykład na początek.
    Technologia mało popularna, ale zapowiada się ciekawie. Mam nadzieję że Oracle jejj nie porzuci, bo zamierzam się w nia wdrozyć.

  • Adam Andrzejewski Autor wpisu

    Należy mieć na uwadze, że w czasie tworzenia tego przykadu JavaFX była w wersji 1.2.1. Obecnie jest już 1.3 i nowsza wersja NetBeans, więc sam proces może wyglądać ciut inaczej. Sam program najprawdopodobniej też nie zadziała bez przekompilowania i być może jakiegoś refaktoringu na JavaFX1.3 – nie ma tu kompatybilności wstecz niestety…