لوحة المتصدرين
المحتوى الأكثر حصولًا على سمعة جيدة
المحتوى الأعلى تقييمًا في 03/02/21 في كل الموقع
-
الدالة addslashes التي تضيف escape letter قبل " الدالة substr لقص آخر محرفين من السلسلة والناتجين من الحلقة الفراغ و , أي " ," <!DOCTYPE html> <html> <body> <?php $arr1 = ["https://google.com", "https://facebook.com", "https://twitter.com"]; $arr2 = "\"["; foreach ($arr1 as $str) { $arr2 .= addslashes('"'. $str . '"' . ', '); } $arr2 = substr($arr2, 0, -2); $arr2 .= "]\""; echo $arr2; ?> </body> </html>2 نقاط
-
لدي الكود التالي: <?php $company = Company::find($id) ->update([ "company_name" => $request["company_name"], "former_company" => $request["former_company"], "company_logo" => $imageName, ]); أريد تعديل الحقل company_logo في حالة ما إذا كان المُتغير imageName لا يُساوي null أما إن كان null يقوم بتعديل الحقول الأخرى فقط. هل هناك إمكانية لعمل هذا داخل الدالة update.2 نقاط
-
اكتب برنامج يطلب من المستخدم ادخال ١٠ قيم صحيحة في مصفوفة a بإستخدام الحلقات ويقوم البرنامج بحساب التالي الفرق بين مجموع الاعداد الزوجيه ومجموع الاعداد الفردية طباعة موقع اقل عنصر في المصفوفة1 نقطة
-
ذكرنا في المقال السابق أسلوب الإدارة الفنية للمشروع بينك وبين العميل وطرق تنظيم العمل على المشروع نفسه من أدوات وبرامج وغير ذلك. أما في هذا المقال فإننا سنذكر بقليل من التفصيل أساليب التعامل مع العملاء، وكيف تحدد أسلوب الخطاب المناسب معهم، مع النظر في المشاكل والتحديات والخلافات التي قد تطرأ بينك وبين العملاء، وكيف تعالجها بالأسلوب الأمثل. ذلك أنك في عملك المستقل ستواجه أنواعًا مختلفة لفرص العمل التي يقدمها أولئك العملاء. ولأن كل عميل مختلف عن الآخر، فيجب أن تحضر نفسك لمواجهة المواقف المختلفة التي قد تطرأ. وسنتجنب هنا الحديث عن العملاء الذين لهم باع في مجالاتهم وعلى قدر من المهنية والأخلاق والخبرة، فهؤلاء لا نظن أنك ستجد مشكلة معهم، وعليه فيكفيك أخلاقك وحسن تعاملك معهم بنفس المهنية والاحترام، وإنما سننظر في أنواع العملاء الذين قد تحدث بينك وبينهم خلافات أو مشاكل لأسباب فنية أو أخطاء بشرية أو إدارية أو غير ذلك. على أن سردنا في هذا المقال لا يعني أن العميل قليل الصبر مثلًا ستعرفه بمجرد النظر! كأن يكون لا يكمل حروف كلماته مثلًا في عرض مشروعه، فأغلب الناس لطيفة وودودة حتى تُستفز مشاعرها أو لا تلبى مطالبها وحاجاتها. تحديد لهجة الخطاب مع العملاء ترتبط هذه النقطة كثيرًا بهويتك التجارية التي تحدثنا عنها في كيفية التسويق الذاتي في العمل الحر، ذلك أن أسلوبك في الرسائل ونمط حديثك يشكل جزءًا كبيرًا من هويتك ولا شك، وقد ترى ذلك جليًا حين تكلم خدمة العملاء للبنك الذي تتعامل معه، وحين تكلم خدمة العملاء لشركة أدوات ترفيهية اشتريت منها جهازًا مثلًا. فترى موظف البنك يتكلم بأسلوب يفتقر إلى المرح والمزاح مقارنة بموظف الشركة الترفيهية الذي يخاطبك بمرح سائلًا إياك عن حالك اليوم وتمنياته لك بيوم سعيد! ذلك أن الأول يتعامل مع أموالك وثروتك، وأي باب للسهو أو الفهم الخاطئ لكلامه قد يودي بكارثة لك أو له. وكذلك في شأنك مع العملاء، فاختر اللهجة المناسبة لعملك وطبيعة شخصيتك في الحديث معهم، فلن نقيدك في هذا، لكن سنضع لك إرشادات عامة ترسم عليها منهجك الذي تحب. اختر الفصحى ما استطعت لنقل أنك ستتعامل مع عملاء يتحدثون العربية كلغة أم في الغالب، فكيف تحدثهم؟ بلهجتك أم بلهجتهم؟ إننا نرى من تجاربنا أن أيًا من اللهجتين ليستا بشيء أمام الفصحى، وذلك لأسباب يقصر المقام عن بيانها، لكن سنذكر لك بعض الأسباب التي تجعلك تستخدم الفصحى بدلًا من لهجتك المحكية. بادئ ذي بدء فإن الفصحى في أي لغة تكون أشمل من اللهجات المحكية في مفرداتها، وأبلغ في إيصال المعنى واضحًا، دون أن يشوب ذلك استخدام لكلمة تخص منطقة بعينها أو كلمة لها أكثر من معنى بحسب المنطقة، كذلك فإنها أكثر رسمية ومهنية من اللهجة المحكية، فتوحي للعميل بأنك شخص ناضج ومحترف. وقد كان آخر عهدي بالحديث بالعامية على الويب قبل خمسة أعوام أو أكثر، حين راسلني أحدهم من فلسطين يسألني عن مقالة كتبتها، فسألته أن يشرح لي قصده لأني لم أفهمه بسبب لهجته، فأعاد شرحه فلم أفهم، فاعتذرت وطلبت إعادة الشرح مرة أخرى فغضب وتركني. فآليت على نفسي بعدها ألا أكلم أحدًا في عمل إلا بالفصحى، ولعل ما أعانني على ذلك أن كان أغلب من أتعامل معهم وقتها من بلاد المغرب العربي الذين تختلف لهجاتهم اختلافًا كبيرًا عن اللهجات المشرقية، فلا يصلح التعامل بيننا إلا بالفصحى. الزم حدود العمل ستتعامل مع عملاء من الشرق والغرب، وستجد فيهم الصغير والكبير، والحليم والغضوب، والرجال والنساء، ومن على دينك ومن ليس من ملتك، وهكذا، فما السبيل إلى مخاطبة كل أولئك؟ ببساطة، الزم حدود عملك، فلا تسأل عن أمور شخصية أو لا تخص عملك في شيء، ولا تسأل العميل عن عمره إلا لحاجة ملحة ترتبط بالعمل، ولا عن مسألة دينية إلا إن كان العميل يطلب عملًا يخالف شريعتك ومبادئك، وهكذا. وكذلك في التعامل بين الجنسين، إذ تكون هذه مسألة حساسة دومًا ولا يمكن تمام ضبطها، فالحل فيها أن تٌقصِر الحديث على مطالب العمل، ولا تمزجه بالمزاح غير الضروري أو الألفاظ غير اللائقة أو حمالة المعاني، بل كن واضحًا ومختصرًا، وكلامنا هذا للرجال والنساء معًا. لكن هل إرشاداتنا هذه ملزمة لك؟ كلا، فهل يعقل أن تحدث عميلًا بينك وبينه سنوات من العمل، بنفس الرسمية التي تخاطب بها عميلًا تقابله لأول مرة؟ لا شك أنكما ستكونان قد صنعتما رابطة تفسح المجال للتبسط في الكلام، لكن لا تدع هذا يغرك، فهو عميلك بالنهاية، وأنت ملتزم أمامه بعمل، فلا تدفعنك معرفته إلى الجور عليه في حقه أو التجاوز معه في الأدب. التواصل المنتظم مع العميل ينزعج العميل لا شك من قلة التواصل أو عدم انتظامه بينك وبينه، فقد يحتاج إلى تعديلات في مرحلة ما من المشروع، لكن لأنك تعمل في صمت دون الرجوع المنتظم إليه بتقارير عما فعلته، فقد تخطئ في تنفيذ تلك المرحلة أو تنفذها على غير ما يريد العميل. أضف إلى أن العميل قد يمثل منظمة أو شركة هي صاحبة العمل، وتريد منه تقارير مرحلية عن المشروع، فتؤذيه أنت بصمتك أثناء العمل. وقد بينا في الإدارة الفنية للمشروع أساليب تنظيم العمل والتواصل بينك وبين العميل لئلا تقع فيه. وإني أود تنبيهك إلى هذه النقطة لأني أقع فيها بنفسي، فإني أميل في العديد من المشاريع الكبيرة إلى قضاء أغلب وقت التنفيذ في النظر فيها والتخطيط لها وحسابها وتنظيمها وتوحيد عناصرها دون أن أكتب كلمة واحدة، ثم قد أنهي العمل كله في آخر الوقت. وإني لأعلم أن هذه خصلة في شخصيتي زادت وبرزت مع مشاريع التصميم الميكانيكي التي كنت أعمل عليها قديمًا لكثرة ما تحتاج من تخطيط قبل الشروع في التنفيذ، لكن هذا يزعج كثيرًا من العملاء الذين يحتاجون إلى تقارير دورية عن تمام العمل، لهذا من المفيد استخدام أداة لمتابعة سير العمل على المشروع، سواء كانت "أنا" أو تريللو أو غيرهما، أو مجرد ملف في جداول جوجل بينك وبين العميل، كما تحدثنا عن ذلك سابقًا بالتفصيل في مقال الإدارة الفنية للمشروع. أسباب عدم التواصل وإضافة إلى ما سبق، فقد يرجع عدم التواصل المتعمد من جانب المستقل إلى عدة أسباب: قد لا تكون للمستقل خطة عمل واضحة أو مناسبة لظروف عمله، وعليه سيمتنع عن التواصل مع العميل تجنبًا للإحراج إن أبطأ في تسليم مهمة أو أكثر، وعلاج هذا باتباع الإرشادات التي فصلناها في مقال الدخول إلى سوق العمل الحر، و مقالة الإدارة الفنية للمشروع. الاختلاف في التوقيت أو المناطق الزمنية، مما يؤدي إلى صعوبة تحديد أوقات خاصة للعمل. حالات الطوارئ، فقد يحدث لك حادث أو ظرف قاهر يقعدك عن العمل، فحينها تخبر العميل بما حدث في أقرب فرصة، وتعرض عليه الخيارات المتاحة لديك. فقد حدث مرة أني اضطررت لإجراء جراحة أثناء العمل على مشروع، فطلبت من الطبيب ورقة تفيد إجرائي لهذه الجراحة وبمدة الراحة التي أحتاجها، ثم أرسلت إلى العميل معتذرًا ومرفقًا لصورة التقرير من الطبيب. وذكر لي أحد أصحاب المشاريع على منصة مستقل -وقت نشر هذه السلسلة- قريبًا من هذا، فقد اختفى أحد المستقلين الذين يتعامل معهم فجأة دون إنذار فألغى المشروع الذي بينهما وقيَّمه سلبًا، لكن المستقل عاد بعد فترة كبيرة ليخبره بإصابته في حادث سير، وكذا حدث مع مستقل آخر، وفي الحالتين يعود المستقل في أقرب فرصة ليطلع العميل بحقيقة وضعه مع إثباتات تدل على صدق دعواه، إذ هذا أدنى ألا يظن به الظنون وهو لا يراه وبعيد عنه. التعامل مع تعديلات العملاء لا شك أنك ستحسب تكلفة المشروع وفقًا لمعيار تعرفه من الناحية الفنية، كأن تحسبه وفق عدد الكلمات أو الصفحات إن كنت مترجمًا أو عدد التصميمات وعناصرها، أو عدد الخصائص البرمجية المطلوبة، وهكذا وفق كل مشروع، فماذا تفعل لو طلب العميل تعديلات على العمل الذي عملت؟ إن هذا يعني وقتًا أطول في العمل على نفس المشروع، مما يعني أن أجرك سينخفض على هذا المشروع مع كل ساعة إضافية، ويجب أن تحسب للتعديلات حسابها وأنت تضع ميزانية المشروع. فمثلًا، يمكنك تحديد عدد محدد لتعديلات العميل، كأن تكون ثلاث تعديلات مجانية مثلًا، أو أن تكون زمنية فيكون للعميل الحق في التعديل ما لم يمر أسبوع على انتهاء العمل، وهكذا. وذلك لأنك قد تقابل عملاء لا يحسنون وصف ما يريدونه، لكنهم يستطيعون البناء على النماذج التي تقدمها ليصلوا إلى الصورة التي ترضيهم للعمل، لهذا نفضل أن تتفق مع العميل ابتداءً على عدد التعديلات ومدتها الزمنية، كي لا تجهد نفسك بدون مقابل من ناحية، أو تضطر إلى تجاهل الرد على العميل بعد تمام المشروع من ناحية أخرى، فإن الأخيرة هذه ليست من حسن التعامل وقد تُدخل شبهات على كسبك ومالك، كما ستضر سمعتك في السوق، وقد بينا في فصول سابقة كيف أن الويب يختلف عن السوق العادي في سهولة تدمير سمعة شركة أو علامة تجارية، وصعوبة تعويض تلك الخسائر. إدارة الخلافات مع العملاء إننا نحاول في هذه السلسلة أن نمهد الطريق لك كي تدخل مجال العمل الحر وتتعامل مع العملاء وتؤمن لنفسك دخلًا كريمًا مع تجنب الوقوع في الأخطاء والمشاكل التي وقعنا أو نقع فيها بأنفسنا من قبلك أو وقع فيها غيرنا، وذلك ببيان الأساليب والأدوات والبرامج التي تعينك على ذلك. لكن هذا لا يمنع من حدوث خلاف بينك وبين عميل حول تفصيل في المشروع القائم بينكما، أو بسبب تأخرك عليه في العمل، أو تأخره عليك في الردود والملاحظات أو في إنهاء المشروع ودفع باقي مستحقاتك wرغم إنهائك للعمل، إلى غير ذلك من المشاكل التي لا يمكن توقعها إلا بالتجربة المباشرة. ولأن هذه المشاكل واردة لا محالة فإننا سنستعرض أهمها وأكثرها حدوثًا ثم نفصل في كيفية حلها بالشكل الأمثل الذي يضمن الحفاظ على سمعتك وعلاقتك مع العملاء، وسنبدأ بالحديث العام حول المشاكل الفنية والعقبات التي قد تطرأ في المشروع، ثم نعرج على بعض المشاكل التي قد تحدث من جانب العملاء ونرى كيفية التعامل معها. فقد يحدث أنك تتأخر على العميل في تسليم ما يريد، أو تقع لك طوارئ لم تحسب حسابها، أو تختلف وجهة نظركما حول تفصيل داخل المشروع، وهكذا، وإن لم تحسن التعامل مع هذه المشاكل فسيتطور الأمر إلى نقاش حاد اللهجة ثم تصير الأمور تراشقًا شخصيًا وينتهي بإلغاء الصفقة بينكما وخسارتك للعمل وربما تقييم سيء من العميل على الويب أو على منصة العمل الحر التي أجريتما عليها الصفقة. التعامل السليم مع الخلافات إننا ننصحك بالتزام الحِلم والإنصاف عند النظر في تلك المشاكل، ومحاولة تفهم وجهة نظر العميل بوضع نفسك مكانه وحساب احتياجاته ومشاكله والضغط الواقع عليه من أجل تنفيذ المشروع، خاصة إن كان يمثل شركة أو جهة يعمل فيها وهي الطالبة للعمل. فانظر في أصل المشكلة الواقعة بينك وبين العميل، هل يلومك على تقصير في عملك أم بطء في التسليم أم قلة تواصل بينكما، أم عدم التزام بمواعيد التسليم، إلى غير ذلك من الأمور. وإني أكاد أجزم من خبرتي الشخصية أن أغلب مشاكل العملاء ستدور حول مدى خبرة المستقل بعمله وفهمه للمطلوب، والتزامه بموعد التسليم، وتواصله المنتظم مع العميل وحسن تعامله في ذلك التواصل. ونحن في هذه السلسلة نحاول التأصيل للحلول العملية المثلى التي تعلمناها دراسةً أو خبرة كي لا تقع في الأخطاء التي وقعنا -ونقع- فيها في هذه الأبواب، فإن وقع بينك وبين العميل إحدى تلك المشاكل لسبب أو لآخر، فتفهَّم أن العميل يريد إنجاز مطلوبه، لا أكثر ولا أقل، فاجتهد أن تتجنب معه تلك المشاكل أعلاه، لكن إن وقعت فيها فأخبر العميل بسبب ذلك، وناقشه في الخيارات المتاحة التي تحفظ علاقة طيبة معه ولا تضر مشروعه في نفس الوقت. فمثلًا، حين أتأخر في تسليم مشروع ما أو أبطئ في التواصل مع العميل أثناء المشروع فإنني أعتذر له مقابل ذلك، وإن شعرت أن الاعتذار لا يكفي فإني أعوض العميل ماديًا بخصم جزء من ثمن المشروع أو من المشروع الذي يليه إن كان بيننا تعامل لاحق. وقد حدثني أحد المستقلين بموقف أظنه وارد الحدوث لأي أحد لكنه أكثر حدوثًا مع الذين يدخلون المجال لأول مرة، إذ قدم عرضه لعميل وقبله العميل، ثم لما بيّن له العميل تفاصيل الصفقة شعر أن المطلوب أكبر من خبرته الفنية، فأرسل إلى العميل معتذرًا عن إتمام الصفقة وطلب إلغاءها. إن هذا خير من تنفيذ المشروع بأي جودة خوفًا من التقييم السيء أو خسارة ثمن الصفقة، فشعور العميل أنك تقدر وقته وماله سيجعله يصرف نظره إلى حسن خلقك وحرصك على موارده. وإني أزيدك في هذا الموقف أن لو كنت تعرف أحدًا من المتخصصين في ذلك المجال الذي اعتذرت عنه ثم أرشدت العميل إليه لبنيت ثقة بينك وبين العميل، ولزادت فرصة تفكيره فيك كخيار أول في المشاريع التالية، إذ يميل الناس إلى التعامل مع من بنوا معهم روابط ثقة وإن كانوا أقل خبرة من غيرهم. وهكذا تحاول وضع يدك على أصل المشكلة ولماذا يتصرف معك العميل بهذا الشكل، ثم تحاول وضع حلول وفقًا لهذا التأصيل. التعامل مع تجاوزات العميل ستجد في تعاملك مع العملاء أحيانًا تجاوزات شخصية وفنية منهم وتبسط في الكلام قد يزعجك، وسننظر في تفصيل هذا كما يلي: التجاوز في طلبات المشروع قد يطلب العميل عينة مجانية للتأكد من جودة عملك قبل المتابعة في المشروع حفظًا لوقته، وهذا لا بأس به، لكن احذر أن تقدم عينة مجانية كبيرة، كأن تكون أكثر من فقرة أو فقرتين إن كان المشروع ترجمة أو كتابة لعقد مثلًا، أو صفحة أو صفحتين مثلًا إن كان المشروع كتابًا، أو تصميمًا لصفحة إن كان موقعًا، وهكذا. فقد يحدث أن يراسل العميل أكثر من شخص طلبًا لعينة مجانية ويقسم المشروع على هذه العينات المجانية، ثم إذا حصل عليها ألغى المشروع. كذلك قد يطلب العميل مشروعًا بتفاصيل معينة، ثم تقدم عرضك عليه وفقًا لهذه التفاصيل ويوافق عليها، فلما تبدأ في العمل تجده يطلب منك زيادة على ما اتفقتما عليه، فحينها تنبهه بلطف إلى أن هذا خارج عن نطاق الاتفاق، وتخبره بثمن هذه الإضافات، فإن رضي فإنك تعدِّل ميزانية المشروع وفقًا لهذا، وإلا فلك الحق في إلغاء الصفقة أو إتمام المتفق عليه فقط. وهنا تبرز أهمية العمل على منصات مثل مستقل وخمسات وغيرها بدلًا من العمل خارجها، إذ تراجع إدارة المنصة نقاش الصفقة بينكما لتحفظ لك حقك، وتستطيع مراسلتها في حال شككت في مثل هذه الحالة أو غيرها لتنظر فيها. السؤال عن أمور شخصية إننا نوجه الكلام لك هنا كمستقل في هذه النقطة خاصة وفي الكتاب عامة، ألا تخلط الحياة العملية بالشخصية، ولا تتبسط في الكلام خارج نطاق المشروع إلا لحاجة، ولا تتعرض بالسؤال أو المزاح مع العميل في أمور شخصية خاصة ما استطعت. لكن كلامنا هنا يصلح للعملاء والمستقلين على سواء، فقد تتعامل أنت مع عميل لا يرى بأسًا في إقحام الأمور الشخصية في العمل، فيسألك عن حالك الاجتماعية وأولادك وغير ذلك من باب المزاح أو التبسط في الكلام، وقد لا ترضى بهذا، وكم رأينا حالات لنساء يشتكين من أسئلة العملاء الشخصية أو مزاحهم الثقيل أو غير المقبول، فماذا تفعل إن رأيت الطرف الآخر تجاوز حد العمل إلى الأمور الشخصية؟ إن ما ننصحك به ابتداءً هو التغافل إن كان الأمر طفيفًا، فإن عاد للمرة الثانية فنبهه بلطف إلى أنك لا تخلط الحياة العملية بالشخصية وتدعوه إلى التركيز على العمل، فإن تكرر للمرة الثالثة فلك الحق هنا في طلب إلغاء المشروع بينك وبينه. التجاوز في الأدب قد تحدث مشكلة أثناء العمل في المشروع وتجد خطاب العميل لك حادًا في لهجته، وهذا مقبول حين تتفهم أن العميل يشتكي تأخرك أو سوء فهمك لنقطة في التنفيذ أو غير ذلك، فتحاول أن تقدم الحلول المتاحة معتذرًا له عن ذلك التقصير، لكن ماذا لو تجاوز العميل في لهجته إلى السب أو التجريح الشخصي؟ عندئذ، ادفع بالتي هي أحسن، فتغافل عن هذا السب في حقك وقدِّم الحلول المتاحة مبينًا أسباب التقصير، وأخبره أنك تتفهم وجهة نظره وغضبه إزاء تنفيذ مشروعه وطلباته، لكنك لا تتقبل هذه اللهجة في الخطاب. فإن قبل منك وأوقف ذلك التجاوز وإلا فلك أن تخبره أنك قد تلغي الصفقة إن استمر في تجاوزه في الأدب ذاك. طلب أعمال مخالفة لشروطك نأتي هنا لنقطة مهمة وحساسة بالنسبة لأي عامل سواء في وظيفة عادية أو بشكل حر، ماذا لو أتاك عميل يطلب عملًا مخالفًا لمبادئك أو شريعتك؟ فمثلًا يأتيك إعلان عن تصميم لطعام غير صحي، أو ترجمة لنص غير أخلاقي أو إباحي، أو نحو ذلك مما يشين المرء أن يقبض أجرًا عليه، فهل تتنازل عن مبادئك من أجل المال أم ماذا؟! إنني أذكر واقعة رأيتها قبل بضعة أشهر من كتابتي لهذه السطور لمشروع تفريغ صوتي لمحادثة بالعربية يبدو أنها عادية لأول وهلة، لكن صاحب المشروع من شركة صينية بحثت عنها فوجدتها متورطة في قضايا مسلمي الأويغور، وقد أوقفت الولايات المتحدة الأمريكية تعاملاتها معها بسبب تلك الانتهاكات، فما بالك بالمستقلة التي كانت تعمل على المشروع، وهي مسلمة عربية؟! وتستغل هذه الشركة تلك التفريغات لربطها بالمقاطع الصوتية ثم تغذية برمجيات الذكاء الصناعي بها لتحسين التقاطها للكلمات العربية، وفي مثل تلك الحالة نصحت صاحبة المشروع بالثبات على مبادئها ورفض مثل تلك المشاريع. وقس هذا المثال على أي عمل قد يعرض لك، فما ذكرته هنا إلا لأنه ما حدث أمامي، وإلا فهذا لا يقيدك بشيء من دين أو قانون أو مبدأ، فالصحيح صحيح والخطأ خطأ، ومن المهانة قبول المال في عمل يخالف مبدأ أو قيمة سامية تربيت عليها. خلاصة المقال وهكذا نكون قد عرضنا في هذا المقال أغلب النقاط التي تتناول التعامل الشخصي مع العملاء والخلافات التي قد تنشب بينك وبينهم، وسننظر في المقال التالي إن شاء الله في إدارة الموارد البشرية لك كمستقل، فنبحث في إدارة الأزمات والوقت وزيادة الإنتاج. كتبت سارة شهيد المسودة الأولية لهذه المقالة. اقرأ أيضًا المقال التالي: العناية بالصحة الجسدية والنفسية للعامل المستقل المقال السابق: الإدارة الفنية للمشروع للعامل المستقل كيف تتخلص من العملاء السيئين بلباقة واحترام إدارة العملاء، كيف تبقى سعيدًا دون أن تفقد شعر رأسك من هم العملاء السلبيون وكيف تتعامل معهم كيف تخطط كمستقل للطوارئ غير المتوقعة النسخة الكاملة من كتاب دليل المستقل والعامل عن بعد1 نقطة
-
1 نقطة
-
1 نقطة
-
أريد الاستفسار عن برمجة وتصميم موقع موسوعة https://mawso3a.net/ هل هو بلوجر ام وردبريس ام برمجة خاصة وهل تكلفة تصميم متل موقع المحيط مكلفة أم لا1 نقطة
-
لماذا لا استطيع للوصل لل id من شاشة ال Mainactivity1 نقطة
-
لدي مُكونين livewire: <div class="col-md-4 p-4"> @livewire('app-add-task') </div> <div class="col-md-8 p-4"> @livewire('app-tasks') </div> المُكون الأول لإضافة مهمة جديدة و المُكون الثاني لعرض جميع المهام، عند إضافتي للمهمة يتم إضافتها لكن لا تظهر مباشرة في الصفحة و إنما حتى أقوم بتحديث الصفحة هل هناك طريقة لعرض المهمة مباشرة من دون تحديث للصفحة، هذا كود المُكون الأول: class AppAddTask extends Component { public $title; public function render() { return view('livewire.app-add-task'); } public function addTask() { auth()->user()->tasks()->create([ 'title' => $this->title, 'status' => false, ]); $this->title = ""; } } و هذا كود المُكون الثاني: class AppTasks extends Component { public function render() { $totalTasks = auth()->user()->tasks()->count(); $tasks = auth()->user()->tasks()->latest()->get(); return view('livewire.app-tasks', [ 'totalTasks' => $totalTasks, 'tasks' => $tasks ]); } }1 نقطة
-
نعم فالفكرة تكمن في إستخدام الأحداث و هناك عدة طرق لإستخدامها من بينها إرسال أو عمل emit للحدث من خلال المُكون الأول و التسمع على الحدث في المُكون الثاني لكن بما أننا نريد عمل تحديث ف livewire توفر طريقة خاصة إسمها $refresh، يُمكن التعامل مع الأحداث بعدة طرق عن طريق القالب أو عن طريق كلاس المُكون أو عن طريق javascript و هذا شرح الطريقة الثانية: إرسال الحدث من المكون الأول: class AppAddTask extends Component { public $title; public function render() { return view('livewire.app-add-task'); } public function addTask() { auth()->user()->tasks()->create([ 'title' => $this->title, 'status' => false, ]); $this->title = ""; $this->emit('taskAdded'); // هنا قمنا بإرسال الحدث } } التسمع على الحدث من خلال المُكون الثاني و عمل refresh: class AppTasks extends Component { protected $listeners = ['taskAdded' => '$refresh']; // التسمع و عمل تحديث public function render() { $totalTasks = auth()->user()->tasks()->count(); $tasks = auth()->user()->tasks()->latest()->get(); return view('livewire.app-tasks', [ 'totalTasks' => $totalTasks, 'tasks' => $tasks ]); } }1 نقطة
-
يوجد مشكلة في الاعتماديات المستخدمة ضمن هذه الصورة، فالصورة التي تستخدمها بشكل تلقائي لديها الاعتمادية mbstring والتي بدورها تحتاج مكتبة oniguruma لتشغيل الكود بالشكل المناسب. يجب عليك إزالة السطر: RUN docker-php-ext-install pdo mbstring وسيتم اعتماد المكتبة الافتراضية الموجودة. وللتأكد من استخدامها بالشكل الصحيح يمكن إجراء التالي: $> docker run --rm -it php:7 php -r "var_dump(mb_ereg_match('^99.*', '123456'));" bool(false) $> docker run --rm -it php:7 php -r "var_dump(mb_ereg_match('^12.*', '123456'));" bool(true) كما يجب إضافة السطر التالي للكود المرفق في آخر الملف ليتم فتح المنفذ وتجنب حدوث مشاكل ضمن docker: EXPOSE 80001 نقطة
-
1 نقطة
-
يمكنك إستخدام React Router النسخة الجديدة بهذه الطريقة، حيث أن الدالة run أصبحت غير صالحة في النسخة الجديدة، وغير محبذ ان تستخدمها. import React from 'react'; import ReactDOM from 'react-dom'; import { BrowserRouter, Route, Link, Switch } from 'react-router-dom'; function Home() { return <h1>Home</h1>; } function About() { return <h1>About Us</h1>; } ReactDOM.render( <BrowserRouter> <div> <ul> <li> <Link to="/">Home</Link> </li> <li> <Link to="/about">About</Link> </li> </ul> </div> <Switch> <Route path="/about"> <About /> </Route> <Route path="/"> <Home /> </Route> </Switch> </BrowserRouter>, document.getElementById('root') );1 نقطة
-
حاولت تطبيق مثال بسيط للغاية من موقع رياكت الرسمي، وظهر لي الخطأ التالي Uncaught Error: Invariant Violation: _registerComponent(...): Target container is not a DOM element. بالرغم من أن الكود بسيط للغاية إلا أنني لا أفهم رسالة الخطأ أو سببها، هذا الكود الخاص برياكت (المثال): <!doctype html> <html> <head> <title>Example</title> <script> var React = require('react'); var App = React.createClass({ render() { return <h1>Hello, World!</h1>; } }); React.renderComponent(<App />, document.body); </script> </head> <body> body content </body> </html> أرجو المساعدة في حل هذا الخطأ أو شرح رسالة الخطأ نفسها.1 نقطة
-
رسالة الخطأ تشير إلى أن العنصر المستخدم لعرض مكونات react غير موجود، وهذا لأن كود جافا سكريبت يتم تنفيذه قبل إنشاء العنصر body وبالتالي لا يجده. والحل هو إما وضع كل كود جافا سكريبت داخل حدث DOMContentLoaded أو الأفضل وهو نقل كل كود جافا سكريبت إلى نهاية عنصر body مع إستخدام عنصر div داخلي لعرض مكونات react بدلا من document.body1 نقطة
-
لاستقبال الدخل من المستخدم نعتمد على الصنف Scanner والذي يحوي آلية للقراءة من لوحة المفاتيح تجميع الأعداد الزوجية و الفردية كل منها في متغير خاص (عليك إكمال جزء الطرح) لمعرفة موقع أصغر قيمة، علينا أولا معرفة ما هي أصغر قيمة و عندما نجدها نحتفظ بموقعها أرجو محاولة كتابة البرنامج بنفسك أولا import java.util.Scanner; class bigest { public static void main (String[] args) { Scanner input = new Scanner(System.in); // قراءة دخل المستخدم من لوحة المفاتيخ System.out.println ("Enter 10 Numbers"); // طلب إدخال 10 قميم int numbers[] = new int[10]; // تعريف مصفوفة ل 10 عناصر for (int i = 0; i < 10 i++) { System.out.println ("Enter number " + i + ":"); numbers[i] = input.nextInt(); // قراءة القيم المدخلة بالترتيب } for (int temp : numbers){ System.out.print(temp + "\t"); // طباعة القيم مع فواصل فراغات } int EvenSum = 0; int OddSum = 0; for (int temp : numbers){ if (temp % 2 == 0) { // عدد زوجي لأن باقِ قسمتعه على 2 هو 0 EvenSum += temp; }else { // فردي OddSum += temp; } } System.out.println("Even= " + EvenSum); System.out.println("Odd= " + OddSum); int MinValue = numbers[0]; // نفترض أصغر عدد هو الأول int MinValueIndex = 0; for (int i = 1; i < 10 i++) { if (numbers[i] < MinValue ){ MinValue = numbers[i]; MinValueIndex = i; } } System.out.println("Min Value index is:" + MinValueIndex); } }1 نقطة
-
السؤال ليس صعبا، هل بدأت كتابة البرنامج لنساعدك بشكل أفضل؟1 نقطة
-
أحاول إختبار خاصية رفع فيديو عن طريق Laravel Livewire بالرغم من أن خاصية الرفع تعمل إلا أن الإختبار يفشل و لا أدر أين المُشكلة، هذا إختبار الخاصية: public function can_upload_video() { $sizeInKilobytes = 100000; $file = UploadedFile::fake()->create( 'video.mp4', $sizeInKilobytes, 'mp4' ); Storage::fake('videos_disk'); $this->actingAs(User::factory()->create()); Livewire::test(Create::class) ->set('title', 'foo') ->set('video', $file) ->call('upload'); dd(Storage::disk('videos_disk')->allFiles()); } و هذا مُكون livewire: class Create extends Component { use WithFileUploads; use DispatchesJobs; public $video; public $title, public function upload() { $this->validate([ 'title' => 'required', 'video' => 'max:1000000|required|file|mimetypes:video/mp4,video/mpeg,video/x-matroska', ]); $video = Video::create([ 'disk' => 'videos_disk', 'original_name' => $this->video->getClientOriginalName(), 'path' => $this->video->store('/', 'videos_disk'), 'streaming_path'=> null, 'title' => $this->title, ]); $this->dispatch(new ConvertVideoForStreaming($video)); } } الخاصية تعمل لكن عند تنفيذ الإختبار يُعطي مصفوفة فارغة. المُتوقع أن يعطيني مصفوفة بها الملف المرفوع.1 نقطة
-
السلام عليكم كيف يمكننى تحويل المصفوفة arr1 والتى تحتوى على روابط فقط إلى الشكل الذى تبدو عليه فى المتغير arr2 $arr1 = ["https://google.com", "https://facebook.com", "https://twitter.com"]; // $arr2 = "[\"https://google.com\", \"https://facebook.com\", \"https://twitter.com\"]"1 نقطة
-
شكراً لكم جميعاً ايها الإخوه الكرام على مساعداتكم, بارك الله فيكم جميعاً لقد نفع حل الاخ الكريم وائل1 نقطة
-
إذا كنت لا تريد تخطي العلامات، يمكنك إستخدام htmlspecialchars. مثال: <?php $arr = [ "https://google.com", "https://facebook.com", "https://twitter.com" ]; $stringified = htmlspecialchars( json_encode($arr), ENT_QUOTES, 'UTF-8' ); var_dump( $stringified ); // الشكل المطلوب هذه الصفحة تحتوي على جدول به جميع العلامات التي يمكن حفظها: https://www.php.net/manual/en/function.htmlspecialchars.php1 نقطة
-
هذا غالباً يحدث بسبب فشل ال validation حيث أنك تتحقق من mime type لكن في الإختبار الملف الوهمي لا يحتوي على نفس mime type هنا: <?php $file = UploadedFile::fake()->create( 'video.mp4', $sizeInKilobytes, 'mp4' ); لذلك حاول تغيير هذه الأسطر: <?php $file = UploadedFile::fake()->create( 'video.mp4', $sizeInKilobytes, 'mp4' ); إلى mime type صحيح بهذا الشكل: <?php $file = UploadedFile::fake()->create( 'video.mp4', $sizeInKilobytes, 'video/mp4' );1 نقطة
-
هل تقصد تحويلها إلى String عن طريق json_encode؟ تمكنك دالة json_encode من تحويل Data Structures من PHP إلى JSON. مثال: <?php $links = [ "https://google.com", "https://facebook.com", "https://twitter.com" ]; echo json_encode( $links ); أيضاً، يمكنك عكس ذلك عن طريق json_decode.1 نقطة
-
1 نقطة
-
يجب تفعيل نظام ويندوز عن طريق الترخيص، كشراء رخصة من شركة مايكروسوفت ثم تثبيتها في النظام لديك1 نقطة
-
1 نقطة
-
في الحقيقة هناك عدة طرق, فيمكنك تطبيق الشرط التالي على متغير $imageName بحيث إذا كان فارغ لا يعدله , ويعدل الحقول الأخرى أما إذا كان يحتوي على قيمة فيعدل جميع الحقول, بحيث تصبح <?php $company = Company::find($id) ->update([ "company_name" => $request["company_name"], "former_company" => $request["former_company"], "company_logo" => $imageName, ]); هكذا <?php $company = Company::find($id); if($imageName != null){ $company->update([ "company_name" => $request["company_name"], "former_company" => $request["former_company"], "company_logo" => $imageName, ]); } else { $company->update([ "company_name" => $request["company_name"], "former_company" => $request["former_company"], ]); }1 نقطة
-
نعم يُمكنك عمل ذلك بإستخدام بإستخدام مُعامل الشرط الثلاثي داخل الدالة update كما هو موضح أدناه: <?php Company::find($id)->update([ 'company_name' => $request->company_name, 'former_company' => $request->former_company ] + ($imageName ? [ 'company_logo' => $imageName ] : [])); و هذا يعني أننا نريد إضافة مصفوفة جديدة للمصفوفة الأولى تضم الحقل company_name في حالة ما إذا كان imageName لا يساوي null أما في الحالة المُعاكسة نضيف مصفوفة فارغة. أو يُمكنك إستخدام التالي: <?php Company::find($id)->update($request->only('company_name', 'former_company') + ($imageName ? [ 'company_logo' => $imageName ] : [])); هذا بطريقة مُختصرة يُمكنك أيضاً إنشاء المصفوفة خارج الدالة update. ثم تتفحص إن كان imageName يساوي null و على أساسه تضيف حقل جديد للمصفوفة ثم تمررها للدالة update1 نقطة
-
إن ظهور Kill في composer وتوقفه هو دليل على أن الإجرائية تقوم باستهلاك موارد كبيرة بالنسبة للمتوفرة على الجهاز، فلذلك ستحتاج لإضافة المزيد من الموارد Ram على جهازك إن أمكن. والسعة المفضلة لذلك هي حوالي 700MB بأقل حد. ولكن في حال كنت تقوم بالإجرائية على خادم الويب مباشرةً، فلا يجب أبداً إجراء composer update. بدلاً من ذلك: قم بإجراء composer update على جهازك المحلي (بيئة التطوير) فسيكون لديك موارد أكبر من الموجودة على خادم الويب في حال كانت موارده قليلة. ثم قم بنقل المشروع عن طريق استخدام git push. ثم قم بإجراء composer install على الخادم. حيث سيقوم الإجراء composer install بالقراءة من ملف .lock واستخدام جميع الإصدارات التي تم تعريفها ضمن المشروع بدلاً من البحث عن آخر إصدارات من جميع المكاتب المضمنة ضمن المشروع و المستخدمة أيضاً في بناء Laravel. وذلك بدوره سيخفف من العبء على الذاكرة والموارد الموجودة على الجهاز. بشكل ممثائل، يمكنك رفع مجلد Vendor مباشرةً ضمن المشروع إلى الخادم، وبالتالي ستستغني عن الحاجة لإجراء composer install على الخادم أيضاً. ولكن عندها يجب عليك القيام بالأمر التالي بعد إجراء عملية النقل: composer dump-autoload --optimize وأيضاً من إحدى الحلول هي بإنشاء swap file. مثال بسيط: mkdir -p /var/_swap_ cd /var/_swap_ #1M * 2000 ~= 2GB of swap memory. هنا يتم إضافة dd if=/dev/zero of=swapfile bs=1M count=2000 chmod 600 swapfile mkswap swapfile swapon swapfile #لتشغيلها بشكل أوتوماتيكي عند الإقلاع echo "/var/_swap_/swapfile none swap sw 0 0" >> /etc/fstab1 نقطة
-
تعني رسالة killed أن العملية استهلكت قدرا كبيرا من الذاكرة لذلك تحتاج إلى إضافة المزيد من الذاكرة إلى نظامك. يمكنك إضافة المكتبة إلى مجلد vendor يدويا ومن ثم يجب تشغيل الأمر التالي composer dump-autoload --optimize يمكنك من ملف php.ini من تغيير قيمة memory_limit إلى 4G1 نقطة
-
مرحباً يخبرك الخطأ بالتالي: Component template should contain exactly one root element. If you are using v-if on multiple elements, use v-else-if to chain them instead. لديك في أحد ملفات العناصر (الكائنات component) عنصرا فيه أكثر من عنصر داخل وسم ال template لذلك قم بالتاكد من وجود عنصر ابن واحد فقط داخل وسم ال template ، ثم ضع بقية العناصر التي تريدها بداخل هذا الابن مهما كان عددها. مثلا هذا الكود سيعطيك خطأ: <template> <div class=""> </div> <div class=""> </div> </template> ولتصحيحه قم بوضع عنصر ابن واحد داخل template كالتالي: <template> <div class=""> <div class=""> </div> <div class=""> </div> </div> </template>1 نقطة
-
إن الخطأ Component template should contain exactly one root element يظهر فقط عندما يتم استخدام أكثر من عنصر على مستوى الجذر ضمن الصفحة الواحدة أو المكوّن الواحد. في حال كنت تستخدم نسخة Vue 2.0 فيوجد قيد على العنصر الجذر ضمن الصفحة أو المكوّن، وهو بأن يكون عنصر واحد فقط، على الشكل التالي: <div> <div class="form-group"> ... </div> <div class="col-md-6"> ... </div> </div> بدلاً من أن يكون أكثر من عنصر على مستوى الجذر في المكوّن أو الصفحة الواحدة، أي على الشكل التالي: <div class="form-group"> ... </div> <div class="col-md-6"> ... </div> //-> سيسبب خطأ ولكن تم إزالة هذا القيد في النسخة الجديدة من Vue 3.0 وأصبح بالإمكان استخدام أكثر من عنصر على مستوى الجذر في الملف أو المكون الواحد. يوجد أيضاً حل آخر باستخدام إضافة: vue-fragment ، يتم تحميلها كالتالي: npm install vue-fragment ولاستخدامها نقوم بتضمنيها كالتالي: import Fragment from 'vue-fragment'; Vue.use(Fragment.Plugin); // or import { Plugin } from 'vue-fragment'; Vue.use(Plugin); ثم يمكننا وضع أكثر من عنصر ضمن الـ fragment: <template> <fragment> <tr class="hola"> ... </tr> <tr class="hello"> ... </tr> </fragment> </template>1 نقطة
-
1 نقطة
-
هل يجب أن يتم الدفع بعملة الدولار؟ نظرًا لأنّ حسابي البنكي لا يوفر سوى العملة المصريّة...1 نقطة
-
هل تنصح مطور واجهات المستخدم Front-end أن يَدرس هذه اللغات : VueJs / AngularJs / ReactJs ؟ أم تنصح بدراسة : PHP / LARAVEL / WORDPRESS .1 نقطة
-
لديك مشكلتين أساسيتين في الكود الذي وفرته الاولى هي خطأ في التعديل والثانية هي أنك تحدد ال cake يدويا بالنسبة لمشكلتك الاولى فالحل بسيط case SELL_ONE_CAKE: const newCakes = [ ...state.cakes ]; نسخ القائمة newCakes[0].qty -= 1; تعديل على القائمة return { ...state, cakes: newCakes }; لصق القائمة أما لمشكلة التعديل اليدوي فيكنك توفير ال id مثلا عندما تقوم بعمل dispatch ثم تقوم باستخدام filter لتحصل على ال index للقيام بعملية التعديل case SELL_ONE_CAKE: let newCakes = state.cakes.filter((cake,i)=> { if (cake.id === action.payload.id) { index = i; //index is global var } return cake.id !== action.payload.id }) let modifiedCake = {...state.cake[index],qty:state.cake[index].qty - 1} newCakes.splice(index, 0, modifiedCake); return { ...state, cakes: newCakes };1 نقطة
-
1 نقطة
-
الطريقة التي تعدل بها خاطئة فهنا أنت سيكون الناتج كالآتي // الجزء الأول صحيح حيث أنك تستخدم الحالة السابقة لكن عند إضافة cakes // فأنت لا ترجعها مصفوفة وإنما رقم لأنك أسندتها إلى رقم { ...state, cakes: state.cakes[0].qty - 1 }; // ليكون الناتج /* { cakes: 39 } */ الحل هو أنك تقوم بالتعديل على ال cakes وتقوم بإرجاع ال array ثم إعطائه لل state case SELL_ONE_CAKE: const modifiedCakes = [ ...state.cakes ]; modifiedCakes[0].qty -= 1; return { ...state, cakes: modifiedCakes }; وبهذا يتم تعديل الرقم وترجع الحالة كما هي1 نقطة
-
اهلا صديقي.. القراءة هي المفتاح.. ابحث عن كتب وصفحات تتحدث عن المحتوى الذي تقدمه.. اقرأ واقرأ بتمعن.. ليصبح لديك الخبرة الكبيرة والقدرة على كتابة وصناعة محتوى حصري خاص بك ويتميز بأسلوبك.. وهذا الذي يجذب أعداد متابعين للحقيقة.. اقترح عليك أيضا الاتجاه إلى مجال نشر فيديوهات لأنها تشد المتابع أكثر من البوستات أتوقع (وخصوصا في البداية) يمكنك أيضا حينها البحث عن أشخاص يقدمون محتوى يشبه المحتوى الذي تقدمه من بلدك.. ثم عمل لقاءات معاً بشكل فيديوهات تنشرها على قناة يوتيوب .. يمكنك هكذا جذب متابعيك ومتابعيه.. لأن الفيديو يجذب ويشد متابعين اكثر.. اتمنى لك كل التوفيق1 نقطة
-
غالبية مُستخدمِي الحاسوب غَيْر مُعتَادون في العموم على برامج سطر الأوامر (command-line programs)، حيث يَجدُون أسلوب التَفاعُل القائم على تَناوُب الحاسوب والمُستخدِم على كتابة النصوص غَيْر مألوف. منذ منتصف الثمانينات، أُتيحَت الحواسيب المنزلية المُدعِّمة لواجهات المُستخدِم الرُسومية (graphical user interfaces)، والتي تُوفِّر للمُستخدِم واجهة أكثر ثراءً يَتَمكَّن من خلالها من اِستخدَام أدوات إِدْخَال مُتعدِّدة مثل الفأرة ولوحة المفاتيح وغيرها للتَفاعُل مع مجموعة من مُكوِّنات الواجهة مثل النوافذ والقوائم والأزرار وصناديق الإِدْخَال النصية وشرائط التمرير وغيرها. سنتناول خلال هذا القسم بعضًا من أساسيات برمجة الواجهات باِستخدَام مكتبة جافا إف إكس (JavaFX) من خلال دراسة تطبيق بسيط يَعرِض وَاجهة مُكوَّنة من نافذة (window) تَحتوِي على رسالة نصية وثلاثة أزرار كما هو مُبيَّن بالصورة التالية. لاحِظ أننا قد اِستخدَمنا مصطلح تطبيق (application) وليس برنامج (program) ضِمْن هذا السياق. إذا ضَغَطت على زر "Say Hello"، سيَرُد الحاسوب بالرسالة "Hello World!" أما إذا ضَغَطت على زر "Say Goodbye"، فسيَتَغيَّر نص الرسالة إلى "Goodbye". تستطيع إغلاق التطبيق إما بالنَقْر على زر "Quit" أو على زر غَلْق النافذة. تطبيقات جافا إف إكس (JavaFX) تَحتوِي حزمة javafx.application على الصَنْف المُجرّد (abstract class) Application، والذي يَحتوِي على تابع النُسخة (instance method) المُجرّد start() من بين أشياء أخرى. لكي تُنشِئ تطبيق جافا إف إكس (JavaFX application)، ينبغي أن تُعرِّف صنفًا جديدًا مُمثِلًا للتطبيق. لابُدّ أن يتوسَّع (extend) الصَنْف الجديد من الصَنْف Application كما لابُدّ أن يُوفِّر تعريفًا (definition) للتابع start(). (اُنظر كُلًا من القسمين الفرعيين "توسيع (extend) الأصناف الموجودة"، و "الأصناف المجردة (abstract classes)" من الفصل "الوراثة والتعددية الشكلية (Polymorphism) والأصناف المجردة (Abstract Classes) في جافا"). سيَحتوِي الصَنْف أيضًا على التابع main()، والذي سيتولَّى مُهِمّة تّنْفيذ التطبيق، ويُكْتَب عمومًا على النحو التالي: public static void main(String[] args) { launch(args); } عندما يُنفِّذ الحاسوب البرنامج main()، سيُنشِئ التابع launch() خيطًا (thread) جديدًا يُعرَف باسم خيط تطبيق جافا إف إكس (JavaFX application thread). كما ذَكَرَنا بالقسم ١.٢، يَضُمّ كل خيط متتالية من التَعْليمَات يُمكِن تّنْفيذها بالتوازي مع خيوط أخرى. ينبغي عمومًا لأي شيفرة تَتَعامَل مع واجهة مُستخدِم رسومية (GUI) أن تَقَع ضِمْن خيط تطبيق جافا إف إكس، وهو ما سيَحدُث أتوماتيكيًا فيما يَتعلَّق بما سنقوم به ضِمْن هذا الفصل، ولكن عندما ننتقل إلى الحديث عن الخيوط (threads) تفصيليًا بالفصل ١٢، سنُطوِّر تطبيقات واجهة مُستخدِم رسومية (GUI) تَستخدِم أكثر من خيط، وعندها ستَّضِح أهمية ذلك. سيُنشِئ التابع launch() الكائن المُمثِل للتطبيق، وهو في الواقع من نفس صنف التابع، ثم سيَستدعِي تابعه start()، والذي تُوكَل له مُهِمّة تجهيز واجهة المُستخدِم الرسومية (GUI)، ومن ثَمَّ فَتْح نافذة (window) بالشاشة. تستطيع إصدارات معينة من الجافا أن تُشغِّل تطبيقات جافا إف إكس (JavaFX) حتى لو لم تَتَضمَّن التابع main()، ولكن لا تَعتمِد على ذلك، واِحرِص دومًا على كتابة التابع main() ضِمْن التطبيقات الخاصة بك، وهو ما سنلتزم به. ها هي شيفرة التطبيق التي سنُناقِشها تفصيليًا بهذا القسم: import javafx.application.Application; import javafx.scene.Scene; import javafx.stage.Stage; import javafx.application.Platform; import javafx.scene.layout.BorderPane; import javafx.scene.layout.HBox; import javafx.geometry.Pos; import javafx.scene.control.Label; import javafx.scene.control.Button; import javafx.scene.text.Font; public class HelloWorldFX extends Application { public void start(Stage stage) { Label message = new Label("First FX Application!"); message.setFont( new Font(40) ); Button helloButton = new Button("Say Hello"); helloButton.setOnAction( e -> message.setText("Hello World!") ); Button goodbyeButton = new Button("Say Goodbye"); goodbyeButton.setOnAction( e -> message.setText("Goodbye!!") ); Button quitButton = new Button("Quit"); quitButton.setOnAction( e -> Platform.exit() ); HBox buttonBar = new HBox( 20, helloButton, goodbyeButton, quitButton ); buttonBar.setAlignment(Pos.CENTER); BorderPane root = new BorderPane(); root.setCenter(message); root.setBottom(buttonBar); Scene scene = new Scene(root, 450, 200); stage.setScene(scene); stage.setTitle("JavaFX Test"); stage.show(); } // end start(); public static void main(String[] args) { launch(args); // Run this Application. } } // end class HelloWorldFX عادةً ما تَستخدِم تطبيقات جافا إف إكس (JavaFX) أصنافًا عديدة، غالبيتها مُعرَّف بحزم javafx الفرعية (subpackages)، ولهذا ستُلاحِظ وجود عدد كبير من تَعْليمَات الاستيراد import ببداية أي من تطبيقاتها كالمثال بالأعلى. سنَذكُر دومًا الحزمة التي يَقَع بها صَنْف معين عندما نَتَعرَّض له لأول مرة كما تستطيع البحث عن أي صَنْف منها بـ توثيق واجهة برمجة تطبيقات جافا إف إكس (JavaFX API). يحتوي الصنف المُمثِل للتطبيق HelloWorldFX -بالأعلى- على التابع main المسئول عن بدء تّنْفيذ التطبيق، بالإضافة إلى التابع start(). نُضيف عادةً توابعًا آخرى لذلك الصنف بحيث يَستدعِيها التابع start() عند تّنْفيذه. علاوة على ذلك، يَحتوِي الصنف المُجرّد Application على عددًا من التوابع (methods) الآخرى، التي يُمكِنك إعادة تعريفها (override) كالتابعين init() و stop(). يَستدعِي النظام init() قبل استدعاء start()، بينما يَستدعِى stop() عندما يَكُون التطبيق على وشك الإغلاق. في حين أن تعريفهما ضِمْن الصَنْف Application لا يَتَضمَّن أي شيء فعليّ، تستطيع أن تُعيد تعريفهما لإجراء بعض التهيئة المبدئية (initialization) أو لإجراء أي تنظيف (cleanup) ضروري. ومع ذلك، يُمكِن تّنْفيذ أي تهيئة مطلوبة ضِمْن التابع start()، لذا نادرًا ما سنلجأ إليهما. المرحلة Stage والمشهد Scene ومبيان المشهد SceneGraph تُوفِّر حزمة javafx.stage الصَنْف Stage، والذي يُمثِل أي كائن منه نافذةً (window) على شاشة الحاسوب. يُنشِئ النظام كائن مرحلة (stage) من ذلك الصَنْف، ويُمرِّره كمُعامِل (parameter) إلى التابع start(). يُمثِل كائن المرحلة، في تلك الحالة تحديدًا، نافذة البرنامج الرئيسية، ويُشار إليه عادةً باسم "المرحلة الرئيسية (primary stage)". قد يُنشِئ البرنامج كائنات مرحلة (stage) آخرى من نفس الصَنْف إذا أراد فَتْح نوافذ آخرى. تُعدّ أي نافذة (window) بمثابة مساحة ضِمْن شاشة الحاسوب، والتي يُمكِن مَلْؤها بمحتوى معين، فمثلًا قد نَملْؤها ببعض مما يُعرَف باسم مُكونات واجهة المُستخدِم الرُسومية (GUI components) كالقوائم، والأزرار، وصناديق الإِدْخَال النصية، ومساحات الرسم (drawing areas) التي كنا قد اِستخدَمناها ببعض البرامج الرسومية بالقسم ٣.٩. كما ذَكَرَنا مُسْبَقًا، يُنشِئ النظام كائنًا من الصنف Stage، ليُمثِل النافذة الرئيسية -ويُعرَف باسم "المرحلة الرئيسية (primary stage)"- قبل استدعاء التابع start()، ومع ذلك تَكُون تلك النافذة (window) ما تزال فارغة وغَيْر مرئية إلى حين استدعائه، وتُوكَل إليه في الحقيقة مُهِمّة مَلْؤها بالمحتوى المناسب، ومن ثَمَّ إظهارها على الشاشة. فمثلًا، بتطبيق HelloWorldFX بالأعلى، يُظهِر السطر الأخير من التابع start() -أيّ التعبير stage.show()- النافذة على الشاشة بينما تُنشِئ أسطر التابع الآخرى المحتوى، وتُضيفه إلى النافذة إلى جانب ضَبْط بعض الخيارات المُتعلِّقة بكُلًا من المحتوى والنافذة ذاتها، فمثلًا، تَضبُط الشيفرة التالية نص شريط عنوان النافذة: stage.setTitle("JavaFX Test"); تتكوَّن أي مرحلة (stage) -تُمثِل نافذة- من مساحة لعَرْض المحتوى (content area)، والتي يُمكِن مَلْئها بـ"مشهد (scene)" يَضُمّ مُكونات واجهة المُستخدِم الرسومية (GUI components) المُفْترَض عَرْضها بالنافذة. تُوفِّر حزمة javafx الصَنْف Scene، والذي يُمثِل أي كائن منه مشهدًا (scene). يُمكِننا ضَبْط المشهد (scene) المُفْترَض عَرْضه بمساحة المحتوى (content area) الخاصة بمرحلة معينة (stage) باِستخدَام التَعْليمَة التالية: stage.setScene(scene); يُمكِنك أن تمَلْئ أي مشهد (scene) بمُكوِّنات واجهة المُستخدِم الرسومية (GUI components) كالأزرار وأشرطة القوائم وغيرها. تُوفِّر منصة جافا إف إكس (JavaFX) صَنْفًا لكل مُكوِّن منها، فمثلًا، يُمكِنك أن تَستخدِم كائنًا من الصنف Button من حزمة javafx.scene.control لتمثيل "زر ضغط (push button)" مثل الزر "Say Hello" بالتطبيق السابق. بالإضافة إلى ذلك، تُوفِّر منصة جافا إف إكس (JavaFX) أصنافًا لمُكوِّنات تَعمَل بمثابة حاويات (containers) تُمثِل قسمًا من النافذة (window) مثل الكائن buttonBar من النوع HBox. قد يَشتمِل ذلك القسم من النافذة على مُكوِّنات واجهة آخرى بما في ذلك أي مُكوِّن حَاوِي آخر. بتعبير آخر، قد تحتوي نافذة معينة على عدد من مُكوِّنات واجهة المُستخدِم الرسومية داخل حاويات (containers) تَقَع بدورها ضِمْن حاويات أكبر، وجميعها مُمثَل بواسطة كائن. تُشكِّل كل تلك الكائنات ما يُعرَف باسم "مبيان المشهد (scene graph)"، والذي يُبيِّن علاقات الاحتواء بين جميع مُكوِّنات المشهد (scene). تُبيِّن الصورة التالية "مبيان المشهد (scene graph)" للتطبيق السابق: لا تُمثِل الصورة بالأعلى سلالة أصناف (class hierarchy) كما قد تَظُنّ، فهي لا تُبيِّن العلاقات بين أصناف تلك الكائنات، وإنما هي بمثابة تَسَلسُل هرمي لعلاقات الاحتواء (containment hierarchy) بين تلك الكائنات، أي تُبيِّن الكيفية التي تَتَضمَّن بها بعض مُكوِّنات المشهد البعض الآخر. فمثلًا، يَتَّضِح من مبيان المشهد (scene graph) أن كُلًا من root و buttonBar عبارة عن مُكوِّنات حاوية (containers) أما message بالإضافة إلى الأزرار الثلاثة فهي مُجرّد مُكوِّنات بسيطة. يَحتوِي أي مشهد (scene) على مُكوِّن جذري (root component) وحيد. هذا المُكوِّن هو عبارة عن حَاوِي (container) لجميع المُكوِّنات الآخرى الموجودة بالمشهد. أطلقنا الاسم root على المُكوِّن الجذري بالتطبيق السابق، ويُمكِنك بالطبع أن تختار أي اسم آخر تُفضِّله. يُمكِنك ضَبْط المُكوِّن الجذري لمشهد معين بينما تُنشِئ كائن الصنف Scene كالتالي: Scene scene = new Scene(root, 450, 200); تُحدِّد الأعداد المُمرَّرة لهذا الباني (constructor) كُلًا من عرض المشهد وارتفاعه بوحدة البكسل (pixel). يُمكِنك حَذْف تلك الأعداد، وفي تلك الحالة، ستُحسَب مساحة المشهد بما يتناسب مع محتوياتها. العقد (nodes) والتخطيط (layout) يتكوَّن أي مبيان مشهد (scene graph) من مجموعة من الكائنات، تُعرَف باسم "العُقَد (nodes)". لابُدّ أن تنتمي تلك الكائنات إلى إحدى الأصناف الفرعية (subclasses) المُشتقَّة من الصَنْف javafx.scene.Node، وقد يَعمَل بعضها كمُكوِّنات حاوية (container)، وفي تلك الحالة، لابُدّ لها من أن تنتمي إلى إحدى الأصناف الفرعية المُشتقَّة من الصَنْف javafx.scene.Parent، والذي هو بدوره صنف فرعي من نفس الصنف Node. لمّا كانت العُقْدة الجذرية (root node) تَعمَل كمُكوِّن حاوي، فلابُدّ أن تَكُون من الصنف Parent. تَشتمِل العُقَد المُمثلة لمُكوِّنات حاوية (containers) على مجموعة من العُقَد (nodes) الآخرى، والتي تُعدّ أبناءً (children) لها. بتطبيق HelloWorldFX السابق، اِستخدَمنا كائنات من النوع Button لتمثيل الأزرار. في الواقع، هذا الصنف هو صنف فرعي (subclass) من الصنف Parent، وسنرى لاحقًا أن بإمكانه أن يَتَضمَّن عُقَدًا (nodes) آخرى. يَستقبِل باني (constructor) الصنف Button مُعامِلًا لتَخْصِيص النص المكتوب على الزر. بالمثل، message هو عبارة عن كائن عُقْدة (node) من النوع Label المُعرَّف بحزمة javafx.scene.control، ويُستخدَم لعَرْض سِلسِلة نصية من النوع String. يَتَضمَّن أي كائن عُقْدة من الصنف Label على خاصية نوع الخط، والتي تَتَحكَّم بحجم محارف السِلسِلة النصية، وهيئتها، ويُمكِن ضَبْطها باِستخدَام التابع setFont() المُعرَّف بنفس الصنف. بالتطبيق السابق، اِستخدَمنا الباني new Font(40)، والذي يُحدِّد مُعامِله (parameter) الوحيد حجم الخط المطلوب. المُكوِّنات الحاوية (containers) هي أيضًا عُقَد (nodes) من النوع Node، ولكن يُمكِنها أن تَشتمِل على عُقَد آخرى كأبناء (children)، ويُشار إلى الكيفية التي يُرتَّب بها هؤلاء الأبناء على الشاشة باسم "التخطيط (layout)". يعني التخطيط (layout) عمومًا ضَبْط كُلًا من حجم المُكوِّنات الواقعة ضِمْن الحاوي ومَوضِعها. على الرغم من تَوفُّر إمكانية لضَبْط تلك القيم بصورة مباشرة، فلربما تُفضِّل الاعتماد على ضَبْطها أتوماتيكيًا بالاستعانة بالمُكوِّن الحاوي (container) نفسه، وفي الواقع، تُعدّ تلك الطريقة أكثر شيوعًا. عمومًا، يُطبِق كل مُكوِّن حاوي سياسة تخطيط (layout policy) مختلفة، فمثلًا، تُرتِّب المُكوِّنات الحاوية من الصنف HBox مُكوِّناتها ضِمْن صف أفقي. اُنظر الباني (constructor) التالي: HBox buttonBar = new HBox( 20, helloButton, goodbyeButton, quitButton ); تُمثِل جميع مُعامِلات (parameter) ذلك الباني فيما عدا الأول عُقَدًا (nodes) ينبغي إضافتها كأبناء (children) للمُكوِّن الحاوي (container)، بحيث يَفصِل بينها فراغًا تُحدِّد مساحته القيمة المُمرَّرة لمُعامِل الباني الأول. في المقابل، تُطبِق المُكوِّنات الحاوية من الصنف BorderPane سياسة تخطيط (layout policy) مختلفة تمامًا. يستطيع أي مُكوِّن حاوي منها أن يحتوى على ما يَصِل إلى ٥ مُكوِّنات (components)، واحدة بالمنتصف، أما البقية فبالأعلى وبالأسفل وعلى اليسار وعلى اليمين. بالتطبيق السابق، كان المُكوِّن الجذري للمشهد عبارة عن مُكوِّن حاوي من الصنف BorderPane، واستخدمنا التَعْليمَات التالية لإضافة مُكوّنات آخرى إلى منتصفه والجزء السفلي منه: root.setCenter(message); root.setBottom(buttonBar); تتوفَّر أيضًا الكثير من الخيارات لضَبْط التخطيط (layout)، فمثلًا يَستخدِم التطبيق السابق إحداها بالتَعْليمَة التالية: buttonBar.setAlignment(Pos.CENTER); تُستخدَم تلك التَعْليمَة لوَضْع الأزرار بمنتصف مُكوّن حاوي من الصنف HBox؛ فبدونه، ستَقَع الأزرار على حافة النافذة اليسرى. تعتمد منصة جافا إف إكس (JavaFX) على أنواع التعداد (enumerated type) بكثرة، والتي كنا قد ناقشناها بالقسم الفرعي ٢.٣.٤، وذلك لتخصيص الخيارات المختلفة، مثل نوع التعداد Pos بالشيفرة السابقة. الأحداث (event) ومعالجاتها (handlers) لا يَقْتصِر دور التابع start() على ضَبْط تخطيط (layout) النافذة، وإنما يُستخدَم أيضًا لضَبْط ما يُعرَف باسم "معالجة الحَدَث (event handling)". مثلًا، بتطبيق HelloWorldFX بالأعلى، عندما يَنقُر المُستخدِم على زر معين، يَقَع ما يُعرَف باسم "الحَدَث (event)"، ويُمكِن عندها للتطبيق أن يُعالِج (handle) ذلك الحَدَث من خلال ما يُعرَف باسم "مُعالِجات الأحداث (event handlers)". تَشتمِل معالجة أي حَدَث على كائنين، يُعبِر الأول عن الحَدَث نفسه ويَحمِل معلومات عنه، فمثلًا، عند النقر على زر، يَكُون كائن الحَدَث من النوع ActionEvent ويَحمِل معلومات عن الزر المنقور عليه. أما الكائن الآخر فيُعبِر عن مُعالِج الحدث، ويَكُون من نوع واجهة نوع الدالة EventHandler، والتي تُعرِّف التابع handle(e) حيث e هو كائن الحَدَث. والآن لكي تُعالِج حَدَثًا معينًا، ينبغي أن تُنشِئ صنفًا يُنفِّذ (implements) الواجهة EventHandler، ويُوفِّر تعريفًا للتابع handle(). ولكن لمّا كانت EventHandler عبارة عن واجهة نوع دالة (functional interface)، فيُمكِن كتابة المُعالِج (handler) بصورة تعبير لامدا (lambda expression). كنا قد ناقشنا تعبيرات لامدا تفصيليًا بالقسم ٤.٥، وهي في العموم شائعة الاِستخدَام بتطبيقات جافا إف إكس (JavaFX)، فتُستخدَم لكتابة مُعالِجات الأحداث (event handlers) من ضِمْن عدة استخدامات آخرى. اُنظر تعبير لامدا التالي على سبيل المثال: e -> message.setText("Hello World!") يُمثِل ذلك التعبير مُعالِج حَدَث (event handler) يَستجيب لحَدَث (event) ما بتغيير نص الرسالة إلى "Hello World". يَستقبِل ذلك المُعالِج مُعامِلًا e، يُمثِل الحَدَث، ويَكُون من النوع ActionEvent، والذي لابُدّ من كتابته دائمًا حتى لو لم يَستخدِمه المُعالِج كالمثال بالأعلى؛ وذلك ليَستوفِي صيغة تعبير اللامدا (lambda expression). ينبغي الآن أن نُسجِّل (register) مُعالِج الحَدَث (event handler) بَعْد كتابته بالكائن المُنتج للحَدَث. فمثلًا بنفس المثال، كان الكائن هو helloButton، ونستطيع أن نُسجِّل المُعالِج (handler) باستدعاء تابع الكائن setOnAction()، كالتالي: helloButton.setOnAction( e -> message.setText("Hello World!") ); ضَبطَنا أيضًا مُعالجي (handlers) الزرين الآخرين بنفس الطريقة. لاحِظ أن لدينا ثلاثة كائنات: كائن مُنتج للحَدَث (event) نتيجة لفعل (action) قام به المُستخدِم، وكائن يُمثِل الحَدَث ذاته، وأخيرًا كائن يُمثِل مُعالِج الحَدَث (event handler) كما يَحتوِي على الشيفرة المطلوب تّنْفيذها استجابةً للحَدَث (event)، كما هو مُوضَح بالصورة التالية: يَتبقَّى لنا فقط توضيح الاستجابة على فعل (action) النقر على زر "Quit"، اِستخدَمنا التعبير Platform.exit() لاستدعاء التابع الساكن exit() المُعرَّف بالصنف Platform. يُفضَّل عمومًا اِستخدَام تلك الطريقة للإنهاء البرمجي لتطبيقات جافا إف إكس (JavaFX)؛ لأنها تُغلِق خيط التطبيق (application thread)، كما تَستدعِي التابع stop() المُعرَّف بالصنف المُمثِل للتطبيق، مما يُعطِي فرصة للمبرمج لإجراء أي تنظيف (clean up) قد يَرغَب به قَبْل الإغلاق، وذلك بخلاف التابع System.exit() مثلًا. يُعدّ هذا القسم بمثابة نظرة عامة ومُختصرة لتطبيقات جافا إف إكس (JavaFX)، ومع ذلك فقد تَعرَّضنا خلالها للكثير من المفاهيم الأساسية. بالأقسام التالية، سنتناول كل ذلك على نحو تفصيلي. ترجمة -بتصرّف- للقسم Section 1: A Basic JavaFX Application من فصل Chapter 6: Introduction to GUI Programming من كتاب Introduction to Programming Using Java.1 نقطة
-
وعليكم السلام اولاً : حتى تنجح في صناعة المحتوى يجب أن تركز على مجال واحد وتبتعد عن النسخ واللصق و أن تكون متميزاً حتى تتمكن من الحصول على متابعين لمنشوراتك. ثانياً : بعد أن تحدد المجال الذي تكتب فيه أو المجالات التي تكتب فيها يجب أن تركز على ثلاثة أشياء منها يمكنك إستخلاص الافكار التي تكتب عنها: جديد المجال أو الاخبار المتعلقة بالمجال فمثلاً إذا اخترت مجال الرياضة فاحرص على أن تقوم بكتابة منشور عن نتائج او ملخص مباريات اليوم وإذا اخترت التكنولوجيا فاكتب عن احدث التقنيات في العالم. الاخبار او المعلومات النادرة او بمعنى اخر ان تكتب المنشورات ذات الطابع التشويقي كأن تكتب عن قصة اغرب ثلاثة اسباب جعلت اللاعبين يعتزلون كرة القدم او ان تكتب هل ستحكم الروبوتات العالم اذا كنت اخترت مجال التكنولوجيا. ان تكتب عن تاريخ المجال و لكن يفضل ان تكتب بصورة منفردة عن الموجودة على الانترنت اي ان تجمع المعلومات بنفسك وتحاول صياغة مقالاتك الخاصة .1 نقطة