كيفية تصميم مكونات JavaFX باستخدام CSS القديم الجيد.
جميع المشاركات في سلسلة JavaFX:
- JavaFX البرنامج التعليمي: الشروع في العمل
- JavaFX البرنامج التعليمي: مرحبا العالم!
- JavaFX البرنامج التعليمي: FXML و SceneBuilder
- JavaFX البرنامج التعليمي: تخطيطات الأساسية
- JavaFX تعليمي: تخطيطات متقدمة
- JavaFX البرنامج التعليمي: CSS التصميم
- JavaFX Weaver: دمج تطبيقات JavaFX و Spring التمهيد
فصل العناصر البصرية
في
مقال سابق
حول FXML ، تعلمنا كيف توفر JavaFX فصلًا واضحًا للمهام عن طريق تقسيم كود واجهة المستخدم إلى قسمين. يتم الإعلان عن المكونات وخصائصها في ملف FXML ، ويتم تخصيص منطق التفاعل بوضوح إلى وحدة التحكم.
بالإضافة إلى ذلك ، هناك جزء ثالث ، لغة FXML ، التي تتحكم فقط في مكونات التطبيق الخاص بك ، وخصائصها وكيفية دمجها في بعضها البعض. لا تحدد العناصر المرئية للمكون ، وهي: الخطوط والألوان والخلفيات والمسافات البادئة. بشكل عام ، يمكنك تحقيق ذلك في FXML ، لكن لا ينبغي عليك ذلك. بدلاً من ذلك ، يجب تعريف العناصر المرئية بوضوح في أوراق أنماط CSS.
وبالتالي ، يصبح التصميم الخاص بك مستقلًا ويمكن استبداله أو تغييره بسهولة دون التأثير على بقية التطبيق. يمكنك ببساطة تنفيذ العديد من السمات التي يمكن تبديلها بناءً على طلب المستخدم.
CSS
من المحتمل أن تكون معتادًا على CSS (أوراق الأنماط المتتالية) المستخدمة لتصميم صفحات HTML على الويب. يتم تطبيق نهج مماثل في JavaFX ، على الرغم من أن JavaFX يستخدم مجموعة من الخصائص المخصصة الخاصة به.
لنلقِ نظرة على مثال:
.button { -fx-font-size: 15px; }
يتم استخدام مفهومين رئيسيين هنا. الأول هو محدد
زر . وهي تحدد المكونات التي يجب أن يطبق عليها النمط. في هذا المثال ، يتم تطبيق النمط على جميع الأزرار.
الجزء الثاني هو الخصائص الفعلية للأسلوب ، والتي سيتم تطبيقها على جميع المكونات التي تطابق محدد لدينا. الخصائص هي كل شيء داخل الأقواس المتعرجة.
كل خاصية لها معنى محدد. في مثالنا ، هناك خاصية
حجم الخط - fx ، والتي تحدد حجم النص. في المثال ، القيمة هي 15
بكسل ، ولكن هذه القيمة يمكن أن تكون أي قيمة أخرى.
لتلخيص - أنشأنا قاعدة تنص على أن جميع الأزرار في كل مكان يجب أن يكون نصها 15 بكسل.
محددات (محددات)
الآن دعونا نلقي نظرة فاحصة على كيفية عمل محددات في JavaFX. يحدث هذا تقريبًا كما في CSS العادي.
فئة (فئة)
يمثل الفصل في CSS عدة عناصر متشابهة. على سبيل المثال ، أزرار أو خانات الاختيار. يبدأ المحدد ، الذي يجب تطبيقه على جميع عناصر نفس الفئة ، بنقطة "." ، يتبعها فورًا اسم الفئة. اصطلاح تسمية الفصل هو فصل الكلمات الفردية بحرف "-". ينطبق المحدد التالي على جميع العناصر مع فئة
التصنيف .
.label { // Some properties }
المدمج في الطبقات
الخبر السار هو أن جميع مكونات JavaFX المدمجة (مثل Label أو Button) لديها بالفعل فئة محددة مسبقًا. إذا كنت ترغب في تخصيص نمط جميع التسميات في التطبيق الخاص بك ، فلن تحتاج إلى إضافة أي فئات مخصصة لكل من التسميات الخاصة بك. كل تسمية لها فئة
التسمية بشكل افتراضي.
من السهل تحديد اسم الفئة من المكون:
- خذ اسم فئة مكون Java - على سبيل المثال. ملصق
- اجعل الاسم صغيرًا
- إذا كانت تتألف من عدة كلمات ، فافصلها بالرمز "-"
بعض الأمثلة:
- التسمية → التسمية
- CheckBox → خانة الاختيار
عند استخدام فئات مثل المحددات ، تأكد من إضافة ".". هذا يعني أن محدد فئة
التصنيف هو
.label .
فصول مخصصة
إذا لم تكن الفئات المضمنة كافية ، يمكنك إضافة الفئات الخاصة بك إلى مكوناتك. يمكنك استخدام عدة فئات مفصولة بفاصلة:
<Label styleClass="my-label,other-class">I am a simple label</Label>
أو في جافا:
Label label = new Label("I am a simple label"); label.getStyleClass().addAll("my-label", "other-class");
لا تؤدي إضافة فئات بهذه الطريقة إلى إزالة فئة المكون افتراضيًا (في هذه الحالة ،
التسمية ).
هناك فئة خاصة واحدة تسمى
الجذر . هذا هو المكون الرئيسي للمشهد الخاص بك. يمكنك استخدامه لتصميم كل شيء داخل المشهد الخاص بك (على سبيل المثال ، تعيين خط عمومي). هذا مشابه لاستخدام محدد علامة النص في HTML.
الهوية
هناك طريقة أخرى لتحديد المكونات في CSS وهي استخدام معرف المكون (ID). إنه معرف فريد للمكون. بخلاف الفئات التي يمكن تخصيصها لمكونات متعددة ، يجب أن يكون المعرف فريدًا في المشهد.
بينما الرمز "." يستخدم للإشارة إلى الفصل. أمام الاسم في محدداتهم ، يتم تمييز المعرفات بالرمز "#".
#my-component { ... }
في FXML ، يمكنك استخدام
fx: id لتعيين معرّف CSS لأحد المكونات.
<Label fx:id="foo">I am a simple label</Label>
ومع ذلك ، هناك تحذير واحد.
يتم استخدام نفس
المعرف للإشارة إلى كائن المكون المعلن في وحدة التحكم الخاصة بك بنفس الاسم. نظرًا لأن المعرف واسم الحقل في وحدة التحكم يجب أن يتطابقان ، يجب أن تأخذ
fx: id في الاعتبار تقييد تسمية Java لأسماء الحقول. على الرغم من أن اصطلاح تسمية CSS يعرّف الكلمات الفردية مفصولة بحرف "-" ، إلا أنه حرف غير صالح لأسماء حقول Java. لذلك ، بالنسبة إلى
fx: id ببضع كلمات ، تحتاج إلى استخدام اصطلاح تسمية مختلف مثل CamelCase ، أو استخدام الشرطة السفلية.
<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>
في Java ، يمكنك ببساطة استدعاء طريقة
setId () للمكون الخاص بك.
Label label = new Label("I am a simple label"); label.setId("foo");
خصائص (خصائص)
على الرغم من أن CSS المستخدم في JavaFX يشبه إلى حد كبير CSS الأصلي للويب ، هناك فرق كبير واحد. أسماء الخصائص مختلفة ، وهناك العديد من الخصائص الجديدة الخاصة بـ JavaFX. لديهم البادئة
-fx- .
فيما يلي بعض الأمثلة:
- -fx- لون الخلفية: لون الخلفية
- -fx- ملء النص: لون النص
- -fx-font-size : حجم النص
يمكنك العثور على قائمة بجميع الخصائص في
دليل التصميم الرسمي .
زائف
بالإضافة إلى الفئات المعتادة التي تحدد مكونات معينة ، هناك ما يسمى بالفصول الزائفة التي تشير إلى حالة المكون. يمكن أن يكون هذا ، على سبيل المثال ، فئة لتمييز أن المكون له تركيز أو أن مؤشر الماوس عليه.
هناك العديد من الطبقات الزائفة المضمنة. لنلقِ نظرة على الزر. هناك العديد من الطبقات الزائفة التي يمكنك استخدامها ، على سبيل المثال:
- تحوم : الماوس فوق زر
- تركز : الزر لديه التركيز
- معطل : تم تعطيل الزر
- الضغط : زر الضغط
تبدأ الفصول الزائفة بالحرف ":" (على سبيل المثال
:: hover ) في محددات CSS. بالطبع ، تحتاج إلى تحديد المكون الذي تنتمي إليه الفئة الزائفة - على سبيل المثال ،
button: hover . يوضح المثال التالي محددًا ينطبق على جميع الأزرار التي لها تركيز:
.button:focused { -fx-background-color: red; }
بخلاف CSS ، التي تحتوي على فصول زائفة أساسية فقط للحالات مثل
التركيز والبؤرة ، تحتوي JavaFX على فصول زائفة خاصة بالمكونات تتعلق بحالات أو خصائص مكونات مختلفة.
على سبيل المثال:
- أشرطة التمرير لها فصول زائفة أفقية ورأسية
- العناصر (الخلايا) لها فصول زائفة غريبة وحتى
- قام TitledPane بتوسيع الطبقات الزائفة والانهيار .
فصول زائفة مخصصة
بالإضافة إلى الطبقات الزائفة المدمجة ، يمكنك تحديد واستخدام الطبقات الزائفة الخاصة بك.
دعنا ننشئ تسمية خاصة بنا (وراثة من فئة التصنيف). سيكون لها خاصية منطقية جديدة تسمى
لامعة . في هذه الحالة ، نريد أن يكون لدينا تسمية
فئة الزائفة
لامعة .
نظرًا لأن العلامة تحتوي على
فئة زائفة
لامعة ، يمكننا تعيين خلفية العلامة
الذهبية :
.shiny-label:shiny { -fx-background-color: gold; }
الآن قم بإنشاء الفصل نفسه.
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); } }
هناك العديد من الأجزاء المهمة هنا:
- لدينا خاصية منطقية BooleanProperty بدلاً من المنطقية المعتادة. هذا يعني أن الكائن اللامع يمكن ملاحظته ، ويمكننا تتبع (الاستماع إلى) التغييرات في قيمتها.
- نقوم بتسجيل موزع رسائل يتم استدعاؤه في كل مرة تتغير فيها قيمة الكائن اللامع باستخدام shiny.addListener () .
- عندما تتغير القيمة اللامعة ، نضيف / نزيل فئة زائفة لامعة وفقًا للقيمة الحالية ل pseudoClassStateChanged (PseudoClass.getPseudoClass ("shiny") ، shiny.get ()) .
- نضيف فئة مخصصة لجميع تسميات التسمية اللامعة ، بدلاً من امتلاك فئة التصنيف الموروثة من الأصل فقط. وبالتالي ، يمكننا فقط اختيار علامات لامعة .
ورقة الأنماط الافتراضية
حتى إذا لم تقدم أنت بنفسك أي أنماط ، فإن كل تطبيق JavaFX لديه بالفعل بعض الأنماط المرئية. هناك ورقة أنماط الافتراضية التي تنطبق على كل تطبيق. يطلق عليه
modena (منذ JavaFX 8 ، كان يطلق عليه سابقًا اسم
بحر قزوين ).
يمكن العثور على ورقة الأنماط هذه في الملف:
jfxrt.jar \ com \ sun \ javafx \ scene \ control \ skin \ modena \ modena.cssأو يمكنك العثور على الملف
هنا . في نفس الدليل ، هناك العديد من الصور التي تستخدمها ورقة الأنماط.
توفر ورقة الأنماط هذه الأنماط الافتراضية ، ولكن لها الأولوية الدنيا على الأنواع الأخرى من أوراق الأنماط ، بحيث يمكنك تجاوزها بسهولة.
ورقة أنماط المشهد
بالإضافة إلى ورقة الأنماط الافتراضية المذكورة أعلاه ، يمكنك بالطبع تقديم الخاصة بك. أعلى مستوى يمكنك من خلاله تطبيق الأسلوب هو المشهد بأكمله. يمكنك تنفيذ ذلك في FXML الخاص بك:
<BorderPane xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml" stylesheets="styles.css" ... > ... </BorderPane>
أو في كود جافا الخاص بك:
String stylesheet = getClass().getResource("/styles.css").toExternalForm(); scene.getStylesheets().add(stylesheet);
انتبه إلى المكالمة إلى
EXternalForm () . يتوقع Scene الحصول على محتويات ورقة الأنماط كسلسلة ، وليس كملف ، لذلك نحن بحاجة إلى تقديم محتويات ورقة الأنماط لدينا كسلسلة.
ورقة أنماط الأصل
بالإضافة إلى ورقة الأنماط للمشهد بأكمله ، من المفيد في بعض الأحيان أن يكون لديك أنماط على مستوى التخطيط. هذا - بالنسبة لحاوية منفصلة ، مثل VBox أو HBox أو GridPane. الأصل الرئيسي لجميع التخطيطات هو الفئة الأصل ، والتي تحدد طرق معالجة أوراق الأنماط على مستوى التخطيط. تنطبق هذه الأنماط فقط على المكونات في هذا التصميم ، وليس على المشهد بأكمله. للأسلوب على مستوى التخطيط الأسبقية على النمط على مستوى المشهد.
<HBox stylesheets="styles.css"> ... </HBox>
في Java ، تحتاج إلى تحميل محتويات ورقة الأنماط بنفسك ، تمامًا كما كان من قبل للمشهد:
HBox box = new HBox(); String stylesheet = getClass().getResource("/styles.css").toExternalForm(); box.getStylesheets().add(stylesheet);
أنماط مضمنة
حتى الآن ، نظرنا فقط في الحالات التي تم فيها تخصيص ورقة أنماط خارجية لمشهد أو تخطيط بأكمله. ولكن يمكنك تعيين خصائص النمط الفردي على مستوى المكون.
هنا لا داعي للقلق بشأن المحدد ، حيث يتم تعيين جميع الخصائص لمكون معين.
يمكنك تحديد العديد من الخصائص مفصولة بفواصل منقوطة:
<Label style="-fx-background-color: blue; -fx-text-fill: white"> I'm feeling blue. </Label>
في Java ، يمكنك استخدام طريقة
setStyle () :
Label label = new Label("I'm feeling blue."); label.setStyle("-fx-background-color: blue; -fx-text-fill: white");
إن الأنماط على مستوى المكون لها الأسبقية على أنماط المشهد وكذلك الأنماط الأصل على مستوى التخطيط.
لماذا تحتاج إلى تجنبها
يمكن أن يكون التصميم على مستوى المكونات مناسبًا ، لكنه حل سريع ومتسخ. أنت تتخلى عن الميزة الرئيسية لـ CSS ، وهو فصل الأنماط عن المكونات. الآن يمكنك ربط العناصر المرئية بشكل صارم بالمكونات. لم يعد بإمكانك تبديل أوراق الأنماط الخاصة بك بسهولة عند الضرورة ، لا يمكنك تغيير السمات.
علاوة على ذلك ، لم يعد لديك مكان مركزي واحد يتم فيه تحديد أسلوبك. عندما تحتاج إلى تغيير شيء ما في مجموعة من المكونات المتشابهة ، تحتاج إلى تغيير كل مكون على حدة ، وليس تحرير مكان واحد فقط في ورقة الأنماط الخارجية. لذلك ، يجب تجنب أنماط المكونات المضمّنة.
أولويات ورقة الأنماط
يمكنك توفير التصميم على عدة مستويات - مشهد ، الأصل ، وأنماط مضمنة ، وهناك أيضا ورقة أنماط المودم الافتراضية. إذا قمت بتغيير نفس الخاصية لنفس المكون على عدة مستويات ، فإن JavaFX له إعداد أولوية يحدد الأنماط التي ينبغي استخدامها. قائمة الأولويات - من الأعلى إلى الأدنى:
- أنماط مضمنة
- أنماط الوالدين
- أنماط المشهد
- الأنماط الافتراضية
هذا يعني أنه إذا قمت بتعيين لون خلفية تسمية معينة في كل من المستوى المضمن ومستوى المشهد ، فسوف تستخدم JavaFX القيمة المحددة في الأنماط المضمنة لأنها لها أولوية أعلى.
قراءة إضافية
يحتوي JavaFX على العديد من خصائص CSS ، ووصفها خارج نطاق هذا المنشور ؛ للحصول على قائمة مفصلة ، راجع
دليل CSS المرجعي الرسمي لـ JavaFX .