Cara mendesain komponen JavaFX menggunakan CSS lama yang baik.
Semua posting di seri JavaFX:
- Tutorial JavaFX: Memulai
- Tutorial JavaFX: Halo dunia!
- Tutorial JavaFX: FXML dan SceneBuilder
- Tutorial JavaFX: Tata Letak Dasar
- Tutorial JavaFX: Tata Letak Lanjutan
- JavaFX Tutorial: styling CSS
- JavaFX Weaver: Mengintegrasikan Aplikasi JavaFX dan Spring Boot
Pemisahan elemen visual
Dalam
artikel sebelumnya
tentang FXML, kami mempelajari bagaimana JavaFX memberikan pemisahan tugas yang jelas dengan membagi kode UI menjadi dua. Komponen dan propertinya dideklarasikan dalam file FXML, dan logika interaksi jelas dialokasikan ke controller.
Selain itu, ada bagian ketiga, bahasa FXML, yang hanya mengontrol komponen aplikasi Anda, sifat-sifatnya dan bagaimana mereka tertanam satu sama lain. Itu tidak mendefinisikan elemen visual dari suatu komponen, yaitu: font, warna, latar belakang, indentasi. Secara umum, Anda dapat mencapai ini di FXML, tetapi Anda seharusnya tidak melakukannya. Alih-alih, elemen visual harus didefinisikan secara jelas dalam style sheet CSS.
Dengan demikian, desain Anda menjadi independen dan dapat dengan mudah diganti atau diubah tanpa mempengaruhi sisa aplikasi. Anda bahkan dapat dengan mudah mengimplementasikan beberapa tema yang dapat diaktifkan sesuai permintaan pengguna.
CSS
Anda mungkin akrab dengan CSS (Cascading Style Sheets) yang digunakan untuk mendesain halaman HTML di web. Pendekatan serupa diterapkan di JavaFX, meskipun JavaFX menggunakan serangkaian properti khusus sendiri.
Mari kita lihat sebuah contoh:
.button { -fx-font-size: 15px; }
Dua konsep utama digunakan di sini. Yang pertama adalah pemilih
.tombol . Ini menentukan komponen yang gaya harus diterapkan. Dalam contoh ini, gaya diterapkan ke semua tombol.
Bagian kedua adalah sifat sebenarnya dari gaya, yang akan diterapkan ke semua komponen yang cocok dengan pemilih kami. Properti adalah segalanya di dalam kurung kurawal.
Setiap properti memiliki makna tertentu. Dalam contoh kita, ada properti
-fx-font-size , yang menentukan seberapa besar teks tersebut. Dalam contoh, nilainya
15px , tetapi nilai ini bisa berupa yang lain.
Untuk meringkas - kami membuat aturan yang menyatakan bahwa semua tombol di mana saja harus memiliki teks 15 piksel.
Penyeleksi
Sekarang mari kita lihat lebih dekat bagaimana penyeleksi bekerja di JavaFX. Ini terjadi hampir sama dengan di CSS biasa.
Kelas
Kelas dalam CSS mewakili beberapa elemen serupa. Misalnya, tombol atau kotak centang. Selektor, yang harus diterapkan ke semua elemen dari kelas yang sama, dimulai dengan titik ".", Diikuti segera dengan nama kelas. Konvensi penamaan kelas adalah untuk memisahkan setiap kata dengan karakter "-". Pemilih berikut ini berlaku untuk semua elemen dengan kelas
label .
.label { // Some properties }
Kelas bawaan
Berita baiknya adalah semua komponen bawaan JavaFX (seperti Label atau Tombol) sudah memiliki kelas yang telah ditentukan. Jika Anda ingin menyesuaikan gaya semua label dalam aplikasi Anda, Anda tidak perlu menambahkan kelas khusus untuk setiap label Anda. Setiap label memiliki kelas
label secara default.
Sangat mudah untuk menentukan nama kelas dari komponen:
- Ambil nama kelas komponen Java - misalnya. Label
- Buat nama huruf kecil
- Jika terdiri dari beberapa kata, pisahkan dengan simbol "-"
Beberapa contoh:
- Label → Label
- Kotak centang → kotak centang
Saat menggunakan kelas seperti penyeleksi, pastikan untuk menambahkan "." Ini berarti bahwa pemilih untuk kelas
label adalah
.label .
Kelas khusus
Jika kelas bawaan tidak cukup, Anda bisa menambahkan kelas Anda sendiri ke komponen Anda. Anda dapat menggunakan beberapa kelas yang dipisahkan oleh koma:
<Label styleClass="my-label,other-class">I am a simple label</Label>
Atau di Jawa:
Label label = new Label("I am a simple label"); label.getStyleClass().addAll("my-label", "other-class");
Menambahkan kelas dengan cara ini tidak menghapus kelas komponen secara default (dalam hal ini,
label ).
Ada satu kelas khusus yang disebut
root . Ini adalah komponen root dari adegan Anda. Anda dapat menggunakannya untuk menata segala sesuatu di dalam adegan Anda (misalnya, mengatur font global). Ini mirip dengan menggunakan pemilih tag tubuh dalam HTML.
ID
Cara lain untuk memilih komponen dalam CSS adalah dengan menggunakan pengenal komponen (ID). Ini adalah pengidentifikasi unik untuk komponen. Tidak seperti kelas yang dapat ditugaskan ke beberapa komponen, pengidentifikasi harus unik di tempat kejadian.
Sedangkan simbol "." Digunakan untuk menunjukkan kelas. di depan nama di pemilihnya, pengidentifikasi ditandai dengan simbol "#".
#my-component { ... }
Di FXML, Anda dapat menggunakan
fx: id untuk mengatur pengenal CSS suatu komponen.
<Label fx:id="foo">I am a simple label</Label>
Namun, ada satu peringatan.
Identifier yang sama
digunakan untuk merujuk ke objek komponen yang dideklarasikan di controller Anda dengan nama yang sama. Karena pengidentifikasi dan nama bidang dalam pengontrol harus cocok,
fx: id harus memperhitungkan pembatasan penamaan Java untuk nama bidang. Meskipun konvensi penamaan CSS mendefinisikan kata individual yang dipisahkan oleh karakter "-", ini adalah karakter yang tidak valid untuk nama bidang Java. Karenanya, untuk
fx: id dengan beberapa kata, Anda perlu menggunakan konvensi penamaan yang berbeda seperti CamelCase, atau menggunakan garis bawah.
<Label fx:id="my-label">I am a simple label</Label> <Label fx:id="my_label">I am a simple label</Label> <Label fx:id="MyLabel">I am a simple label</Label>
Di Java, Anda bisa memanggil metode
setId () dari komponen Anda.
Label label = new Label("I am a simple label"); label.setId("foo");
Properti
Meskipun CSS yang digunakan dalam JavaFX sangat mirip dengan CSS web asli, ada satu perbedaan besar. Nama properti berbeda, dan ada banyak properti khusus JavaFX baru. Mereka memiliki awalan
-fx- .
Berikut ini beberapa contohnya:
- -fx-background-color : Warna latar belakang
- -fx-text-fill : Warna teks
- -fx-font-size : Ukuran teks
Anda dapat menemukan daftar semua properti di
panduan desain resmi .
Kelas semu
Selain kelas yang biasa menandai komponen tertentu, ada yang disebut kelas semu yang menunjukkan keadaan komponen. Ini bisa berupa, misalnya, kelas untuk menandai bahwa komponen memiliki fokus atau kursor mouse ada di sana.
Ada banyak kelas pseudo bawaan. Mari kita lihat tombolnya. Ada beberapa pseudo-class yang dapat Anda gunakan, misalnya:
- hover : tombol mouse di atas
- terfokus : tombol memiliki fokus
- dinonaktifkan : tombol dinonaktifkan
- ditekan : tombol ditekan
Kelas pseudo dimulai dengan karakter ":" (misalnya
:: hover ) di pemilih CSS. Tentu saja, Anda perlu menentukan komponen milik pseudo-class Anda - misalnya,
tombol: hover . Contoh berikut menunjukkan pemilih yang berlaku untuk semua tombol yang memiliki fokus:
.button:focused { -fx-background-color: red; }
Tidak seperti CSS, yang hanya memiliki pseudo-class dasar untuk status seperti
fokus dan
melayang , JavaFX memiliki kelas pseudo-spesifik-komponen yang berhubungan dengan status atau properti komponen yang berbeda.
Sebagai contoh:
- Scrollbar memiliki kelas pseudo horizontal dan vertikal
- Elemen (Sel) memiliki kelas pseudo yang aneh dan genap
- TitledPane telah memperluas dan menciutkan kelas semu.
Kelas Kustom Pseudo
Selain kelas pseudo bawaan, Anda dapat mendefinisikan dan menggunakan kelas pseudo Anda sendiri.
Mari kita buat label kita sendiri (mewarisi dari kelas Label). Ini akan memiliki properti logis baru yang disebut
shiny . Dalam hal ini, kami ingin label kami memiliki pseudo-
class yang mengkilap .
Karena tag memiliki pseudo-
class mengkilap , kita dapat mengatur latar belakang tag
emas :
.shiny-label:shiny { -fx-background-color: gold; }
Sekarang buat kelas itu sendiri.
public class ShinyLabel extends Label { private BooleanProperty shiny; public ShinyLabel() { getStyleClass().add("shiny-label"); shiny = new SimpleBooleanProperty(false); shiny.addListener(e -> { pseudoClassStateChanged(PseudoClass.getPseudoClass("shiny"), shiny.get()); }); } public boolean isShiny() { return shiny.get(); } public void setShiny(boolean shiny) { this.shiny.set(shiny); } }
Ada beberapa bagian penting di sini:
- Kami memiliki properti boolean BooleanProperty bukan boolean biasa. Ini berarti bahwa objek yang mengkilap dapat diamati, dan kita dapat melacak (mendengarkan) perubahan nilainya.
- Kami mendaftarkan pendengar yang akan dipanggil setiap kali nilai objek mengkilap berubah menggunakan shiny.addListener () .
- Ketika nilai shiny berubah, kita menambah / menghapus pseudo- class shiny tergantung pada nilai pseudoClassStateChanged saat ini (PseudoClass.getPseudoClass ("shiny"), shiny.get ()) .
- Kami menambahkan kelas khusus untuk semua label label mengkilap , alih-alih hanya memiliki kelas label yang diwarisi dari induknya. Dengan demikian, kami hanya dapat memilih tag mengkilap .
Lembar Gaya Default
Bahkan jika Anda sendiri tidak menyediakan gaya apa pun, setiap aplikasi JavaFX sudah memiliki beberapa gaya visual. Ada stylesheet default yang berlaku untuk setiap aplikasi. Ini disebut
modena (sejak JavaFX 8, sebelumnya disebut
caspian ).
Lembar gaya ini dapat ditemukan dalam file:
jfxrt.jar \ com \ sun \ javafx \ scene \ control \ skin \ modena \ modena.cssAtau Anda dapat menemukan file di
sini . Dalam direktori yang sama ada banyak gambar yang digunakan oleh stylesheet.
Lembar gaya ini memberikan gaya standar, tetapi memiliki prioritas terendah dibandingkan jenis lembar gaya lainnya, sehingga Anda dapat dengan mudah menimpanya.
Lembar gaya adegan
Selain stylesheet default yang disebutkan di atas, Anda tentu saja dapat menyediakan sendiri. Level tertinggi di mana Anda dapat menerapkan gaya adalah seluruh adegan. Anda dapat menerapkan ini di FXML Anda:
<BorderPane xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml" stylesheets="styles.css" ... > ... </BorderPane>
Atau dalam kode Java Anda:
String stylesheet = getClass().getResource("/styles.css").toExternalForm(); scene.getStylesheets().add(stylesheet);
Perhatikan panggilan
keExternalForm () . Scene berharap mendapatkan konten stylesheet sebagai string, bukan file, jadi kami harus menyediakan konten stylesheet kami sebagai string.
Lembar gaya orang tua
Selain stylesheet untuk seluruh adegan, terkadang berguna untuk memiliki gaya di tingkat tata letak. Yaitu - untuk wadah terpisah, seperti VBox, HBox atau GridPane. Induk umum semua tata letak adalah kelas induk, yang mendefinisikan metode untuk memproses lembar gaya pada tingkat tata letak. Gaya ini hanya berlaku untuk komponen dalam tata letak ini, dan tidak untuk seluruh adegan. Gaya di tingkat tata letak lebih diutamakan daripada gaya di tingkat adegan.
<HBox stylesheets="styles.css"> ... </HBox>
Di Jawa, Anda perlu memuat konten stylesheet sendiri, seperti sebelumnya untuk adegan:
HBox box = new HBox(); String stylesheet = getClass().getResource("/styles.css").toExternalForm(); box.getStylesheets().add(stylesheet);
Gaya sebaris
Sejauh ini, kami hanya melihat kasus-kasus di mana style sheet eksternal telah ditetapkan untuk seluruh adegan atau tata letak. Tetapi Anda dapat mengatur properti gaya individu di tingkat komponen.
Di sini Anda tidak perlu khawatir tentang pemilih, karena semua properti diatur untuk komponen tertentu.
Anda dapat menentukan beberapa properti yang dipisahkan oleh titik koma:
<Label style="-fx-background-color: blue; -fx-text-fill: white"> I'm feeling blue. </Label>
Di Jawa, Anda bisa menggunakan metode
setStyle () :
Label label = new Label("I'm feeling blue."); label.setStyle("-fx-background-color: blue; -fx-text-fill: white");
Gaya pada tingkat komponen lebih diutamakan daripada gaya pemandangan serta gaya induk di tingkat tata letak.
Mengapa Anda harus menghindarinya?
Penataan tingkat komponen bisa nyaman, tetapi ini adalah solusi cepat dan kotor. Anda mengabaikan keunggulan utama CSS, yaitu pemisahan gaya dari komponen. Sekarang Anda secara kaku mengikat elemen visual Anda langsung ke komponen. Anda tidak lagi dapat dengan mudah mengganti lembar gaya jika diperlukan, Anda tidak dapat mengubah tema.
Selain itu, Anda tidak lagi memiliki satu tempat pusat di mana gaya Anda ditentukan. Ketika Anda perlu mengubah sesuatu dalam satu set komponen yang serupa, Anda perlu mengubah masing-masing komponen secara terpisah, dan tidak hanya mengedit satu tempat di style sheet eksternal. Oleh karena itu, gaya komponen inline harus dihindari.
Prioritas stylesheet
Anda dapat memberikan gaya pada beberapa level - scene, parent, style inline, dan ada juga stylesheet modem default. Jika Anda mengubah properti yang sama dari komponen yang sama di beberapa level, JavaFX memiliki pengaturan prioritas yang menentukan gaya mana yang harus digunakan. Daftar prioritas - dari yang tertinggi ke yang terendah:
- Gaya sebaris
- Gaya induk
- Gaya adegan
- Gaya bawaan
Ini berarti bahwa jika Anda mengatur warna latar belakang label tertentu pada level inline dan scene, JavaFX akan menggunakan nilai yang ditetapkan dalam gaya inline karena memiliki prioritas yang lebih tinggi.
Bacaan tambahan
JavaFX memiliki banyak properti CSS, dan uraiannya berada di luar cakupan posting ini, untuk daftar terperinci, lihat
panduan referensi CSS resmi untuk JavaFX .