المرحلة والمشهد وشجرة العقد
المرحلة والمشهد وشجرة العقد
يُبنى كل تطبيق JavaFX مرئي من ثلاثة مفاهيم متشابكة: المرحلة (Stage)، والمشهد (Scene)، وشجرة العقد (Scene Graph). إن فهم ماهية كل منها بدقة — وكيفية ارتباطها ببعضها — يُشكّل النموذج الذهني الذي يجعل كل قرار تخطيط وتنسيق وأحداث يقع في مكانه الطبيعي.
المرحلة (Stage)
المرحلة Stage هي نافذة من أعلى المستوى. يُنشئ وقت تشغيل JavaFX واحدة لك — المرحلة الأساسية — ويمررها إلى دالة start(Stage stage) الخاصة بك. يمكنك أيضًا إنشاء مزيد من كائنات Stage عند الحاجة إلى نافذة ثانية (حوار، لوحة أدوات، عرض على شاشة ثانوية).
تُغلّف فئة Stage نافذة نظام التشغيل الأصلية. وأكثر الخصائص التي تُهيَّأ شيوعًا هي:
stage.setTitle("My App")— نص شريط عنوان النافذة.stage.setWidth(800)/stage.setHeight(600)— الأبعاد الأولية بالبكسل.stage.setResizable(false)— تعطيل تغيير حجم النافذة من قِبَل المستخدم.stage.initStyle(StageStyle.UNDECORATED)— إزالة واجهة نظام التشغيل كليًا (مفيد لشاشات التحميل).stage.initModality(Modality.APPLICATION_MODAL)— حجب الإدخال عن النوافذ الأخرى (نمط الحوار المشروط).stage.show()— إظهار النافذة؛ لن يظهر شيء على الشاشة حتى يُستدعى هذا الأسلوب.
new Stage() لاستبدالها — بل هيّئ الكائن الذي يُسلَّم إليك وأظهره.
المشهد (Scene)
المشهد Scene هو حاوية المحتوى التي تعيش داخل المرحلة. يكون مشهد واحد نشطًا في أي لحظة؛ يمكنك تبديل المشاهد لتطبيق التنقل بأسلوب الصفحات دون فتح نوافذ جديدة. يُنشأ المشهد بعقدة جذر وأبعاد مفضّلة اختيارية:
الخصائص الرئيسية لـ Scene:
- عقدة الجذر — حاوية التخطيط الوحيدة في المستوى الأعلى التي تملأ مساحة المشهد بأكملها.
- أوراق الأنماط —
scene.getStylesheets().add(...)يضيف ملفات CSS خارجية تُنسّق الشجرة بأكملها. - التعبئة —
scene.setFill(Color.DARKGRAY)يضبط لون خلفية المشهد (خلف عقدة الجذر). - مؤشر الماوس —
scene.setCursor(Cursor.WAIT)يغيّر مؤشر الماوس للنافذة بأكملها.
stage.getScene().setRoot(settingsPane). هذا سريع، ويحتفظ بالمرحلة والمشهد نفسيهما، ويُبقي على أي أوراق أنماط أضفتها إلى المشهد مسبقًا.
شجرة العقد (Scene Graph)
شجرة العقد هي شجرة من كائنات Node جذرها هو العقدة الجذر للمشهد. كل عنصر مرئي أو تفاعلي في JavaFX — زر، تسمية، صورة، مستطيل، جزء تخطيط، مشغّل وسائط — هو Node. وتُرتَّب في هرمية أب-ابن:
- العقد الأبوية (الفئات الفرعية من
Parent) يمكنها امتلاك عناصر فرعية:VBox،HBox،BorderPane،StackPane،Group، إلخ. - العقد الورقية لا يمكنها امتلاك عناصر فرعية:
Button،Label،Rectangle،ImageView، إلخ.
إليك شجرة عقد صغيرة في الكود:
تبدو الشجرة الناتجة كما يلي:
لماذا شجرة؟ تتالي الخصائص
بنية الشجرة ليست اعتباطية — بل تُشغّل ثلاثة سلوكيات قوية في المنصة:
- تتالي CSS: تنطبق قاعدة الأنماط المطبّقة على أحد الآباء تلقائيًا على كل المنحدرين، تمامًا كـ CSS على الويب. اضبط خطًا على
BorderPaneوكلLabelفرعي سيرثه ما لم يُستبدَل. - فضاء الإحداثيات: يُعبَّر عن موضع كل عقدة نسبةً إلى أبيها. حرّك الأب وكل الأبناء يتحركون معه — دون الحاجة إلى حسابات.
- انتشار الأحداث: تنتقل نقرات الماوس وضغطات المفاتيح نزولًا عبر الشجرة (مرحلة الالتقاط) ثم صعودًا (مرحلة الفقاعة)، مما يتيح لمستمع واحد على حاوية اعتراض أحداث أي منحدر.
اجتياز الشجرة والفحص
نادرًا ما تحتاج إلى السير في الشجرة يدويًا، لكن يفيدك معرفة أن الواجهة البرمجية موجودة. تعرض كل Node ما يلي:
node.getParent()— يعيد الأب المباشر، أوnullللجذر.node.getScene()— يعيدSceneالتي تنتمي إليها هذه العقدة، أوnullإذا لم تُضَف بعد.parent.getChildrenUnmodifiable()— عرض للقراءة فقط لقائمة أبناء الأب.scene.lookup("#myId")— البحث عن أي عقدة بمعرّف CSS الخاص بها، مثلdocument.getElementByIdفي المتصفح.scene.lookupAll(".btn-primary")— العثور على جميع العقد المطابقة لمحدد فئة CSS.
العقد الحية مقابل غير المرتبطة
العقدة التي أُضيفت إلى شجرة العقد وهي جزء من مرحلة مُظهَرة تُسمى حية. بمجرد أن تصبح حية، تُنسّقها محرك CSS، ويقيسها محرك التخطيط ويضعها في موضعها، ويرسمها محرك التصيير في كل إطار. أما العقدة التي أنشأتها لكن لم تضفها بعد فهي غير مرتبطة — توجد في الذاكرة لكنها غير مرئية وغير منسّقة. يهم هذا التمييز عندما تحاول قياس حجم عقدة قبل تخطيطها: استدعِ node.applyCss() وnode.layout() أولًا إذا احتجت إلى الأبعاد قبل نبضة التصيير الأولى.
تجميع كل شيء معًا
النموذج الذهني هو ثلاث طبقات متسلسلة:
- Stage — إطار نافذة نظام التشغيل (شريط العنوان، والزخارف، والحالة المشروطة).
- Scene — لوحة المحتوى داخل المرحلة (الحجم، ولون خلفية التعبئة، وأوراق أنماط CSS).
- Scene Graph — شجرة كائنات
Nodeالتي تحدد ما يُعرض ويتفاعل فعليًا.
كل ميزة تبنيها في JavaFX — عناصر تحكم مخصصة، وتحريكات، وربط بيانات، وسحب وإفلات — تعمل على هذه الشجرة. إن معرفة كيفية بنائها والتنقل فيها والتفكير في علاقات الأب والابن هو الأساس الذي يقوم عليه كل شيء آخر.