الرسوم المتحركة والانتقالات
الرسوم المتحركة والانتقالات
يأتي JavaFX مزوّدًا بمحرك رسوم متحركة متكامل يعمل على نفس مؤقّت النبضات (pulse timer) الذي يستخدمه محرك التخطيط والعرض. لا تحتاج إلى مكتبة خارجية أو خيط عمل منفصل — إذ يتولّى الإطار جدولة التنفيذ والاستيفاء (interpolation) وسلامة الخيوط تلقائيًا. يغطّي هذا الدرس كل الأدوات الرئيسية في ذلك المحرك: Timeline لتحريك القيم، وفئات Transition الجاهزة التي تستهدف خصائص بعينها، ومركّبَي الانتقالات SequentialTransition وParallelTransition، وAnimationTimer منخفض المستوى للتحكم الكامل في كل إطار.
Thread.sleep أو javax.swing.Timer.
Timeline — المحرّك متعدد الأغراض
تُحرّك Timeline أي WritableValue (وهو ما تمثّله كل خاصية JavaFX) عبر سلسلة من نقاط التفتيش KeyFrame. تُحدّد القيمة التي يجب أن تكون عليها الخاصية عند كل لحظة زمنية، ثم يقوم المحرك بالاستيفاء السلس بينها.
يُغلّف KeyValue مرجعًا للخاصية وقيمةً مستهدفة. أما KeyFrame فيُغلّف واحدًا أو أكثر من كائنات KeyValue إلى جانب نقطة زمنية. يمكن لـ Timeline واحدة أن تحمل أي عدد من الإطارات المفتاحية مع أي عدد من الخصائص.
يمكنك أيضًا إرفاق EventHandler<ActionEvent> عادي بإطار مفتاحي لتشغيل استدعاء راجع عند لحظة محددة، وهو مفيد لتشغيل مؤثرات صوتية أو تحديث الحالة أو تنسيق التغييرات غير المرتبطة بالخصائص:
فئات الانتقال الجاهزة
للمهام الأكثر شيوعًا توفّر JavaFX فئات Transition جاهزة. كل منها يستهدف خاصية أو تأثيرًا محددًا، مما يغنيك عن كتابة KeyValue يدويًا.
TranslateTransition— تحريك العقدة على محاور X / Y / Z.ScaleTransition— تحجيم العقدة حول نقطة محورها.RotateTransition— تدوير العقدة حول محور Z (أو محور مخصص).FadeTransition— تحريك خاصيةopacityبين قيمتين.FillTransition— استيفاء لون التعبئة فيShape.StrokeTransition— استيفاء لون الحدود فيShape.PathTransition— تحريك العقدة على طول مسارShapeاعتباطي.
تشترك كل الفئات الفرعية في نفس الواجهة البرمجية الأساسية: setDuration() وsetCycleCount() وsetAutoReverse() وplay() وpause() وstop(). إليك مثالًا كاملًا يجمع ثلاثة انتقالات:
تركيب الرسوم المتحركة: Sequential و Parallel
نادرًا ما تُشغّل واجهات المستخدم الحقيقية رسمًا متحركًا واحدًا معزولًا. تُشغّل SequentialTransition قائمة من الرسوم المتحركة واحدةً تلو الأخرى؛ بينما تُشغّل ParallelTransition جميعها في آنٍ واحد. كلاهما تنفّذ واجهة Animation، لذا يمكن تداخلها بشكل اعتباطي.
Transition بذاكرة تشير إلى العقدة المستهدفة. إذا استدعيت play() على انتقال يعمل بالفعل فإنه يُعيد التشغيل من البداية. أنشئ نُسخًا جديدة حين تحتاج إلى تشغيل نفس الرسوم المتحركة على عقد متعددة.
Interpolators — التحكم في الإحساس بالحركة
افتراضيًا تُستوفى الخصائص خطيًا — بسرعة ثابتة من البداية إلى النهاية مما يبدو آليًا. توفّر فئة Interpolator في JavaFX عدة منحنيات تسهيل جاهزة:
Interpolator.LINEAR— معدّل ثابت (الافتراضي).Interpolator.EASE_IN— بداية بطيئة ثم تسارع.Interpolator.EASE_OUT— بداية سريعة ثم تباطؤ عند النهاية.Interpolator.EASE_BOTH— بداية بطيئة ونهاية بطيئة؛ المنحنى الأكثر طبيعية لرسوم واجهات المستخدم.Interpolator.SPLINE(x1, y1, x2, y2)— منحنى Bézier مكعّب لتسهيل مخصّص كليًا.Interpolator.DISCRETE— يقفز فورًا إلى القيمة المستهدفة عند حدود الإطار المفتاحي؛ مفيد لسلاسل الصور الإطارية.
مرّر Interpolator كمعامل ثالث لـ KeyValue، أو استدع setInterpolator() على فئة Transition:
AnimationTimer — التحكم الكامل في كل إطار
حين تحتاج إلى تحديث خاصية المشهد في كل إطار — كحلقة لعبة أو محاكاة فيزيائية أو مخطط بيانات في الوقت الفعلي — فإن AnimationTimer هو الأداة المناسبة. تجاوز طريقة handle(long now) الخاصة بها: now هو الطابع الزمني الحالي بالنانوثانية، تستخدمه لحساب الوقت المنقضي بين الإطارات.
handle() يحجب خيط الرسم. اجعله خفيفًا: تحديث المواضع، أو استهلاك طابور محسوب مسبقًا، أو تبديل مخزن صورة معاد رسمه. لا تُجرِ عمليات I/O أو استعلامات قاعدة بيانات أو حسابات حاجبة أبدًا بداخله.
دورة حياة الرسوم المتحركة
تشترك جميع الفئات الفرعية من Animation في نفس دورة الحياة:
play()— البدء أو الاستئناف من الموضع الحالي.playFromStart()— الرجوع إلى اللحظة 0 والتشغيل.pause()— التجميد عند الموضع الحالي؛ تستأنفplay()من هناك.stop()— التوقف وإعادة الضبط إلى اللحظة 0.jumpTo(Duration)— الانتقال إلى موضع محدد دون تغيير حالة التشغيل.setRate(double)— القيمة 2.0 تُشغّل بضعف السرعة؛ -1.0 تُشغّل بالعكس.setOnFinished(EventHandler)— استدعاء راجع يُطلَق عند اكتمال الدورة الأخيرة.
نمط عملي: تغذية راجعة بصرية عند ضغط الزر
رسم متحرك قصير للتحجيم والعودة عند النقر على الزر هو مثال كلاسيكي يجمع ما تعلّمته. يستخدم SequentialTransition من نسختين من ScaleTransition ويقرأ بشكل واضح في كود المتحكّم:
الخلاصة
يمنحك JavaFX مجموعة أدوات رسوم متحركة متعددة الطبقات: Timeline للتحكم الكامل في الخصائص الاعتباطية، وفئات Transition الجاهزة للتأثيرات الشائعة، وSequentialTransition وParallelTransition للتركيب، وAnimationTimer لحلقات اللعبة على مستوى الإطار. تحدّد منحنيات Interpolator الإحساس بالحركة. في الدرس الأخير من هذا البرنامج التعليمي ستجمع كل هذه التقنيات — الربط، والأحداث، وCSS، والرسوم المتحركة — معًا في تطبيق JavaFX تفاعلي متكامل.