JavaFX adalah framework open source berbasis java yang digunakan untuk membangun aplikasi
client. JavaFX bisa dibandingkan dengan framework lain semisal Adobe Flex dan Microsoft
Silverlight. Java FX juga bisa mendukung Swing dalam membangun GUI di pemrograman Java.
Library JavaFX tersedia sebagai public Java API. JavaFX mengandung berbagai fitur yang
membuatnya menjadi pilihan dalam membangun banyak aplikasi client antara lain:
- JavaFX ditulis dalam bahasa pemrograman Java, yang mengizinkan kita untuk
menggunakan semua fitur dalam java, misalnya multithreading, generics dan lambda
expression. Kita juga bisa menggunakan berbagai editor java seperti netbeans, untuk
melakukan compile, run, debug, dsb untuk aplikasi JavaFX yang kita buat.
- JavaFX mendukung data binding.
- Kode JavaFX dapat ditulis menggunakan banyak JVM.
- JavaFX menawarkan dua cara dalam membangun user interface (UI): menggunakan kode
Java dan menggunakan FXML.
- JavaFX memberikan banyak dukungan multimedia, seperti memainkan audio dan video.
- JavaFX memungkinkan kita menanamkan konten web di dalam aplikasi.
Kebutuhan sistem
kita memerlukan beberapa software yang terinstal pada komputer kita, yaitu:
- Java Development Kit 8
- NetBeans 8 atau yang lebih baru
Selain menggunakan NetBeans, kita juga bisa menggunakan IDE alternatif lainnya, sebagai
contoh, Eclipse, JDeveloper, IntelliJ IDEA, dsb.
Listing 1- 1
Meng-Override method start()
Jika kita coba meng-compile class HelloFXApp, maka akan menghasilkan pesan error:
HelloFXApp is not abstract and does not override abstract method start(Stage) in Application.
Kesalahan ini berarti bahwa class Application mengandung sebuah method abstract
start(Stage stage), yang belum di-override di dalam class HelloFXApp. Sebagai
developer java, kita mengetahui apa yang selanjutnya harus dilakukan: mendeklarasikan class
HelloFXApp sebagai abstrak atau mengimplementasikan method start(). Di sini yang
diperlukan adalah mengimplementasikan method start(). Listing 1-2 menampilkan perbaikan
kode pada class HelloFXApp.
Listing 1- 2
Dari perbaikan yang dilakukan di atas, ada dua hal yang perlu diperhatikan, yaitu:
1. Kita telah menambahkan statement import class Stage dari package javafx.stage.
2. Kita telah mengimplementasikan method start().
Method start() adalah poin utama dalam aplikasi JavaFX. Method ini dipanggil oleh JavaFX
Application launcher.
Menampilkan Stage
Sama halnya dengan stage (panggung) di dunia nyata, stage di JavaFX digunakan untuk
menampilkan scene. Sebuah scene adalah hal yang tampak – seperti teks, shapes, image,
animasi, efek – yang digunakan pengguna untuk berinteraksi dengan aplikasi.
Di JavaFX, stage utama(primary stage) adalah tempat untuk scene. Stage secara tampilan
berbeda tergantung dari lingkungan kerja(environment) aplikasi kita berjalan. Kita tidak
memerlukan basis action dalam environment, karena JavaFX runtime memberikan semuanya
secara detail untuk kita. Sebagai contoh, jika aplikasi berjalan sebagai aplikasi desktop, maka
stage utamanya adalaha sebuah window dengan title bar dan area untuk menampilkan scene. Jika
aplikasi berjalan sebagai applet di web browser, maka stage utamanya adalah area di dalam
jendela browser.
Stage utama dibuat oleh application launcer yang tidak mempunyai scene. Kita akan membuat
scene untuk stage kita pada kesempatan yang lain.
Kita perlu menampilkan stage untuk melihat visual yang terkandung dalam scene. Gunakan
method show() untuk menampilkan stage. Kita bisa mengatur judul(title) menggunakan
method setTitle(). Perhatikan perubahan kode pada class HelloFXApp pada Listing 1-3.
Listing 1- 3 : Menampilkan Stage utama
Meluncurkan aplikasi
Kita sudah siap untuk menjalankan aplikasi JavaFX pertama kita. Kita bisa menggunakan dua
opsi untuk menjalankannya:
1. JavaFX tidak memerlukan method main() untuk memulai aplikasi. Ketika kita
menjalankan class di Java yang merupakan turunan dari class Application, Java akan
memerintahkan meluncurkan (launch) aplikasi JavaFX jika class yang akan berjalan tidak
mengandung method main().
2. Jika kita menambahkan method main() dalam aplikasi JavaFX, maka kita perlu
memanggil method launch() untuk menjalankan aplikasi. Method launch() akan
melewatkan sebuah array String sebagai parameter ke aplikasi JavaFX.
Jika kita menggunakan opsi pertama, kita tidak perlu menulis banyak kode tambahan untuk class
HelloFXApp. Jika kita menggunakan opsi yang kedua, diperlukan tambahan kode untuk class
HelloFXApp yaitu method main() yang akan ditampilkan pada Listing 1-4.
Method main() memanggil method launch(), yang akan melakukan beberapa pekerjaan setup dan
juga memanggil method start() pada class HelloFXApp. Method start() menentukan title untuk
stage utama dan menampilkan stage. Lihat gambar 1-1.
3. Area utama di window terlihat kosong. Ini adalah area konten di mana stage akan
menampilkan scene. Karena kita belum memiliki scene, maka stage terlihat kosong. Title
bar menampilkan judul yang telah diatur di method start(). Kita bisa menutup
aplikasi menggunakan tombol close di pojok kanan atas, atau menggunakan tombol
Alt+F4.
Sebuah node bisa membuat anak menggunakan method getChildren() yang akan
mengembalikan sebuah ObservableList untuk anak tersebut. Untuk menambahkan child node,
sederhananya menambahkan child node ke dalam ObservableList. Perhatikan potongan kode
di bawah ini untuk menambahkan Text node ke dalam VBox:
//membuat VBox
VBox root = new VBox();
//membuat Text node
Text msg = new Text(“Hello JavaFX”);
//menambahkan text node ke dalam VBox sebagai child node
Root.getChildren().add(msg);
Class Scene mengandung beberapa constructor. Kita akan menggunakan salah satu untuk
menentukan ukuran root node di dalam scene. Statemen di bawah ini membuat scene dengan
VBox sebagai root node, dengan ketentuan lebar 300px dan tinggi 50px:
//membuat scene
Scene scene = new Scene(root, 300, 50);
Kita juga perlu menentukan scene ke dalam stage dengan memanggil method setScene() pada
class Stage:
Stage.setScene(scene);
Perhatikan Listing 1-5 untuk kode program yang lengkap, dan hasilnya pada Gambar 1-2.
Listing 1- 5
Gambar 1- 2
Ketika tombol tersebut di-klik, akan menuju ke sebuah EctionEvent. Kita bisa menambahkan
ActionEvent handler untuk menangani event tersebut. Gunakan method setOnAction()
untuk mengatur ActionEvent handler dari tombol. Statement berikut ini menangani
ActionEvent handler untuk button. Handler ini akan menutup aplikasi. Kita dapat menggunakan
pernyataan lambda atau class yang tidak dikenal untuk mengatur ActionEvent handler.
Perhatikan potongan kode di bawah ini:
//menggunakan ekspresi lambda
exitBtn.setOnAction(e -> Platform.exit());
//menggunakan class anonymous(tidak dikenal)
Import javafx.event.ActionEvent;
Import javafx.event.EventHandler;
...
exitBtn.setOnAction(new EventHandler<ActionEvent>(){
@Override
Public void handle(ActionEvent e){
Platform.exit;
}
});
Program dalam Listing 1-6 menampilkan bagaimana menambah node ke dalam scene. Progam
menggunakan method setStyle() pada class Label untuk mengatur warna menjadi biru. Saya
akan mendiskusikan penggunaan CSS ke dalam JavaFX pada kesempatan lain.
Listing 1- 6: Berinteraksi dengan pengguna di Aplikasi JavaFX
Gambar 1- 3: Aplikasi JavaFX yang menampilkan control ke dalam scene
Sebuah parameter bisa bernama ataupun tidak bernama. Parameter bernama terdiri dari (nama,
nilai). Parameter tak bernama terdiri dari nilai tunggal. Method getNamed() mengembalikan
Map<String, String> yang mengandung sepasang nilai-kunci dari parameter nama. Method
getUnnamed() mengembalikan List<String>, di mana setiap elemen adalah nilai dari
parameter tak bernama.
Kita hanya melewatkan parameter bernama dan tak bernama saja untuk aplikasi JavaFX. Jangan
melewatkan parameter bertipe raw. JavaFX runtime membuat semua parameter, bernama dan tak
bernama, yang dilewatkan ke dalam aplikasi sebagai List<String> di luar method getRaw()
pada class Parameters.
Method getParameters() pada class Application mengembalikan referensi ke class
Application.Parameters. referensi untuk class Parameters tersebut terdapat di dalam
method init() pada class Application dan kode yang dieksekusi setelah itu. Parameter
tersebut tidak terdapat di dalam constructor pada aplikasi yang dipanggil sebelum method
init(). Pemanggilan method getParameters() di dalam constructor akan mengembalikan
nilai null.
Program pada Listing 1-7 membaca semua tipe melewatkan parameter ke dalam aplikasi dan
menampilkannya ke dalam TextArea. TextArea adalah node yang menampilkan teks dengan
banyak baris.
Listing 1- 7
Sesuai dengan konvensi, nama dari method getter dan setter disusun oleh nama properti, dengan
huruf pertama besar, setelah kata get dan set.method getter tidak mempunyai suatu parameter, dan
mengembalikan tipe data yang sama dengan tipe dari field. Method setter memiliki parameter yang
bertipe data sama dengan tipe data field, dan tipe kembaliannya adalah void.
Perhatikan potongan kode untuk memanipulasi properti name dari sebuah bean Person:
X = y + z;
Pernyataan di atas mendefinisikan sebuah binding antara x, y, dan z. Ketika dieksekusi, nilai x
adalah sama dengan jumlah y dan z. Binding juga mempunyai faktor waktu. Dari pernyataan di
atas, nilai dari x dibatasi oleh jumlah y dan z dan bernilai valid waktu pernyataan tersebut
dieksekusi. Nilai dari x bukanlah jumlah dari y dan z sebelum dan sesudah pernyataan tersebut
dieksekusi.
Terkadang diperlukan sebuah binding untuk menangani lebih dari satu periode. Perhatikan
pernyataan di bawah ini yang mendefinisikan binding menggunakan harga, diskon, dan pajak:
Dari kasus ini, kita ingin menjaga binding tetap valid, sehingga harga jual terhitung dengan benar,
bila mana harga, diskon atau pajak diubah.
Dari binding di atas, harga, diskon, dan pajak saling tergantung satu sama lain (dependencies), dan
bisa dikatakan bahwa hargaJual terikat dengan harga, diskon, dan pajak.
Agar binding bekerja dengan benar, maka perlu bahwa binding diberi tahu setiap dependensinya
berubah. Bahasa pemrograman yang mendukung binding memberikan mekanisme untuk
meregistrasi listener ke dependensi. Sehingga ketika dependensi menjadi salah atau berubah,
semua listener akan memberi tahu. Sebuah binding bisa menyinkronkan dirinya sendiri dengan
dependensinya ketika menerima pemberitahuan.
Sebuah binding bisa termasuk ke dalam eager binding atau lazy binding. Pada eager binding,
variabel yang terikat menghitung ulang segera setelah ada perubahan dependensinya. Pada lazy
binding, variabel yang terikat tidak menghitung ulang setelah ada perubahan dependensinya.
Perhitungan ulangnya akan dibaca di lain waktu. Lazy binding bekerja lebih baik dibandingkan
eager binding.
Sebuah binding bisa termasuk kedalam unidirectional atau bidirectional. Binding unidirectional
hanya bekerja di satu arah; perubahan pada dependensinya disebarkan ke variabel terikat.
Bidirectional binding bekerja pada dua arah. Dimana antara variabel terikat dan dependensinya
menjaga nilainya tetap tersinkronisasi satu dengan lainnya. Cirinya adalah, bidirectional binding
hanya didefinisikan antara dua variabel, contohnya; x = y dan y = x, dimana nilai x dan y selalu
sama.
Secara matematika, tidak mungkin mendefinisikan sebuah bidirectional binding dengan banyak
variabel unik. Pada contoh di atas, ikatan pada harga jual termasuk dalam unidirectional binding.
Jika kita ingin membuatnya menjadi bidirectional binding, tidak memungkinkan untuk
menghitung nilai dari daftar harga, diskon, dan pajak ketika harga jual diubah.
Aplikasi GUI memberi penggunak dengan UI widget, sebagai contoh, text field, check box, dan
button untuk manipulasi data. Data yang ditampilkan di UI widget bisa disinkronkan berdasarkan
model data. Di sini, bidirectional binding diperlukan agar UI dan model data bisa sinkron.
Kedua properti dari bean Karyawan bersifat read/write. Properti gaji merupakan properti ikatan
(bound). Di mana setter akan menghasilkan pemberitahuan perubahan properti ketika properti
gaji diubah.
Listener bisa didaftarkan atau dikeluarkan dari daftar sebagai pemberitahuan perubahan
menggunakan method addPropertyChangeListener() dan
removePropertyChangeListener(). Kelas PropertyChangeSupport adalah bagian dari
JavaBean API yang memfasilitasi pendaftaran dan penghapusan properti change listener serta
menembakkan properti change notification (notifikasi perubahan).
Tiap pihak yang berkepentingan dalam sinkronisasi nilai berdasarkan perubahan gaji perlu
mendaftar dengan bean Karyawan dan perlu melakukan tindakan ketika diberitahukan tentang
perubahannya.
Listing 2-2 menampilkan bagaimana mendaftar untuk memberitahukan perubahan gaji pada bean
Karyawan. Hasil keluaran(output) akan menampilkan pemberitahuan perubahan gaji sebanyak
dua kali, padahal method setSalary() dipanggil sebanyak tiga kali. Hal ini dikarenakan pada
pemanggilan method setSalary() yang kedua, nilai gaji sama dengan pada pemanggilan yang
pertama dan kelas PropertyChangeSupport cukup cerdas mendeteksi hal ini. Contoh tersebut
juga menampilkan bagaimana kita akan mengikat(bound) variabel menggunakan JavaBeans API.
Pajak seorang karyawan dihitung berdasarkan persentase pajak. Pada JavaBeans API,
pemberitahuan perubahan properti digunakan untuk mengikat variabel.
Listing 2- 2 kelas DemoKaryawan yang mengetes bean Karyawan pada perubahan gaji
Properti memberikan dua pasang method getter dan setter: get()/set() and getValue()/
setValue(). Method get()dan set() untuk mendapatkan (get) dan menetapkan (set) nilai
pada properti. Untuk properti primitif, maka bekerja dengan nilai bertipe primitif juga. Sebagai
contoh, pada IntegerProperty, tipe yang dikembalikan pada method get() dan tipe
parameter pada method set() adalah int. Method getValue() and setValue() bekerja
dengan tipe objek/referensi. Contohnya, tipe kembalian dan tipe parameter adalah Integer pada
IntegerProperty.
counter.set(2);
counterValue = counter.get();
System.out.println("Counter:" + counterValue);
Counter:1
Counter:2
Bekerja dengan properti read-only sedikit lebih rumit. Sebuah kelas ReadOnlyXXXWrapper
memiliki dua properti dengan tipe XXX: yang satu read-only dan satunya lagi read/write. Kedua
properti tersebut tersinkronisasi. Di mana method-nya getReadOnlyProperty()
mengembalikan sebuah objek ReadOnlyXXXProperty.
Perhatikan potongan kode di bawah ini yang menampilkan cara membuat properti Integer
read-only. Properti idWrapper adalah read/write, sedangkan properti id adalah read-only.
Ketika nilai dari properti idWrapper diubah, maka nilai pada id juga berubah otomatis.
ReadOnlyIntegerWrapper idWrapper = new ReadOnlyIntegerWrapper(100);
ReadOnlyIntegerProperty id = idWrapper.getReadOnlyProperty();
System.out.println("idWrapper:" + idWrapper.get());
System.out.println("id:" + id.get());
System.out.println("idWrapper:" + idWrapper.get());
System.out.println("id:" + id.get());
idWrapper:100
id:100
idWrapper:101
id:101