اذهب إلى المحتوى

محمد Albittar

الأعضاء
  • المساهمات

    14
  • تاريخ الانضمام

  • تاريخ آخر زيارة

كل منشورات العضو محمد Albittar

  1. تعلمنا في الدرس السابق حول تصميم واجهات إدخال البيانات باستخدام مايكروسوفت إكسل VBA كيفية تصميم واجهة إدخال البيانات وتوزيع الكائنات، وتنسيقها وتجهيزها لعملية البرمجة، وكذا ربطها بخلايا الصفحة التي ستُرحَّل إليها البيانات عند الضغط على زر الإدخال. وفي هذا المقال سنتعرف على كيفية برمجة هذه الواجهت باستخدام مايكروسوفت إكسل VBA. كتابة الإجراءات الخاصة بالكائنات لتحرير الشيفرة البرمجية الخاصة بالكائن نضغط على الكائن نقرةً مزدوجةً، لتظهر لدينا النافذة التي نكتب فيها الشيفرات والإجراءات مثل العادة. مثال لفهم آلية البرمجة بالتفصيل سنُبرمج الواجهة التي صممناها مسبقًا، ولكن في البداية يجب تجهيز صفحة استقبال البيانات في ملف الإكسل، فتصبح واجهة الإدخال وصفحة الإكسل كالتالي: والآن سنحرر واجهة كتابة الشيفرات الخاصة بزر الإدخال، ونبدأ بكتابة التعليمات الخاصة بترحيل البيانات إلى صفحة الإكسل، وهنا نلاحظ أن الإجراء الموجود فيها هو إجراء يُنفذ عند النقر على الزر. والآن نُقسّم الشيفرة إلى أجزاء صغيرة ليسهل علينا التفكير في آلية إنشائها، والعمل الفعلي للواجهة هو جمع البيانات التي نُدخلها عبر كائناتها وترحيلها إلى صفحة الإكسل، ووضعها في السطر الأخير، لذا يجب علينا في البداية معرفة كيف يمكننا معرفة رقم السطر الأخير غير الفارغ، ثم نُرحل البيانات للسطر الذي يليه، ولمعرفة رقمه نَعُدّ الأسطر غير الفارغة ضمن الصفحة كالتالي: نُعرّف متغير من النوع integer، أو من النوع long، ونُخزن فيه عدد الأسطر غير الفارغة كما يلي: Private Sub btnAdd_Click() Dim LastRow As Long End Sub نكتب الدالة المسؤولة عن عدّ الخلايا غير الفارغة، وهي الدالة CountA، ولكن لاستدعائها ضمن الإجراء نكتبها بالشكل التالي: LastRow = WorksheetFunction.CountA(Sheets("الموظفون").Range("A:A")) كما نلاحظ تُستدعى الدوال الأساسية في إكسل عن طريق الفيجوال بيسك بأن نضع قبلها التعليمة WorksheetFunction، لكن هنا عند تحديد المجال يجب أن نُعرّف مساره كاملًا ابتداءً من اسم الصفحة كما في التعليمة السابقة، حيث نضع: Sheets("الموظفون").Range("A:A") أي أن المحرر يستدعي الدالة CountA، ويحدد لها المجال الذي ستحصي الخلايا منه، ويُخزن النتيجة في المتغير LastRow. الآن نربط كل كائن في الواجهة مع الخلية المقابلة له في صفحة الإكسل، وذلك كالتالي: Sheets("الموظفون").Cells(LastRow + 1, 1).Value = UserForm.txtName.Value هنا عرّفّنا المسار الذي سنُسند إليه قيمة الكائن، حيث إن التعليمة Cells(value1,value2) لديها وسيطتان، الأولى تُعبر عن رقم السطر والثانية تُعبّر عن رقم العمود، ولدينا هنا رقم السطر هو عبارة عن متغير LastRow الذي يَعُد الخلايا غير الفارغة ونضيف له القيمة 1 لنحصل على موقع أول سطر فارغ بعد البيانات؛ أما UserForm.Name.Value، فتُعبر عن القيمة المُدخلة عن طريق الواجهة. يجب أن لا ننسى أن نتعامل هنا عن طريق الاسم البرمجي، وبنفس الطريقة نُسند باقي الكائنات إلّا الكائنات من النوع OptionButton، وهنا لدينا عدّة قيم للكائن، حيث يجب أن نفحص الكائن هل هو نشط أم لا، وذلك حتى نعوّض قيمة الكائن النشط منها في الخلية الخاصة به، وتكون التعليمات كالتالي: If UserForm.OptMale = True Then Sheets("الموظفون").Cells(LastRow + 1, 3).Value = "Male" Else Sheets("الموظفون").Cells(LastRow + 1, 3).Value = "Female" End If أما التعليمات الخاصة ببقية الكائنات فهي كالتالي: Sheets("الموظفون").Cells(LastRow + 1, 2).Value = UserForm.JobStatus.Value Sheets("الموظفون").Cells(LastRow + 1, 5).Value = UserForm.PhoneNumber.Value Sheets("الموظفون").Cells(LastRow + 1, 6).Value = UserForm.Rate.Value Sheets("الموظفون").Cells(LastRow + 1, 4).Value = UserForm.Salary.Value نلاحظ أن البيانات تبقى موجودةً في الكائنات بعد الإرسال، لذا لا بد من كتابة تعليمات تعمل على تفريغ الكائنات بعد ترحيلها، ولإجراء ذلك نُسند قِيَمًا فارغةً للكائنات بعد عمليات الترحيل، وتكون التعليمات كالتالي: UserForm.txtName.Value = "" UserForm.OptMale = False UserForm.OptFemale = False UserForm.JobStatus.Value = "" UserForm.PhoneNumber.Value = "" UserForm.Rate.Value = "" UserForm.Salary.Value = "" نلاحظ أن العمليات تعمل على أكمل وجه والواجهة تعمل بطريقة جيدة، ولكن لو ضغطنا على زر الإدخال بدون ملء الكائنات بالبيانات، فسنلاحظ أنه سيملأ صفحة الإكسل بسطرٍ فارغ، وذلك يُعَد خطأً برمجيًا كبيرًا. نكتب شروط إدخال للتغلب على الحالة السابقة، لذا نفحص ببساطة جميع الكائنات قبل ترحيل البيانات، فإذا وُجد كائن فارغ فسنوجه المستخدم إلى تعبئته وعدم تركه فارغًا عن طريق رسالة نصية، والتعليمات الخاصة بهذا الجزء من الإجراء كالتالي: If UserForm.txtName.Value = "" Or (UserForm.OptMale = False And UserForm.OptFemale = False) Or_ UserForm.JobStatus.Value = "" Or UserForm.PhoneNumber.Value = "" Or_ UserForm.JobRate.Value = "" Or UserForm.Salary.Value = "" Then_ MsgBox "يُرجى إتمام البيانات" يصبح الإجراء كاملًا بالشكل التالي: Private Sub btnAdd_Click() Dim LastRow As Long LastRow = WorksheetFunction.CountA(Sheets("الموظفين").Range("A:A")) If UserForm.txtName.Value = "" Or UserForm.JobStatus.Value = "" Or (UserForm.OptMale = False And UserForm.OptFemale = False) Or UserForm.PhoneNumber.Value = "" Or UserForm.Rate.Value = "" Or UserForm.Salary.Value = "" Then MsgBox "يُرجى إتمام البيانات" Else Sheets("الموظفون").Cells(LastRow + 1, 1).Value = UserForm.txtName.Value Sheets("الموظفون").Cells(LastRow + 1, 2).Value = UserForm.JobStatus.Value If UserForm.OptMale = True Then Sheets("الموظفون").Cells(LastRow + 1, 3).Value = "Male" Else Sheets("الموظفون").Cells(LastRow + 1, 3).Value = "Female" End If Sheets("الموظفون").Cells(LastRow + 1, 5).Value = UserForm.PhoneNumber.Value Sheets("الموظفون").Cells(LastRow + 1, 6).Value = UserForm.Rate.Value Sheets("الموظفون").Cells(LastRow + 1, 4).Value = UserForm.Salary.Value UserForm.txtName.Value = "" UserForm.OptMale = False UserForm.OptFemale = False UserForm.JobStatus.Value = "" UserForm.PhoneNumber.Value = "" UserForm.Rate.Value = "" UserForm.Salary.Value = "" End If End Sub لتطوير العمل أكثر يمكننا إضافة زر جديد على الواجهة السابقة، وعمله هو حذف البيانات التي أدخلناها للكائنات ولم نُرحلها إلى صفحة الإكسل بعد (أي لم نضغط على زر الإدخال)، ويؤدي فقط الجزء الأخير من الإجراء السابق الخاص بتفريغ الكائنات بعد الإرسال، لذا نُضيف زرًا جديدًا نُسميه حذف البيانات، ونضع له الاسم البرمجي BtnDelete، ويكون الإجراء الخاص به كالتالي: Private Sub BtnDelete_Click() UserForm.txtName.Value = "" UserForm.OptMale = False UserForm.OptFemale = False UserForm.JobStatus.Value = "" UserForm.PhoneNumber.Value = "" UserForm.Rate.Value = "" UserForm.Salary.Value = "" End Sub تعامل واجهات الإدخال مع الأحداث يمكننا توظيف الأحداث في التعامل مع واجهاتنا لتطوير عمل البرنامج، حيث يمكن التعامل مع الواجهة في الحدث كما تُعامل الدوال والتعليمات في الأحداث كما تعلمنا في درس صناعة الدوال الخاصة والتعامل مع الأحداث في مايكروسوفت إكسل VBA، ولا بد من تطبيق ذلك عمليًا لتوضيح الفكرة أكثر. مثال باستخدام الواجهة السابقة نريد تنفيذ إجراء يعمل على إظهار نافذة إدخال البيانات فقط وإخفاء برنامج الإكسل عند فتح الملف، ولإنجاز ذلك نفتح المحرر الخاص بملف العمل، ونختار من أحداثه الحدث الذي يُنفِّذ الأوامر عند فتح الملف، ونضع فيه التعليمات التالية: Private Sub Workbook_Open() Application.Visible = False UserForm.Show End Sub حيث يُخفي الأمر Application.Visible = False ملف الإكسل، ويُظهر الأمر UserForm.Show واجهة الإدخال عند فتح الملف، ويُشغلها. نلاحظ أن الإجراء السابق يؤدي المطلوب، ولكن لدينا هنا خلل بسيط، وهو عند إغلاق واجهة الإدخال، حيث يبقى برنامج الإكسل مفتوحًا ويعمل في الخلفية، ولكنه مخفي. لذا يجب أن نُجهّز حدثًا جديدًا يعمل على حفظ البيانات وإغلاق ملف الإكسل عند إغلاق واجهة إدخال البيانات السابقة، أي أن الحدث خاص بواجهة الإدخال، لذا نكتب التالي: Private Sub UserForm_Terminate() ActiveWorkbook.Save Application.Quit End Sub حيث إن: UserForm_Terminate: هو حدث يُنفّذ عند إغلاق الواجهة. ActiveWorkbook.Save: هو أمر يحفظ ملفات العمل النشطة، وبما أن ملف العمل مرتبط مُسبقًا بالواجهة، فإن الأمر سيُنفذ عليه حتى لو وجدت العديد من ملفات العمل مفتوحةً، لأنه بمجرد النقر ضمن الواجهة يصبح الملف المرتبط بها هو الملف النشط. Application.Quit: أمر إغلاق ملف العمل. لكن يجب الانتباه أنه بمجرد تشغيل هذا الإجراء، فلن نستطيع عرض البيانات من صفحة الإكسل، لذا يجب إضافة إجراء يعمل على فتح البيانات في صفحة الإكسل، ويُنفذ عن طريق زر في الواجهة نفسها. نضيف زرًا جديدًا يُنفذ الإجراء السابق، ونسميه عرض البيانات، ونسميه اسمًا برمجيًا مثل BtnShowData، ونكتب الإجراء المناسب لهذه العملية كالتالي: Private Sub BtnShowData_Click() Application.Visible = True Sheets("الموظفون").Activate UserForm.Hide End Sub خاتمة إن تصميم وبرمجة الواجهات من أجمل المزايا في برمجة الإكسل، حيث يزيد العمل عن طريق الواجهات من دقة البيانات المُدخلة، كما يقلل التعامل مع البيانات -عن طريق واجهات تفاعلية- من عمليات التشتت، وكلما تعمقنا أكثر في تطوير برمجياتنا على إكسل، زاد إنتاجنا وكفاءتنا في تقديم البيانات الدقيقة بالسرعة المطلوبة، لأن برمجة الواجهات تضيف شروطًا كثيرةً على العمل، مما يجعل المستخدم أقل عرضةً للوقوع في أخطاء إدخال البيانات بالطريقة التقليدية. اقرأ أيضًا استخدام أدوات مايكروسوفت إكسل لتنسيق الخلايا عن طريق الشيفرات VBA استخدام الشيفرات لتنفيذ العمليات الأساسية في مايكروسوفت إكسل VBA التفاعل مع المستخدم في مايكروسوفت إكسل باستخدام VBA الحلقات التكرارية في مايكروسوفت إكسل باستخدام VBA العمليات الشرطية في مايكروسوفت إكسل باستخدام VBA مدخل إلى البرمجة باستخدام VBA في مايكروسوفت إكسل
  2. تُعَد صناعة واجهات الإدخال من أقوى المزايا في إكسل التي تجعلنا قادرين على إدخال بياناتنا من خلال عناصر وأدوات إدخال وقوائم منسدلة، وتنقلها مباشرةً إلى صفحات الإكسل، أي كأننا نُحول الإكسل لبرنامج قواعد بيانات متكامل. تصميم واجهة تفاعلية مع المستخدم User Form يمكننا تصميم واجهة تفاعلية عن طريق محرر الفيجوال بيسك في الإكسل، حيث يمكننا تصميم واجهة إدخال واستعراض بياناتنا من خلاله، وذلك بأن نفتح محرر الشيفرات، ومن القائمة Insert نختار الأمر UserForm، فتظهر لنا النافذة التالية: نلاحظ وجود مجموعة من الأدوات ضمن صندوق الأدوات ToolBox تحتوي على الأزرار وعناصر الإدخال والتحكم التي يمكننا إضافتها إلى مساحة العمل الفارغة بجانبه، والتي يمكننا التحكم بأبعادها من حيث الطول والعرض، وذلك بالسحب من الأطراف. حيث يكون لدينا في الطرف الأيسر للقائمة Properties نافذة الخصائص التي نستطيع من خلالها تعيين كل خصائص الواجهة أو خصائص عناصر الإدخال فيها، وهي قائمة بغاية الأهمية لأننا من خلالها سنُعيّن جميع خيارات العناصر. بعض الأدوات في صندوق ToolBox توجد العديد من الأدوات التي يمكننا التعامل معها لصناعة الواجهات، وتختلف هذه الأدوات بين إصدارات مايكروسوفت أوفيس اختلافًا بسيطًا، ومن أهم هذه الأدوات وأكثرها استخدامًا الأدوات التالية: CheckBox: يتيح هذا العنصر للمستخدم تحديد خيار أو أكثر. ComboBox: يتيح هذا العنصر للمستخدم تحديد عنصر من القائمة المنسدلة. CommandButton: يسمح عنصر التحكم هذا للمستخدم بتنفيذ إجراء معين، حيث يُشغِّل إجراءً فرعيًا منفصلًا. Label: يتيح هذا العنصر عرض النص للمستخدم، ويُستخدم عادةً لعرض نص وصفي بجانب العناصر. ListBox: يسمح عنصر التحكم هذا للمستخدم بالاختيار من قائمة الخيارات الممكنة. +OptionButton: يسمح عنصر التحكم هذا للمستخدم بالاختيار من قائمة الخيارات الممكنة اختيارًا واحدًا فقط. Ref Edi: يسمح عنصر التحكم هذا للمستخدم بتحديد نطاق من الخلايا. TextBox: يتيح هذا العنصر إمكانية عرض النص والسماح للمستخدم بإدخال المعلومات. Frame: يتيح هذا العنصر تجميع العناصر الأخرى معًا. Calendar: يتيح هذا العنصر تضمين تقويم دائم في ورقة عمل. Image: يتيح هذا العنصر إمكانية إضافة رسم أو صورة إلى واجهة المستخدم. SpinButton: يتيح هذا العنصر للمستخدم تحديد قيمة بالنقر فوق زرين، إما لزيادة القيمة أو تقليلها. مثال نريد تصميم واجهة إدخال تحتوي على البيانات الخاصة بموظفي إحدى المنشآت، ونريد مثلًا البيانات التالية: الاسم. الجنس. الوضع الوظيفي. رقم الهاتف. تقييم العمل. الراتب. نرسم عناصر الإدخال ضمن مساحة العمل المخصصة، ويلزمنا في البداية عنصر من النوع TextBox لإدخال الاسم، وعنصر من النوع Label، ونحدد أبعاد كل منهما، حيث يمكننا التحكم بأبعادهما من طول وعرض حسب ما نراه مناسبًا. يمكن تحرير النص الخاص بـ Label عن طريق النقر عليه مرةً واحدةً لتحريره، ثم نحدد النص ونستبدله بما نريد، أو عن طريق القائمة Properties عن طريق الخاصية Caption التي تُعبر عن الاسم الظاهر للمستخدم، ونُغيّر الاسم الذي تحتويه. الآن نرسم العنصر الخاص بالجنس، وبما أن الإجابة تكون أحد اختيارين، فنختار الأداة OptionButton، ونضع لها العنوان بجانبها. ثم نرسم العنصر الخاص بالوضع الوظيفي هنا، ويمكن أن تكون العديد من الخيارات، والإجابة هي أحد هذه الخيارات، لذا الأداة المناسبة هي ComboBox. العنصران رقم الهاتف والراتب عبارة عن TextBox، والعنصر تقييم العمل عبارة عن ComboBox، لذا ننسخ العناصر السابقة مع تغيير عناوينها Label. نُعدل من ترتيب العناصر قليلًا، ونضع كل 3 عناصر في عمود، ونلاحظ أن الأبعاد بالنسبة للعناصر غير متساوية بالكامل، لذا يجب تعديلها لتظهر بنفس الأبعاد وبمظهر أفضل، ولإجراء ذلك نحدد العناصر ذات الشكل المتقارب TextBox وComboBox، ومن القائمة Format الخاصة بتنسيق العناصر نختار الأمر Make Same Size، ومن هنا نجد الخيارات التالية: Width: لجعل العناصر بنفس العرض. Height: لجعل العناصر بنفس الطول. Both: لجعل العناصر بنفس العرض والطول. نختار منها الأمر Both. ثم نُنسق العناصر من خلال محاذاة العناصر في العمود الواحد والسطر الواحد، وذلك من القائمة نفسها Format، حيث نختار الأمر Align، فنحدد العناصر في العمود الواحد ونجعل المحاذاة في المنتصف من الأمر Center، ونحدد عناصر كل صف ونجعل المحاذاة سفليةً من الأمر Bottom، ثم نساوي بين تباعد العناصر، وذلك بتحديد عناصر العمود الواحد، ومن نفس القائمة نختار الأمر vertical Spacing الذي يأخذ القيم التالية: Make Equal: لجعل كل المسافات الأفقية والعمودية بين العناصر بنفس الحجم. Increase: لزيادة المسافة بين العناصر درجةً واحدةً من كل الجوانب. Decrease: لتقليل المسافة بين العناصر درجةً واحدةً من كل الجوانب. Remove: لإزالة المسافة بين العناصر. نختار منها الأمر Make Equal. نُسمي الآن العناصر بأسماء برمجية لاستدعائها عند كتابة الإجراءات واستخدامها فيها، ولإجراء ذلك نحدد العنصر، ومن القائمة Properties عند الخاصية المسماة Name نضع اسمًا مُعبرًا عن العنصر (الاسم اختياري، ولكن يجب ألا يحتوي على فراغات). نسمي العناصر بالأسماء التالية: الاسم = txtName. ذكر = OptMale. أنثى = OptFemale . الوضع الوظيفي = JopStatus. رقم الهاتف = PhoneNumber. تقييم العمل = Rate. الراتب = Salary. إلى الآن لا تحتوي قوائمنا المنسدلة على أية قيم، لذا نحتاج إلى تخصيص قيم مناسبة لها، وذلك باستيراد مجال من الخلايا من صفحة إكسل في ملف العمل، حيث ننشئ ورقة عمل جديدةً، ونضع فيها القيم المحتملة لجميع القوائم التي نعمل عليها ونستوردها لواجهة الإدخال عن طريق الخاصية RowSource في القائمة Properties، ونضع فيها المجال بذكر اسم الصفحة بعده إشارة تعجب (!) بعدها المجال الخاص بهذه القائمة المنسدلة. الآن أصبحت قوائمنا جاهزة، ولكن عند تشغيل الواجهة هنا نلاحظ أنه يمكننا تعبئة عنصر القائمة المنسدلة يدويًا، وذلك الأمر خاطئ، لذا يجب أن نقيد واجهة الإدخال بالمجال الذي استوردناه فقط، وذلك عن طريق الخاصية MatchRequired من القائمة Properties، حيث إن القيمة الافتراضية لها False التي تُمكن المستخدم من إدخال بيانات غير موجودة في القائمة، لذا نضع القيمة True بدلًا منها، وذلك لتقييد إدخالات المستخدم بمحتويات القائمة فقط. نجد في الصورة السابقة أننا نستطيع إدخال قيم من خارج القائمة المنسدلة ضمن العنصر الخاص بالوضع الوظيفي، لأن الإدخال غير مقيد، ولكن لم نستطع إدخال قيمة من خارجها في عنصر التقييم، لأن الإدخالات فيها مقيدة، وأظهر لنا المحرر رسالة خطأ تُفيد بأن القيمة المُدخلة غير مقبولة. لنُصمم الآن عنصر زر يعمل على ترحيل البيانات الموجودة في الوجهة إلى صفحة إكسل والإضافة تراكميًا، أي كلما أضفنا بيانات جديدة وضغطنا زر الإدخال تُرحل البيانات إلى السطر الفارغ أسفل البيانات، ونضع اسمًا برمجيًا له BtnExport. الآن نغير من الاسم البرمجي للواجهة تغييرًا كاملًا، ونضع لها الاسم UserForm، ونغير من الظاهر للمستخدم عن طريق الخاصية Caption. أصبحت واجهة الإدخال جاهزةً للبرمجة وربطها مع خلايا الصفحة التي سنُرحل إليها البيانات، وهو ما سنتعلمه لاحقًا. الخصائص العامة للعناصر في القائمة Properties تحتوي القائمة Properties على خصائص معينة لكل عنصر، حيث تُستخدم لتعيين الميزات أو تحريرها وفقًا لاحتياجات ومتطلبات المستخدم، وللتعديل نضغط على الخاصية ونُعدلها في العمود الأيمن، ومن أهم هذه الخصائص: Name: الاسم البرمجي للعنصر الذي تتعرف عليه الإجراءات عند كتابة الشيفرات البرمجية، ويتكون من 40 حرفًا بحد أقصى. Caption: تُستخدم هذه الخاصية لتحديد الاسم الظاهري للعنصر الذي يظهر في تصميم الواجهة. Height, Width: تُستخدم هذه الخاصية لتعيين ارتفاع وعرض نموذج المستخدم والعناصر الخاصة به، ويمكنك تخصيص الحجم عن طريق إدخاله يدويًا في خاصية الارتفاع والعرض في نافذة الخصائص، وتعيين القيم بالنقاط، ولا يمكن أن تُقبَل القيم السالبة. Value: يكثر استخدام هذه الخاصية مع العنصرين CheckBox وOptionButton، حيث تجعل العنصر مُفعلًا تلقائيًا، أي أنه يكون قيمةً افتراضيةً ويأخذ القيمة 1 أو القيمة True، بمعنى أن العنصر مُفعل افتراضيًا، والقيمة 0 أو القيمة False التي تعني أنه غير مفعل؛ أما في العنصرين TextBox وComboBox، فيمكننا وضع قيمة نصية أو رقمية افتراضية، ولكن يجب الانتباه أن تكون القيمة ضمن خيارات القائمة المنسدلة ومطابقةً للقيمة في صفحة الإكسل تمامًا. AutoSize: تستخدم هذه الخاصية لتحديد ما إذا كان حجم العنصر الذي يعرض المحتوى بالكامل تلقائيًا أم لا، وإذا عُيِّنت هذه الخاصية على القيمة TRUE فسيعمل تلقائيًا على تغيير حجم عنصر التحكم المحدد وفقًا لحجم المحتوى؛ أما بالنسبة للقيمة FALSE (الخيار الافتراضي)، فسيحتفظ بحجم عنصر التحكم كما هو أثناء التصميم. BackColor: تُستخدم هذه الخاصية لتعيين لون الخلفية للعناصر، ولتنفيذ خاصية BackColor يجب التأكد من ضبط نمط الخلفية لخاصية BackStyle على خلفية معتمة. BorderColor: تُستخدم هذه الخاصية لتعيين لون الحدود لـ UserForm والعناصر الخاصة به، ولتطبيق خاصية لون الحدود يجب تعيين الخاصية BorderStyle إلى قيمة غير صفرية. ControlTipText: تُستخدم هذه الخاصية لعرض النص عندما يشير المستخدم ويمرر الماوس فوق العنصر، وهذه الخاصية مفيدة في تثقيف المستخدمين من خلال تقديم نصائح أو تفسيرات حول استخدام العنصر. Font: تحدد هذه الخاصية نوع الخط المستخدم في نموذج المستخدم أو في العناصر، ويمكنك التلاعب بالخط بسهولة عن طريق تحديد اسم الخط الخاص به ونمطه وحجمه. MousePointer: تُستخدم لتحديد الطريقة التي يُعرَض مؤشر الماوس فيها عندما يتحرك فوق العنصر، حيث توجد العديد من الأشكال التي يمكن اختيارها. Visible: تحدد هذه الخاصية إمكانية الرؤية للتحكم في النموذج، فإذا عُيِّن على القيمة المنطقية TRUE (القيمة الافتراضية)، فسيكون العنصر مرئيًا آخر، وإلا بالنسبة للقيمة False فسيختفي العنصر، ويمكن استخدام هذه الخاصية لعرض عنصر مخفي فقط في حالة استيفاء أي شرط، وإلا سيظل العنصر مخفيًا. خاتمة من خلال ما طرحناه نكون استوفينا أهم آليات تصميم الواجهات التي تُعَد من الطرق التي تجعل التعامل مع عمليات إدخال البيانات أكثر متعةً ودقةً وأقل تشتيتًا للمستخدم، حيث سيكون كل تركيزه فقط في بعض الخانات التي يتعامل معها من خلال هذه الواجهة، ولا يتشتت نظره في الكم الهائل من البيانات كما في طريقة الإدخال التقليدية. اقرأ أيضًا المقال السابق: صناعة الدوال الخاصة والتعامل مع الأحداث في مايكروسوفت إكسل VBA استخدام الشيفرات لتنفيذ العمليات الأساسية في مايكروسوفت إكسل VBA استخدام أدوات مايكروسوفت إكسل لتنسيق الخلايا عن طريق الشيفرات VBA الحلقات التكرارية في مايكروسوفت إكسل باستخدام VBA العمليات الشرطية في مايكروسوفت إكسل باستخدام VBA مدخل إلى البرمجة باستخدام VBA في مايكروسوفت إكسل
  3. لا شك أننا نتعامل مع الكثير من الدوال في برنامج مايكروسوفت إكسل، فهنالك المئات من الدوال التي تُبسّط علينا العمل دائمًا، ولكن توجد بعض العمليات التي تحتاج إلى بعض الاحتيال عليها للوصول إلى حل المسائل التي تعترضنا، وربما نستخدم خلالها العديد من الدوال المتداخلة مع بعضها البعض لحل المسألة، وباستخدام برمجة المايكروسوفت إكسل عن طريق الفيجوال بيسك يمكننا صناعة دوال خاصة بعملنا، والتي تخدم الوصول لحل المشاكل التي نتعامل معها دومًا بأقصر الطرق. تعرفنا سابقًا على آلية كتابة الإجراءات باستخدام فيجوال بيسك في درس مدخل إلى البرمجة باستخدام VBA في مايكروسوفت إكسل، ووجدنا أن الإجراء من النوع sub-routine يُنفذ أمرًا أو مجموعةً معينةً من الأوامر، وأن الإجراء من النوع Function يُضيف دوال على برنامج مايكروسوفت إكسل للاستخدام الاعتيادي كما لو أنها من ضمن دوال البرنامج الأساسية. صناعة الدوال توجد طريقتان لكتابة الإجراء هما: إجراء مع وسطاء (معطيات) وتكون الشيفرة كما يلي: Function name(arguments) as type Code End Function حيث إن: name: اسم للدالة التي نصنعها، ويُفضل أن يكون الاسم مُعبرًا عن عمل الدالة. arguments: الوسطاء التي ستعمل الدالة مع محتوياتها. type: نوع المُخرَج للدالة التي نصنعها. Code: مجموعة الشيفرات التي ستُنفذها الدالة. مثال لدينا البيانات التالية، ونريد صناعة دالة خاصة تعمل على دمج الاسم الأول مع الأخير للحصول على الاسم الكامل. لدينا وسيطان هنا، هما: الاسم الأول والاسم الأخير من النوع النصي، لذا نكتب الإجراء بالشكل التالي: Function FullName(FirstName As String, LastName As String) As String FullName = FirstName & " " & LastName End Function عند العودة إلى برنامج مايكروسوفت إكسل سنجد أن الدالة أُضيفت إلى الدوال الأساسية فيه، وتعمل مثل باقي الدوال الاعتيادية. مثال لدينا البيانات التالية، ونريد صناعة دالة خاصة تحسب الراتب بعد الزيادة، وذلك وفقًا لتقييم كل موظف. حيث يتقاضى الموظف زيادةً قدرها 0.2 عندما يكون تقييمه أكثر من 7، وزيادةً قدرها 0.1 عندما يكون تقييمه أكثر من 5 وأقل من 7، وزيادةً أخرى قدرها 0.08 عندما يكون أكثر من 1، وزيادةً قدرها 0.04 إذا لم نُسند خانة التقييم للدالة، وعليه يكون الإجراء كالتالي: Function NewSalary(Salary As Currency, Optional Rate As Integer) As Currency If Rate = 0 Then NewSalary = Salary + (Salary * 0.04) ElseIf Rate >= 7 Then NewSalary = Salary + (Salary * 0.2) ElseIf Rate >= 5 Then NewSalary = Salary + (Salary * 0.1) ElseIf Rate >= 1 Then NewSalary = Salary + (Salary * 0.08) End If End Function بتنفيذ الدالة على البيانات السابقة نجد التالي: إجراء بدون وسطاء (معطيات) وتكتب الشيفرة كما يلي: Function name() as type Code End Function حيث إن: name: اسم للدالة التي نصنعها، ويُفضل أن يكون الاسم مُعبرًا عن عمل الدالة. type: نوع المُخرَج للدالة التي نصنعها. Code: مجموعة الشيفرات التي ستُنفذها الدالة. مثال لنَعُد إلى المثال السابق، حيث نريد إضافة عمود يحتوي أرقامًا تعريفيةً عشوائيةً للموظف، لذلك نكتب الإجراء التالي: Function RandCode() As Long RandCode = Rnd() * 10000 End Function عند تنفيذ الدالة على البيانات السابقة فسنحصل على النتيجة التالية: التعامل مع الأحداث تعلمنا في المقالات السابقة كيفية كتابة إجراءات لتنفيذ مجموعة من الأوامر، وذلك بطريقتين: الأولى عندما نطلب منه تنفيذ الإجراء يدويًا، والثانية عن طريق إضافة أزرار تُنفذ الإجراء عند الضغط عليها، لكن في بعض الأحيان نحتاج أن تُنفَّذ هذه الإجراءات آليًا عند وقوع حدث معين، مثل فتح ملف، أو ظهور رسالة ترحيب عند فتح ملف إكسل، أو عند الطباعة، أو عند تعبئة خلية، وهذه الإجراءات تسمى أحداثًا، وهي موجودة في كل لغات البرمجة، ونستطيع برمجة برنامج الإكسل لتنفيذها عند وقوع الحدث. الصيغة العامة لكتابة الأحداث Sub Event_Name (variables) Our code End sub نجد أن الصيغة العامة للحدث هي نفسها للإجراء الروتيني، ولكن يجب تسميتها بأسماء محددة تدل على حدث معين، أي أن الاسم هنا ليس اختياريًا، بل يكون مُعرّفًا عن طريق لغة البرمجة، وتوجد بعض القوانين لكتابة الأحداث وهي: تُكتب الأحداث في محرر الفيجوال بيسك ضمن الأوراق أو ضمن الملف، وليس ضمن model؛ لأن الحدث هو خاص بورقة العمل أو الملف، وبالنقر مرتين على اسم الصفحة أو اسم الملف يفتح المحرر الخاص بالصفحة أو الملف. الحدث خاص، فلا يمكن جعله ضمن المحرر عامًا، ولتنفيذ ذلك توجد قائمة منسدلة تعمل على تبديل الإجراء من عام إلى إجراء خاص بالصفحة أو الملف. اسم الحدث هو اسم معين ليس اختياريًا، أي أن محرر الشيفرات هو من يزودنا به ولا يمكن إنشاؤه، ونُحدد الحدث الذي نريده من القائمة المنسدلة في الزاوية اليمنى من واجهة المحرر. سنتعرف على بعض الأمثلة التي تشرح آلية عمل الأحداث. مثال 1 نريد إنشاء حدث يُظهر رسالة ترحيب عند فتح صفحة معينة، لذا فأول ما نفعله البحث عن الحدث الذي يُنفذ عند فتح الصفحة، وهو مُعرّف بالاسم SheetActivate، وهذا الحدث يعمل على مستوى الملف، ويكون الإجراء كالتالي: Private Sub Workbook_SheetActivate(ByVal Sh As Object) If Sh.Name = "Sheet2" Then MsgBox "hello" End If End Sub حيث إن المتغير sh هو متغير مُعرف في الحدث، يُعبر عن الصفحات كمتغيرات. مثال 2 نريد إظهار نفس الرسالة السابقة عند فتح ملف الإكسل. Workbook_Open: هو الحدث الذي يُنفّذ عند فتح ملف الإكسل، ولذلك نكتب الإجراء التالي: Private Sub Workbook_Open() MsgBox "welcome back" End Sub مثال 3 نريد كتابة إجراء يُضيف الصفحات الجديدة في نهاية صف الصفحات، ولتنفيذ ذلك علينا تقسيم المراحل لعمل الإجراء ومعرفة الأوامر الضرورية لفعل ذلك: Workbook_NewSheet: هو الحدث الذي يُنفذ عند إضافة صفحة عمل جديدة. يجب في البداية أن نعرف عدد الصفحات في الملف، لذا لنُعرّف المتغير sheet_count، ونُخزن فيه قيمة الأمر الذي يحصي عدد الصفحات، وهو الأمر sheet.count. نكتب الأمر المسؤول عن تحريك الصفحة الجديدة لآخر الصف، وهو الأمر التالي: object.move after:=sheets("عدد الصفات في الملف") حيث يُعبّر object هنا عن الصفحة الجديدة، ويُصبح الإجراء كالتالي: Private Sub Workbook_NewSheet(ByVal Sh As Object) Dim sheet_count As Integer sheet_count = Sheet.Count Sh.Move after:=Sheets("sheet_count") End Sub مثال 4 نريد تنفيذ إجراء عند الانتقال من خلية إلى أخرى يتغير لون عمود وسطر تقاطع الخلية، لذا نكتب الإجراء كما يلي: في البداية نريد دالةً تحذف الألوان السابقة عن طريق التعليمة التالية: Cells.Interior.ColorIndex = xlNone حيث تعني القيمة xlNone جعل الخلية بلا لون، وهذه التعليمة تُلغي اللون لكل خلايا الصفحة. الآن نكتب التعليمة الخاصة بجعل خلايا السطر كاملًا تأخذ لونًا موحدًا كالتالي: EntireRow.Interior.Color = RGB(14, 148, 148) ونفس الحالة بالنسبة لإعطاء خلايا العمود لونًا واحدًا، ولكن نُسبق التعليمتين بالأمر Target الذي يُعبر هنا عن مجال الصفحة، ومن هنا يصبح الإجراء بالشكل التالي: Private Sub Worksheet_SelectionChange(ByVal Target As Range) Cells.Interior.ColorIndex = xlNone Target.EntireRow.Interior.Color = RGB(14, 148, 148) Target.EntireColumn.Interior.Color = RGB(14, 148, 148) End Sub أهم الأحداث المرتبطة بملف العمل الأحداث المرتبطة بملف العمل كثيرة، ولكن سنذكر أهمها فيما يلي: Workbook_BeforeSave: الحدث قبل إتمام حفظ الملف. Workbook_BeforePrint: الحدث قبل البدء بالطباعة. Workbook_AfterSave: الحدث بعد إتمام حفظ الملف. Workbook_SheetActivate: الحدث عند تنشيط (فتح) الصفحة (ورقة عمل معينة). Workbook_NewSheet: الحدث عند إضافة ورقة عمل جديدة. Workbook_SheetChange: الحدث عند تعديل ورقة عمل. Workbook_BeforeClose: الحدث قبل إغلاق ملف الإكسل. Workbook_Open: الحدث عند فتح ملف الإكسل. أهم الأحداث المرتبطة بورقة العمل Worksheet_Activate: الحدث عند تنشيط الصفحة. Worksheet_BeforeDelete: الحدث قبل تنفيذ حذف الصفحة. Worksheet_Change: الحدث عند إجراء تغييرات على الصفحة. Worksheet_Deactivate: الحدث عند إلغاء تنشيط الصفحة (الانتقال إلى صفحة أخرى). خاتمة لا تقل الأحداث أهميةً عن الإجراءات التي تعلمناها سابقًا، فلكلٍ منها عملٌ مخصص ضمن الشيفرات، كما تساعد كثيرًا في صناعة البرمجيات بصورة أفضل ومضبوطة أكثر في نفس الوقت، وتوجد الكثير من الأحداث الأخرى التي سنتطرق إليها، والتي سنشرح آلية عملها وقت الحاجة إليها أثناء العمل. اقرأ أيضًا المقال السابق: استخدام أدوات مايكروسوفت إكسل لتنسيق الخلايا عن طريق الشيفرات VBA استخدام الشيفرات لتنفيذ العمليات الأساسية في مايكروسوفت إكسل VBA التفاعل مع المستخدم في مايكروسوفت إكسل باستخدام VBA الحلقات التكرارية في مايكروسوفت إكسل باستخدام VBA العمليات الشرطية في مايكروسوفت إكسل باستخدام VBA مدخل إلى البرمجة باستخدام VBA في مايكروسوفت إكسل
  4. تعلمنا في مقال استخدام الشيفرات لتنفيذ العمليات الأساسية في مايكروسوفت إكسل VBA كيفية تنفيذ إجراءات عمل بعض الأدوات عن طريق الشيفرات البرمجية، وسنكمل في هذا المقال شرح عمل الأدوات التالية عن طريق الشيفرات البرمجية: تنسيق الخلايا. تنسيق الخطوط. إضافة حدود للخلايا. مسح محتويات الخلايا. إضافة خلايا أو صفوف أو أعمدة. تغيير حجم خط الخلية نستخدم لتغيير حجم خط الخلية التعليمة التالية: expression.Font.Size = "قيمة حجم الخط الذي نريده" حيث تعبّر expression عن الكائن الذي سنتعامل معه، وفي الغالب يكون من النوع Range بدون ذكر اسم الملف والصفحة اللذين يحويان هذا النطاق، إلا إذا كان تنفيذ الشيفرة في غير الصفحة النشطة أو في غير الملف النشط، أي أنها تصبح بالشكل التالي: Range("عنوان الخلية").Font.Size = "قيمة حجم الخط الذي نريده" والقيمة الافتراضية لحجم الخط هي 11. جعل خط الخلية عريضا نستخدم لذلك التعليمة التالية: Range("عنوان الخلية").Font.Bold = True or False حيث إن القيمة True للخط العريض، والقيمة False للخط العادي، وهي القيمة الافتراضية. تغيير لون خط الخلية ويمكن تنفيذ ذلك بعدة طرق، وهي: عن طريق الاسم الصريح للون، والتعليمة كالتالي: Range("عنوان الخلية").Font.Color = vbColor حيث إن القيمة الافتراضية للون الخط هي vbBlack. عن طريق رقم الفهرس للون، والتعليمة كالتالي: Range("عنوان الخلية").Font. ColorIndex = "الرقم المرجعي للون" حيث تكون القيمة الرقمية للون بين الرقم 1 والرقم 56 وفق المرفق بالصورة التالية، والقيمة الافتراضية للون الخط هي 1. عن طريق نظام الـ RGB للألوان: الفكرة الأساسية من نظام RGB هي القدرة على إعادة إنتاج أي لون آخر بناءً على نسب تداخل ثلاثة ألوان أساسية: الأحمر R والأخضر G والأزرق B، حيث إن وجود هذه الألوان معًا بقيمتها الكاملة 255 ينتج اللون الأبيض، بينما غياب قيمتها لتصل إلى 0 ينتج اللون الأسود. هذا النوع من أنظمة الألوان ضوئي بالكامل، لذا فهو مثالي للشاشات وأجهزة العرض المختلفة، ونتلاعب بقيم كل من الألوان الأساسية للحصول على أي لون آخر قد نريده، وفي العادة تتراوح شدة كل لون ضمن مجال من 0 حتى 255. ويُعَد نظام ألوان RGB نظام إضافة، حيث تعني كل قيمة مضافة لأحد الألوان المزيد من الضوء، أي أن الألوان ذات القيم الكبرى (في كل من R وG وB) أفتح، بينما تلك التي تمتلك قيمًا دُنيا أقتم. والتعليمة التي تحدد لون الخط هي كالتالي: Range("عنوان الخلية").Font. Color = RGB(0,0,0) تغيير لون الخلية وذلك عن طريق التعليمة: Range("عنوان الخلية").Cells.Interior.ColorIndex = "الرقم المرجعي للون" محاذاة النصوص كما نعلم لدينا نوعان من المحاذاة للنصوص، وهما: المحاذاة الأفقية، والمحاذاة العمودية. المحاذاة الأفقية تحدد موضع النص من الخلية أفقيًّا، والتعليمة الخاصة بها هي: Sub alignment_H() expression.HorizontalAlignment = type End Sub حيث تأخذ type إحدى القيم التالية: xlHAlignLeft محاذاة النص يسار الخلية. xlHAlignRight محاذاة النص يمين الخلية. xlHAlignCenter محاذاة النص منتصف الخلية. المحاذاة العمودية تحدد موضع النص من الخلية أفقيًّا، والتعليمة الخاصة بها هي: Sub alignment_V() expression. VerticalAlignment= type End Sub حيث تأخذ type إحدى القيم التالية: xlVAlignTop محاذاة النص أعلى الخلية. xlVAlignBottom محاذاة النص أسفل الخلية. xlVAlignCenter محاذاة النص منتصف الخلية. تفعيل الخلية أو الصفحة لجعل الخلية أو الصفحة نشطةً (مُفعَّلةً) نستخدم التعليمة التالية: Sub active() expression. Activate End Sub تغيير عرض الخلية نستخدم لذلك التعليمة التالية: Range("عنوان الخلية").ColumnWidth = "قيمة عرض الخلية الذي نريده " حيث إن القيمة الافتراضية لعرض الخلية هي 8.43. مثال نريد إنشاء الخلية A2 التي تحوي القيمة 5000، والخلية B1 التي تحوي القيمة 48، ونريد جعل الخط عريضًا حجمه 20، ولونه أبيض، ولون خلفية الخلية أخضر داكنًا، وجعل المحتوى يتوسط الخلايا، ولذلك نكتب الإجراء التالي: Sub example() Range("A2") = "5000" Range("B2") = "48" Range("A2:B2").Font.Bold = True Range("A2:B2").Font.Size = 20 Range("A2:B2").Font.Color = RGB(255, 255, 255) Range("A2:B2").Cells.Interior.ColorIndex = 10 Range("A2:B2").HorizontalAlignment = xlHAlignCenter End Sub إضافة حدود للخلية نستخدم لذلك التعليمة التالية: Range("عنوان الخلية").Borders(direction).LineStyle = type حيث إن: direction: نُحدد عن طريقها مكان الحدود للخلية، حيث تأخذ القيم التالية: XlDiagonalDown لوضع خط يقطع الخلية إلى مثلثين يبدأ من الزاوية اليسرى للخلية. XlDiagonalUp لوضع خط يقطع الخلية إلى مثلثين يبدأ من الزاوية اليمنى للخلية. XlEdgeBottom لوضع خط للخلية من الأسفل. XlEdgeLeft لوضع خط للخلية من اليسار. XlEdgeRigh لوضع خط للخلية من اليمين. XlEdgeTop لوضع خط للخلية من الأعلى. XlInsideHorizonta لوضع خطوط أفقية للخلايا، لكن يجب أن يحوي المجال عدة أعمدة، وتكون الخطوط للخلايا بين بداية المجال ونهايته. XlInsideVertical لوضع خطوط عمودية للخلايا، لكن يجب أن يحوي المجال عدة أعمدة، وتكون الخطوط للخلايا بين بداية المجال ونهايته. LineStyle: تحدد شكل الخط الذي سنضعه للخلية، ويأخذ القيم التالية: XlContinuous الخط الاعتيادي (خط متصل). Xldash الخط عبارة عن مجموعة شَرْطَات (متقطع) بالشكل التالي ------- XlDashDot الخط عبارة عن مجموعة متتابعة بالشكل، شَرْطَة تليها نقطة. XlDashDotDot الخط عبارة عن مجموعة متتابعة بالشكل، شَرْطَة تليها نقطتان. XlDot الخط منقط بالشكل التالي …….. XlDouble الخط عبارة عن خطين عاديين فوق بعضهما. XlLineStyleNone لإلغاء تنسيق الحدود الموجودة بالخلية. XlSlantDashDot الخط عبارة عن مجموعة متتابعة بالشكل، شَرْطَة مقطوعة بشكل مائل تليها نقطة. ولإضافة حدود من كافة الاتجاهات للخلية، نكتب الصيغة السابقة كالتالي: Range("عنوان الخلية").Borders.LineStyle = type تغيير ثخانة حدود الخلية نستخدم لذلك التعليمة التالية: Range("عنوان الخلية").Borders.value = "قيمة ثخانة الحدود للخلية" حذف محتويات الخلايا يمكن حذف محتويات الخلايا بعدة طرق، ومنها استخدام الأمر Delete والأمر Clear والأمر ClearContents والأمر ClearFormats، ولكلٍ منها عمل مخصص. الأمر Delete يُستخدم لحذف الخلايا مع مكانها ضمن البيانات، ويؤدي استعمال هذا الأمر إلى إزاحة الخلايا المتبقية باتجاه مكان الخلايا المحذوفة، والشكل العام لصيغة الأمر هو: Sub Delete() Rang("الخلايا أو النطاق الذي نريد حذفه").Delete (Shift) End Sub حيث إن shift وسيط اختياري يُحدد مكان إزاحة الخلايا، ويأخذ القيم التالية: xlShiftToLeft إزاحة الخلايا المتبقية لموضع الخلايا المحذوفة من اليسار، وهي القيمة الافتراضية. xlShiftUp إزاحة الخلايا المتبقية لموضع الخلايا المحذوفة من الأسفل. مثال بالعودة إلى المثال السابق نريد حذف الخانات من A1:A3، وذلك باستخدام الطرق السابقة، ولذلك نكتب التعليمات التالية: Sub Delete() Range("A1:A3").Delete End Sub الأمر Clear يُستخدم لحذف بيانات الخلية وتنسيقاتها مع الحفاظ على موضع البيانات، والشكل العام لصيغة الأمر: Sub Clear() Range("الخلايا أو النطاق الذي نريد حذفه").Clear End Sub مثال لنجرب نفس المثال السابق، فنكتب الإجراء كالتالي: Sub Clear() Range("A1:A3").Clear End Sub الأمر ClearContents يُستخدم لحذف البيانات، ولكن هذا الأمر يُحافظ على موضع وتنسيق الخلية، والشكل العام لصيغة الأمر هو: Sub Clear_Contents () Range("الخلايا أو النطاق الذي نريد حذفه"). ClearContents End Sub مثال نُطبِّق الأمر على مثالنا السابق، فنكتب الإجراء التالي: Sub Clear_Contents () Range("A1:A3"). ClearContents End Sub الأمر ClearFormats يُستخدم لحذف تنسيق الخلية مع إبقاء المحتوى، والشكل العام لصيغة الأمر هو: Sub Clear_Contents () Range("الخلايا أو النطاق الذي نريد حذفه"). ClearFormats End Sub مثال نُطبِّق الأمر على مثالنا السابق، فنكتب الإجراء التالي: Sub Clear_Contents () Range("A1:A3"). ClearFormats End Sub إدراج خلايا أو أسطر أو أعمدة التعليمة المسؤولة عن الإدراج هي التعليمة Insert إدراج خلايا نُدرج خلايا جديدةً عن طريق الأمر التالي: Sub insert() expression. Insert (Shift) End Sub حيث يحدد الوسيط Shift اتجاه إدراج البيانات، ويأخذ القيم التالية: xlShiftDown تُدرج خلايا أسفل النطاق المحدد. xlShiftToRight تُدرج خلايا يمين النطاق المحدد. مثال نريد إدراج خلايا ضمن بياناتنا في الجدول التالي، بحيث تكون الخلايا المضافة للأعلى ضمن النطاق A1:B5: نكتب الإجراء التالي: Sub Insert() Range("A1:B5").Insert xlShiftDown End Sub إدراج أسطر أو أعمدة نُدرجها عن طريق الأمر التالي: Sub insert() expression. Insert End Sub مثال نريد إدراج 3 صفوف ضمن بياناتنا في جدول البيانات السابق، ولذلك نكتب الإجراء التالي: Sub Insert() Range("2:5").Insert End Sub نلاحظ أنه أُضيفت 3 أسطر ابتداءً من السطر رقم 2، وأن بقية البيانات أُزيحت للأسفل. ولإضافة أعمدة سنتبع نفس الأسلوب، ولكن المجال يتضمن أعمدةً فقط، وبفرض أننا نريد إضافة عمود واحد يكون الإجراء كالتالي: Sub Insert() Range("A:A").Insert End Sub هنا تُزاح البيانات نحو اليسار في النسخة الإنجليزية، وإلى اليمين في النسخة العربية. خاتمة توجد العديد من التعليمات الجزئية التي تُشكل اللَّبنة الأساسية لبناء التطبيقات، لذا يتوجب علينا فهم آلية عمل التطبيق، وتقسيمه لأجزاء ومهام صغيرة، ثم البحث عن التعليمات التي تنفذ هذه المهام، حيث تطرقنا لأهمها، وسنستوفي شرح ما يصادفنا من أوامر خلال المقالات القادمة أثناء صناعة البرمجيات الصغيرة. اقرأ أيضًا التفاعل مع المستخدم في مايكروسوفت إكسل باستخدام VBA الحلقات التكرارية في مايكروسوفت إكسل باستخدام VBA العمليات الشرطية في مايكروسوفت إكسل باستخدام VBA مدخل إلى البرمجة باستخدام VBA في مايكروسوفت إكسل
  5. يمكننا تنفيذ الأوامر التي تنفذها الأدوات على برنامج إكسل باستخدام الشيفرات البرمجية، مثل إضافة صفحات وتنسيق الخطوط والخلايا والعديد من العمليات، وفيما يلي أهم الأوامر التي نستخدمها في إنشاء التطبيقات: إضافة صفحة عمل جديدة. تحديد الخلايا. عمليتا النسخ واللصق. إلغاء تحديد الخلايا المنسوخة. عمليتا القص واللصق. إسناد قيمة إلى خلية معينة. إضافة صفحة عمل جديدة نُضيف صفحات جديدةً عن طريق التعليمة التالية: Sub add_sheet () Worksheets.add End Sub تُضاف الصفحة بالاسم الافتراضي بهذه الطريقة، وذلك حسب الترقيم الافتراضي (… ,sheet1, sheet2, sheet3)؛ أما إذا أردنا وضع اسم معين للصفحة، فيمكننا ذلك عن طريق التعليمة التالية: Sub add_sheet() Worksheets.add.name = name End Sub حيث تُعبر name عن اسم اختياري للصفحة. تحديد الخلايا يمكننا تحديد خلية أو مجموعة من الخلايا عن طريق التعليمة التالية: Sub selection() Range("عنوان الخلية").Select End Sub عمليتا النسخ واللصق لدينا عدة حالات يمكن استخدامها لنسخ ولصق الخلايا: النسخ واللصق مباشرة تختلف الآلية هنا باختلاف مكان لصق البيانات المنسوخة، ولدينا عدة أشكال: اللصق في نفس الصفحة. اللصق في صفحة أخرى. اللصق في ملف آخر. اللصق في نفس الصفحة الأوامر المسؤولة عن العمليتين هي: Sub Range_Copy_paste() Range("الخلية التي نريد نسخها").Copy Range("الخلية التي سنلصق فيها المحتوى المنسوخ") Range("المجال الذي نريد نسخه").Copy Range("المجال الذي سنلصق فيه المحتوى المنسوخ") Range("المجال الذي نريد نسخه").Copy Range("بداية مجال اللصق للمحتوى المنسوخ") End Sub نلاحظ وجود فراغ يفصل بين التعليمة Range(" ").Copy والتعليمة الخاصة باللصق، ويجب أن تكونا في نفس السطر البرمجي. مثال لدينا البيانات التالية، ونريد نسخ الخلايا إلى أماكن مختلفة في نفس الصفحة، لذا نكتب الإجراء التالي: Sub Range_Copy_paste() Range("A1").Copy Range("C1") Range("A1:A3").Copy Range("D1:D3") Range("A1:A3").Copy Range("D1") End Sub نلاحظ أن اللصق يحصل بكامل ما تحتويه الخلية من تنسيقات ومعادلات وبيانات. اللصق في صفحة أخرى لاستعمال هذه الطريقة للنسخ من صفحة واللصق في صفحة أخرى تكون التعليمات كما يلي: Sub Range_Copy_paste_in_other_sheet() Worksheets("الصفحة التي سننسخ منها البيانات").Range("الخلية التي نريد نسخها").Copy Worksheets("الصفحة التي سننسخ البيانات إليها").Range("الخلية التي سنلصق فيها المحتوى المنسوخ") End Sub اللصق في ملف آخر نتعامل مع النسخ من ملف إكسل إلى آخر بنفس الأسلوب، وتكون التعليمات كالتالي: Sub Range_Copy_paste_in_other_workbook() Workbooks("اسم الملف الذي سننسخ منه البيانات.xlsx")_ .Worksheets("الصفحة التي سننسخ منها البيانات").Range("الخلية التي نريد نسخها").Copy_ Workbooks("اسم الملف الذي سننسخ إليه البيانات.xlsx")_ .Worksheets("الصفحة التي سننسخ البيانات إليها").Range("الخلية التي سنلصق فيها المحتوى المنسوخ") End Sub مثال لدينا البيانات التالية، ونريد نسخها مرةً إلى صفحة أخرى ومرةً إلى ملف آخر، لذا نكتب الإجراء التالي: Sub Range_Copy_paste_in_other_sheet() Worksheets("Sheet1").Range("A1").Copy Worksheets("Sheet2").Range("A1") Workbooks("Book1.xlsx").Worksheets("Sheet1").Range("A1").Copy _ Workbooks("Book2.xlsx").Worksheets("Sheet1").Range("A1") End Sub النسخ واللصق عن طريق الإسناد يمكننا هنا جعل خلية تأخذ قيمة خلية أخرى عن طريق الإسناد، وتكون التعليمات كالتالي: Sub Paste_Values_Examples() Range("الخلية التي نريد النسخ إليها").Value = Range("الخلية التي نريد نسخها").Value Range("المجال الذي نريد نسخه").Value = Range("المجال الذي سنلصق فيه المحتوى المنسوخ").Value End Sub ونتعامل مع النسخ من صفحة إلى أخرى ومن ملف إلى آخر بنفس الأسلوب. مثال بالعودة إلى المثال السابق نريد نسخ البيانات في نفس الصفحة، ومرةً أخرى في صفحة ضمن نفس الملف، ومرةً ثالثةً في ملف آخر مستقل، لذا تكون لدينا التعليمات كالتالي: Sub Paste_Values_Examples() النسخ واللصق ضمن نفس الصفحة Range("C1").Value = Range("A1").Value Range("D1:D3").Value = Range("A1:A3").Value النسخ واللصق في صفحة أخرى Worksheets("Sheet2").Range("A1").Value = Worksheets("Sheet1").Range("A1").Value النسخ واللصق في ملف آخر Workbooks("file2.xlsm").Worksheets("Sheet1").Range("A1").Value _ =Workbooks("file1.xlsm").Worksheets("Sheet1").Range("A1").Value End Sub نلاحظ في هذه الطريقة أن اللصق يكون للقيمة فقط، ويتجاهل التنسيقات بشكل كامل. النسخ واللصق الخاص يمكننا نسخ البيانات واستعمال اللصق الخاص -كما في مايكروسوفت إكسل- باستعمال التعليمات التالية: عند النسخ واللصق في نفس الصفحة Sub PasteSpecial_Examples() Range("الخلية التي نريد نسخها").Copy Range("الخلية التي نريد لصق المحتوى فيها").PasteSpecial Paste: = type_of_paste End Sub عند النسخ واللصق في صفحة أخرى Sub PasteSpecial_Examples() Worksheets("اسم الصفحة التي تنسخ منها البيانات").Range("المجال الذي نريد نسخه").Copy Worksheets("اسم الصفحة التي سنلصق فيها البيانات").Range("المجال الذي سنلصق فيه البيانات").PasteSpecial Paste: = type_of_paste End Sub عند النسخ واللصق في ملف آخر Sub PasteSpecial_Examples() Workbooks("اسم الملف الذي ننسخ منه البيانات.xlsx").Worksheets("اسم الصفحة").Range("المجال الذي نريد نسخه").Copy Workbooks("اسم الملف الذي سننسخ إليه البيانات.xlsx")_ .Worksheets("الصفحة التي سننسخ البيانات إليها").Range("الخلية التي سنلصق فيها المحتوى المنسوخ")_ .PasteSpecial Paste: = type_of_paste End Sub حيث تُعبر type_of_paste عن نوع اللصق الخاص الذي نريده، وفيما يلي أهم أشكاله: xlPasteAll لصق الخلايا مع التنسيقات. xlPasteAllExceptBorders لصق الخلايا مع التنسيقات عدا حدود الخلية. xlPasteColumnWidths لصق عرض العمود المنسوخ. xlPasteComments لصق التعليقات. xlPasteFormats لصق التنسيقات فقط. xlPasteFormulas لصق المعادلات أو الدوال المستخدمة في خلايا المصدر. xlPasteFormulasAndNumberFormats لصق المعادلات أو الدوال المستخدمة في خلايا المصدر بالإضافة لتنسيقات الأرقام. xlPasteValidation لصق عمليات التحقق من صحة البيانات. xlPasteValues لصق المحتوى فقط بدون أية تنسيقات أو معادلات. مثال لنَعُد إلى المثال السابق وننسخ الخلية A1، ثم نُلصق البيانات بشكل خاص في خلايا العمود D باستعمال بعض الأنواع السابقة من اللصق الخاص، لذا نكتب التعليمات التالية: Sub PasteSpecial_Examples() Range("A1").Copy Range("D1").PasteSpecial Paste:=xlPasteAll Range("D3").PasteSpecial Paste:=xlPasteAllExceptBorders Range("D5").PasteSpecial Paste:=xlPasteFormats Range("D7").PasteSpecial Paste:=xlPasteValues End Sub نعيد كتابة الإجراء الخاص بالمثال السابق بدون التعليمة Paste:= لنجده يعمل دون أية أخطاء: Sub PasteSpecial_Examples() Range("A1").Copy Range("D1").PasteSpecial xlPasteAll Range("D3").PasteSpecial xlPasteAllExceptBorders Range("D5").PasteSpecial xlPasteFormats Range("D7").PasteSpecial xlPasteValues End Sub إلغاء تحديد الخلايا المنسوخة كما وجدنا في المثال السابق، بقي التحديد يحيط بالخلية المنسوخة مسبقًا بعد الانتهاء من عمليتي النسخ واللصق، ولإلغاء التحديد نضيف التعليمة التالية إلى الشيفرة: Sub PasteSpecial_Examples() Application.CutCopyMode = False End Sub تأخذ التعليمة إما القيمة True التي تُبقي التحديد وهي القيمة الافتراضية، أو القيمة False التي تُلغيه. عمليتا القص واللصق يمكننا إجراء عملية القص بنفس الطريقة المباشرة لعملية النسخ، كما يلي: Sub Range_Copy_paste() Range("الخلية التي نريد نسخها").Cut Range("الخلية التي سنلصق فيها المحتوى المنسوخ") Range("المجال الذي نريد نسخه").Cut Range("المجال الذي سنلصق فيه المحتوى المنسوخ") Range("المجال الذي نريد نسخه").Cut Range("بداية مجال اللصق للمحتوى المنسوخ") End Sub ويمكن تنفيذ اللصق في صفحة أخرى، أو في ملف آخر مثل عملية النسخ. مثال لنَعُد إلى المثال السابق حيث نريد قص 7 خلايا من العمود A ولصقها في عمود آخر، ثم قصها مرةً أخرى ولصقها في الصفحة الثانية، كما نريد قص 7 خانات من العمود B ولصقها في الملف الثاني، لذا تكون التعليمات كالتالي: Sub Paste_Values_Examples() Range("A1:A7").Cut Range("D1") Worksheets("Sheet1").Range("D1:D7").Cut Worksheets("Sheet2") _ .Range("A1") Workbooks("file1.xlsm").Worksheets("Sheet1").Range("B1:B7").Cut _ Workbooks("file2.xlsm").Worksheets("Sheet1").Range("A1") End Sub إسناد قيمة إلى خلية معينة نستطيع إسناد قيمة إلى خلية؛ إما بإسناد قيمة مباشرة، أو بإسناد قيمة مساوية لقيمة خلية أخرى، كالتالي: إسناد قيمة مباشرة عن طريق التعليمة التالية: Range("عنوان الخلية") = "القيمة التي نريد إسنادها" إسناد قيمة مساوية لقيمة خلية أخرى عن طريق التعليمة التالية: Range("عنوان الخلية") = Range("عنوان الخلية التي سنُسند قيمتها للخلية الأخرى").value مثال لنطبق التعليمتين السابقتين على بياناتنا، بحيث نُسند قيمة الخلية B5 إلى الخلية A3، ونسند القيمة أحمد في الخلية A10، لذا نكتب الإجراء التالي: Sub attribution() Range("A3") = Range("B5").Value Range("c10") = 61 End Sub خاتمة تُعَد هذه الأوامر -رغم صغر حجمها وأفعالها البسيطة- من الركائز الأساسية والمهمة في صناعة برمجيات الإكسل عن طريق الفيجوال بيسك، بغض النظر عن حجم البرنامج وعدد العمليات التي يؤديها بشكلٍ دائم، لذا لا بد لنا من فهم عملها بطريقة صحيحة، ومعرفة خصائصها وآلية تكوين أجزاء الشيفرات البرمجية عن طريقها. اقرأ أيضًا التفاعل مع المستخدم في مايكروسوفت إكسل باستخدام VBA الحلقات التكرارية في مايكروسوفت إكسل باستخدام VBA العمليات الشرطية في مايكروسوفت إكسل باستخدام VBA مدخل إلى البرمجة باستخدام VBA في مايكروسوفت إكسل
  6. عند كتابة الإجراءات نُجهّز كل شيء للتعامل مع أوامر المستخدم النهائي للتطبيق، ولكن بغض النظر عن مدى خبرتك في كتابة الشيفرات في VBA، فإنّ الأخطاء دائمًا ستكون جزءًا من الشيفرة سواءً كنت مبتدئًا أو خبيرًا، ولكن الفرق هنا بين المبتدئ والخبير هو معرفة كيفية التعامل مع الأخطاء واستخدامها فعّالية. أنواع الأخطاء في البداية لابد لنا من معرفة الأنواع المختلفة للأخطاء التي من المحتمل أن تواجهنا في عملية البرمجة، فهناك أربعة أنواع من الأخطاء في VBA وهي: أخطاء في بنية التركيب البرمجي (الشيفرة البرمجية) Syntax errors. أخطاء التجميع Compilation errors. أخطاء التشغيل Runtime errors. أخطاء منطقية Logical Errors. أخطاء في بنية التركيب البرمجي Syntax errors هي أخطاء تحدث في بناء الشيفرة، مثل: نسيان قوس مفتوح، أو نسيان كتابة جزء من تعليمة. نجد في الإجراء الموضَّح بالصورة أن التركيب خاطئ، حيث أنّ الشرط يفتقد لكلمة Then، وعند كتابة التعليمات في VBA، فسيتحقق المحرّر من كل الجملة بمجرد الضغط على الزر Enter، فإذا وجد شيئًا مفقودًا في بناء التركيب، فسيعرض رسالةً على الفور تحتوي بعض النص الذي يمكن أن يساعدك في فهم الجزء المفقود. للتأكد من رؤية المحرّر لأخطاء التركيب البرمجي كلما كان هناك شيء مفقود، فنحتاج إلى التأكد من تمكين التحقّق من بناء الجملة Auto syntax check، وذلك من قائمة Tools في واجهة المحرّر، حيث نضغط على الخيار options لتظهر لنا النافذة التالية: نتأكد من تبويب Editor بأن الخيارAuto syntax check مُفعّل، فإذا كان غير مُفعّل فإن المحرّر سيُحدد لك السطر الذي يحوي الخطأ ويُلّونَه بلون أحمر ولكن بدون إعلامنا ما هو نوع الخطأ. أخطاء التجميع Compilation errors تحدث عندما يكون هناك جزء مفقود من النص ومطلوب في نفس الوقت، تتشابه هذه الأخطاء قليلًا مع المجموعة السابقة لكن الفرق بينهما بينهما يكمن في كون الأخطاء في بنية التركيب تُظهر الخطأ في حال كان السطر البرمجي فيه جزء مفقود، أمّا أخطاء التجميع فتظهر عند تشغيل الشيفرة ويكون سطر بالكامل مفقود، أي أن صيغة الشيفرة صحيحة في سطر ما ولكنها غير صحيحة عند معالجة جميع شيفرة الإجراء أو المشروع ككتلة واحدة، ومن الأمثلة على ذلك: تعليمة IF الشرطيّة بدون عبارة End IF المقابلة لها. حلقة For التكرارية بدون عبارة Next المقابلة لها. استدعاء إجراء غير موجود، أو موجود ولكن فيه معلومات خاطئة. عدم تعريف أحد المتغيّر ات. أخطاء التشغيل Runtime errors هي الأخطاء التي تحدث أثناء تشغيل الشيفرة، وذلك عندما نكون قد تجاوزنا النوعين السابقين من الأخطاء، أي في حال وجود خطأ من أحدهما فله أولوية الظهور بين الأخطاء ولا يظهر خطأ التشغيل قبل معالجته، ومن الأمثلة على الأخطاء وقت التشغيل: إدخال بعض البيانات في صفحة ما ضمن الملف الذي نعمل عليه ولكن هذه الصفحة غير موجودة (سواءً حُذفت أو تغيّر اسمها). تصميم إجراء يحتوي عمليات على ملف ما وعند التشغيل لم يَجِد المحرّر هذا الملف، عندها نحصل على خطأ التشغيل. في هذا النوع من الأخطاء نجد أن المحرّر سيُظهر لنا نافذةً تحتوي على خطأ من النوع أخطاء التشغيل Runtime errors، ولكنها مفيدة أكثر من النوعين السابقين، حيث نجد أن محتوى الرسالة هو تفصيل شبه كامل عن الخطأ وسببه، وعند الضغط على الزر Debug، فسيعمل المحرّر على تمييز جزء الشيفرة الذي يؤدي إلى الخطأ. أخطاء منطقية Logical Errors لا تؤدي هذه الأخطاء إلى إيقاف تنفيذ الشيفرة ولكنها قد تؤدي إلى نتائج خاطئة يمكن أن تكون أصعب أنواع الأخطاء اكتشافًا، وبالتالي فإن إصلاحها يكون أصعب، حيث أن المحرّر لا يستطيع تمييزها وتحتاج إلى الإصلاح اليدوي، أمثلة على ذلك: تعريف متغيّرين تجري عليهما عملية جمع ضمن إجراء ما وعند كتابة العملية وضع إشارة الضرب بدل إشارة الجمع بين المتغيّرين. كتابة حلقة غير منتهية مثل فحص الخلايا الفارغة في عمود، ولم نضع له شرط يحدد قيمة النهاية للفحص. معالجة الأخطاء هنالك ثلاث طرق للمعالجة يمكننا استخدامها وهي: عرض الخطأ وإيقاف الشيفرة. تجاهل الخطأ وإكمال الشيفرة. تجاهل الخطأ والذهاب لموقع معين في الشيفرة. وجميعها تأخذ الصيغة العامة التالية: On Error statement حيث أن On Error تفيد توجيه المحرّر إلى ما نريد تنفيذه لمعالجة الخطأ عند وجوده، وstatement ما نريد من المحرّر فعله لمعالجته، ولدينا 4 حالات للمعالجة: on Error Go To 0 on Error Resume Next on Error Go To [Label] on Error Go To -1 المعالجة باستخدام on Error Go To 0 هو السلوك الافتراضي في VBA، بمعنى آخر إذا كنّا لا نستعمل أيًا من أساليب معالجة الأخطاء، فسينفّذ هذا النوع تلقائيًا عند وجود خطأ ما، حيث أن مُعالج الشيفرة يتوقف ويعرض رسالة الخطأ، وهنا يتطلب التطبيق تدخل المستخدم مع الشيفرة لمعالجة الخطأ حتى يتمكّن من متابعة تنفيذ الشيفرة. مثال ليكن لدينا الإجراء التالي الذي يعمل على حساب بعض المعادلات Sub UsingDefault() Dim x As Long, y As Long x = 6 y = 6 / 0 End Sub عند تشغيل الشيفرة التالية، فستظهر رسالة الخطأ من النوع on Error Go To 0. يفيدنا هذا النوع من المعالجات في تحديد موقع الخطأ ولكن له عدة مساوئ، حيث لا يمكن للمستخدِم الاستمرار بالعمل على التطبيق دون إصلاح هذا الخطأ، ويُعَد التطبيق غير مناسب للمستخدِم النهائي، وهو يُعَد من الأخطاء غير المهنية وتجعل التطبيق غير مستقر. المعالجة باستخدام on Error Resume Next يؤدي استخدام هذا النوع إلى تجاهل السطر الذي يحتوي على الخطأ والمتابعة بدون تنفيذه. هناك مواضع محددة قد يكون هذا النوع من الحلول مفيدًا، ولكن في الغالب يُفضّل عدم استخدامه إلا للضرورة، لأنه من الممكن أن يؤثِّر الخطأ على كتلة التطبيق وينتهي بنا المطاف بالحصول على بيانات خاطئة أو غير صالحة، حيث أن المستخدِم لن يعلم بحدوث الخطأ أثناء التشغيل. مثال لنأخذ نفس المثال السابق، حيث عند استعمال هذه الصيغة يصبح شكل الإجراء كالتالي: Sub UsingDefault() On Error Resume Next Dim x As Long, y As Long x = 6 y = 6 / 0 End Sub نلاحظ أنه عند تشغيل الشيفرة بدون التعليمة، فسيُظهر لنا المحرّر رسالة الخطأ، أي أنه يعمل على النوع on Error Go To 0؛ أما عند وضع التعليمة on Error Resume Next فقد تجاهلَ المحرّر سطر الخطأ وأكمل قراءة الشيفرة. عند استخدامنا للتعليمة On Error Resume Next فإن الشيفرة تتجاهل الخطأ الذي نتوقع حدوثه، ولكن ماذا لو كان في الشيفرة أخطاء أخرى لم نتوقعها، هنا ستتجاهلها الشيفرة أيضًا. لذلك يجب أن نُعيد سياق فحص الأخطاء إلى الوضع الافتراضي لذا نستخدم هنا on Error Go To 0 بعد التعليمة التي نريد تجاهل خطأها. مثال آخر ليكن لدينا الإجراء التالي الذي يحدد الخلايا الفارغة ضمن عدة خلايا مُحددة: Sub SelectFormulaCells() Dim x As Long, y As Long On Error Resume Next Selection.SpecialCells(xlCellTypeBlanks).Select On Error GoTo 0 X=7 Y=7/0 End Sub عندما تكون الخلايا المحددة جميعها غير فارغة، فسينتج لدينا خطأ تشغيل، وهنا سيتجاهل المحرّر الخطأ الأول ولكن لا يتجاهل الثاني ويُظهر خطأ تشغيل عند السطر Y=7/0. المعالجة باستخدام ‪on Error Go To [Label] هي طريقة يمكنك من خلالها تحديد ما تريد فعله في حال وجود خطأ في الشيفرة البرمجية والصيغة العامة لها: Sub Test() On Error GoTo Label: this line causes an error (سطر يحتوي على خطأ) Exit Sub Label: code to handle the error End Sub حيث أن: Exit sub: تفيد هنا عدم انتقال الشيفرة للجزء التالي إذا كانت التعليمات سليمةً ولا تحوي أخطاء. label: العنوان الذي ستنتقل إليه الشيفرة عند وجود خطأ في القسم الأول، ويمكن أن يحتوي رسالةً أو تعليمات جديدة. مثال Sub Errorhandler() Dim x As Long, y As Long On Error GoTo ErrMsg X = 12 Y = 20 / 0 Exit Sub ErrMsg: MsgBox "There seems to be an error" End Sub عند حدوث خطأ ما هنا فستُنفذ الأسطر قبل سطر الخطأ، حيث أنه يُسند القيمة 12 إلى المتغيّر x ولكن عند حدوث الخطأ لا تُسند القيمة للمتغيّر y، وبالتالي لا يُنفذ باقي الشيفرة أي أنه أيضًا لا تُسند القيمة إلى z، عندها ينتقل تنفيذ الشيفرة إلى الجزء ErrMsg المعالجة باستخدام on Error Go To -1 يُستخدZم هذا النوع لمسح الخطأ الحالي من ذاكرة VBA بدلًا من تحديد سلوك معيّن، حيث أن ذاكرة VBA تسمح لنا بالتعامل مع خطأ واحد وتحفظه بالذاكرة، إذ لديها مكان واحد لحفظ الأخطاء، وتعمل هذه التعليمة على تفريغ هذا المكان للخطأ التالي إن وُجِد، ومن غير المحتمل أن نستخدِم هذه التعليمة في عملنا. مثال ليكن لدينا جزء من إجراء كالتالي: Sub Errorhandler() Dim x As Long, y As Long, Z As Long, A As Long, B As Long On Error GoTo ErrMsg X = 12 Y = 20 / 0 Z = 30 Exit Sub ErrMsg: MsgBox "There seems to be an error" On Error GoTo ErrMsg2 A = 10 / 2 B = 35 / 0 Exit Sub ErrMsg2: MsgBox "There seems to be an error again" End Sub عند معالجة الخطأ الأول تستمر الشيفرة بتنفيذ ما تحتوي الأسطر التي بعد قسم معالجة الخطأ، ولكن عند الوصول لخطأ ثانٍ فسنحصل على خطأ من أخطاء التشغيل Runtime errors، بحيث لا ينقلنا المحرّر إلى جزء المعالجة الثاني ولهذا يجب علينا تفريغ الذاكرة أولًا وذلك عن طريق التعليمة On Error GoTo -1، عندها ينتقل الإجراء في الخطأ الثاني إلى قسم معالجة الخطأ الثاني ولا يظهر خطأ التشغيل Runtime error، وتصبح الشيفرة كالتالي: Sub Errorhandler() Dim x As Long, y As Long, Z As Long, A As Long, B As Long On Error GoTo ErrMsg X = 12 Y = 20 / 0 Z = 30 Exit Sub ErrMsg: MsgBox "There seems to be an error" On Error GoTo -1 On Error GoTo ErrMsg2 A = 10 / 2 B = 35 / 0 Exit Sub ErrMsg2: MsgBox "There seems to be an error again" End Sub خاتمة إن للأخطاء أهمية كبيرة في عمليات البرمجة فهي تعمل على تصحيح عمل الشيفرة ولكن بطريقة غير مباشرة، حيث تكمن أهميتها في اكتشاف المشاكل والأجزاء المفقودة من التعليمات، كما أن التطبيقات موجّهة لمستخدمين ربّما لا يكون لديهم معرفة بتعديل الأخطاء، أو حتى فهمها لذا يجب علينا أن نُعالج كافة الأخطاء وتقدير احتمالات حدوثها، ووضع حلول مسبقة لها ولهذا تُعَد معالجة الأخطاء من المهام الأساسيّة في عمليّة صناعة البرمجيات، ويجب إتقانها جيدًا لصناعة تطبيقات خالية من العيوب. اقرأ أيضًا الحلقات التكرارية في مايكروسوفت إكسل باستخدام VBA التفاعل مع المستخدم في مايكروسوفت إكسل باستخدام VBA العمليات الشرطية في مايكروسوفت إكسل باستخدام VBA
  7. تتفاعل إجراءات الفيجوال بيسك مع المستخدم عن طريق نوعين من النوافذ، وهما: الرسائل الصندوقية MsgBox، وصناديق الإدخال InputBox. التعامل مع الرسائل النصية MsgBox تُستخدَم للتواصل والتفاعل مع المستخدِم، ومن خلالها يمكننا عرض المعلومات وطرح الأسئلة وحفظ الإجابات، كما يمكننا توجيهه لإجراء عمل ما في بعض الأحيان مثل (التأكد من الإغلاق، حفظ الملف قبل الإغلاق). الشكل العام للصيغة MsgBox(prompt,[buttons],[title],[help,context]) حيث أن: prompt: هو نص الرسالة التي ستظهر للمستخدِم، وهو مُعطى مطلوب. buttons: هي الأزرار التي سنضيفها للرسالة، وهو مُعطى اختياري، حيث أن القيمة الافتراضيّة له هي زر موافق. title: هو النص الذي سيظهر في شريط العنوان للرسالة، وهو مُعطى اختياري، حيث أن القيمة الافتراضيّة له هي Microsoft Excel. help,context: إرفاق ملف مساعد بمثابة دليل للمستخدم، وهو مُعطى اختياري ولا يُستخدم مع إكسل غالبًا. أشكال الرسائل المستخدمة في MsgBox يوجد خمس أجزاء تعمل على تشكيل الرسائل، أربعة منها أساسية وواحدة نادرة الاستخدام، بحيث نُدخلها كاملةً ضمن المُعطى button وهي: نوع الأزرار الظاهرة. نوع الأيقونات ضمن الرسالة. تعيين الزر الافتراضي. تعيين نوع الاستجابة. إضافة بعض الخصائص للرسالة. تحديد نوع الأزرار الظاهرة لدينا الأنواع التالية التي تُحدد عمل الرسائل عن طريق الأزرار المستخدَمة وهي: vbOKOnly: تعمل على إظهار الزر OK فقط، رقم التعريف الخاص به 0، وهو الإفتراضي عند عدم تحديد نوع الزر المستخدَم. +vbOKCancel: تعمل على إظهار الزر OK مع زر Cancel، ورقم التعريف الخاص به 1. vbAbortRetryIgnore: تعمل على إظهار الأزرار Abort بمعنى فشل العملية، وRetry لإعادة المحاولة، وIgnore بعنى تجاهل الخطأ؛ أما رقم التعريف الخاص به 2. vbYesNoCancel: تعمل على إظهار الأزرار Yes، وNo، وCancel التي تفيد هنا إلغاء العملية؛ أما رقم التعريف الخاص به فهو 3. vbYesNo: تعمل على إظهار الأزرار Yes، وNo ، ورقم التعريف الخاص به هو 4. vbRetryCancel: تعمل على إظهار الأزرار Cancel، وRetry، رقم التعريف الخاص به هو 5. نستطيع استخدام أحد هذه الأزرار ببساطة، ولكن نحتاج إلى تعريف متغيّر نوعه MsgBoxResult لتخزين نتيجة اختيار المستخدِم فيه لاستعمالها لاحقًا في تنفيذ الأوامر. ولا نُعرّف هذا المتغيّر في حال استخدامنا للزرvbOKOnly فقط. آلية حفظ نتيجة اختيار المستخدم على فرض أننا نستعمل الزر من النوع vbYesNoCancel، فسيكون له ثلاثة احتمالات لاختيار المستخدم، ولتكن لدينا الصيغة التالية: Sub test1() Dim result As VbMsgBoxResult result = MsgBox("هل أنت متأكد من الإغلاق", vbYesNoCancel) End Sub هنا تكون النتيجة إحدى الاحتمالات التالية vbYes، وvbNo، وvbCancel. وعند الضغط على أحد هذه الأزرار، فستُحفظ قيمته في المتغيّر بحيث يمكننا الاستفادة منها لاحقًا في تنفيذ بعض التعليمات اعتمادًا عليها، وبنفس الطريقة تعمل باقي الأزرار. كما يمكننا استخدام رقم التعريف عوضًا عن الاسم، أي لاستعمال الزر vbYesNoCancel نضع في المُعطى الخاص به الرقم المُعرِّف له بدل اسم الزر وهو 3، والذي يعطي نفس النتيجة. Sub test1() Dim result As VbMsgBoxResult result = MsgBox("هل أنت متأكد من الإغلاق", 3) End Sub تحديد نوع الأيقونات الظاهرة vbCritical: إظهار علامة X، ورقم التعريف الخاص به 16. vbQuestion: إظهار علامة الاستفهام، ورقم التعريف الخاص به 32. vbExclamation: إظهار علامة التعجب الصفراء المثلثة، ورقم التعريف الخاص به 48. vbInformation: إظهار علامة التعجب الزرقاء الدائرية، ورقم التعريف الخاص به 64. يمكننا إضافة الأيقونة للرسالة عن طريق الوسيطة buttons، وذلك بإضافة اسم الأيقونة إلى اسم الزر، لنفصل بينهما بإشارة +، وبالعودة للمثال السابق وإضافة الأيقونة سنحصل على الصيغة التالية: Sub test1() Dim result As VbMsgBoxResult result = MsgBox("هل أنت متأكد من الإغلاق", vbYesNoCancel+ vbInformation) End Sub أو بالصيغة المرجعية لرقم الخاصية: Sub test1() Dim result As VbMsgBoxResult result = MsgBox("هل أنت متأكد من الإغلاق", 3 + 64) End Sub تحديد الزر الافتراضي يمكننا تحديد أي الأزرار يكون هو الافتراضي عند الضغط على زر Enter من لوحة المفاتيح. vbDefaultButton1: الزر الأول هو الافتراضي، ورقم التعريف الخاص به 0. vbDefaultButton2: الزر الثاني هو الافتراضي، ورقم التعريف الخاص به 256. vbDefaultButton3: الزر الثالث هو الافتراضي، ورقم التعريف الخاص به 512. vbDefaultButton4: الزر الرابع هو الافتراضي، ورقم التعريف الخاص به 768. تحديد نوع الاستجابة vbApplicationModal: عند استخدامها تُجبر المستخدِم على الاستجابة للرسالة قبل المتابعة، ورقم التعريف الخاص به 0. vbSystemModal: عند استخدامها فإن جميع برامج النظام تتوقف حتى يستجيب المستخدم للرسالة، ورقم التعريف الخاص به 4096. إضافة بعض الخصائص للرسالة vbMsgBoxHelpButton: إظهار زرّ Help على الرسالة، ورقم التعريف الخاص به 16384. vbMsgBoxSetForeground: جعل نافذة الرسالة في مقدمة النوافذ المفتوحة، ورقم التعريف الخاص به 65536. vbMsgBoxRight: محاذاة نص الرسالة للجهة اليُمنى، ورقم التعريف الخاص به 524288. vbMsgBoxRtlReading: اتجاه الكتابة من اليمين لليسار للغة العربية، ورقم التعريف الخاص به 1048576. مثال تطبيقي ليكن لدينا جدول البيانات التالية ونريد كتابة إجراء يحذف البيانات ضمن الجدول، ولكن قبل الحذف نريد من المستخدم تأكيد العملية عن طريق MsgBox وفي حال لم يوافق على الحذف تظهر له رسالة أخرى تُعلمه أن البيانات لم تُحذف: لكتابة الإجراء الخاص بالعمليات السابقة، نُعرّف الإجراء ونضع له الاسم "clear"، ثم نُعرّف متغيّر من النوع VbMsgBoxREsult ونُسند إليه الرسالة التي ستظهر للمستخدِم، والتي تحتوي على رسالة تأكيد عملية الحذف. بحيث يكون الزر فيها من النوع vbYesNo، والأيقونة من النوع vbQuestion، بالإضافة لعنوان الرسالة الذي يُعبّر عن تحذير تصبح الصيغة كالتالي: result = MsgBox("هل أنت واثق من حذف البيانات", vbYesNo + vbQuestion, "تحذير") لاستخدام نتيجة اختيار المستخدم نضع شرطًا، بحيث إذا ضغط المستخدِم على الزر yes، فسيُنفِّذ عملية حذف البيانات؛ أما إذا ضغط على الزر No، فينتقل للشق الثاني من الشرط وهو إظهار رسالة بأن البيانات لم تُحذف، نكتب الشرط بالصيغة التالية: If result = vbYes Then ActiveSheet.Range("D12:H29").ClearContents Else MsgBox ("البيانات لم تُحذف") End If هكذا نكون قد حصلنا على الإجراء المطلوب ويصبح الإجراء كاملًا كالتالي: Sub Clear() Dim result As VbMsgBoxResult result = MsgBox("هل أنت واثق من حذف البيانات", vbYesNo + vbQuestion, "تحذير") If result = vbYes Then ActiveSheet.Range("A2:H12").ClearContents Else MsgBox ("البيانات لم تُحذف") End If End Sub التفاعل مع المستخدم عبر صندوق الإدخال عن طريق InputBox مثل سابقتها، تعمل على إظهار رسالة للمستخدِم، ولكن عن طريقها يستطيع المستخدِم إدخال قيمة ما عبر صندوق إدخال القيم، ولدينا نوعان منها. الشكل العام للصيغة InputBox(prompt, [ title ], [ default ], [ xpos ], [ ypos ], [ helpfile, context ]) هذه التعليمة خاصّة بلغة فيجوال بيسك عمومًا، حيث أن: prompt: هو نص الرسالة التي ستظهر للمستخدِم، وهو مُعطى مطلوب. title: هو النص الذي سيظهر في شريط العنوان للرسالة، وهو مُعطى اختياري، حيث أن القيمة الافتراضيّة له هي *Microsoft Excel*. default: هي القيمة الافتراضيّة في صندوق الإدخال، وهو مُعطى اختياري. xpos: هي الموقع الأفقي لظهور الرسالة في الصندوق، وهو مُعطى اختياري، تكون القيمة الافتراضيّة له Left. ypos: هي الموقع الشاقولي لظهور الرسالة في الصندوق وهو مُعطى اختياري، وتكون القيمة الافتراضيّة له Top. help,context: إرفاق ملف مساعد بمثابة دليل للمستخدم، وهو مُعطى اختياري ولا يُستخدم مع إكسل غالبًا. expression.InputBox (Prompt, [ title ], [ default ], [ xpos ], [ ypos ], [ helpfile, context ], [Type]) هذه التعليمة خاصة بتطبيقات أوفيس مع الفيجوال بيسك، حيث أن المعطيات هي نفسها ولكن مع بعض الزيادات: expression: عن طريقها نُحدد كائن من كائنات الإكسل الذي سنطبق التعليمات عليه مثل الكائن Application. type: تحدد نوع البيانات التي سيُدخلها المستخدِم، ولدينا عدة أنواع كما هو موضح في الصورة. آلية العمل والفرق بين الصيغتين نُعرِّف متغيّرات تعمل على حفظ القيمة التي سيُدخلها المستخدِم، ثم نُسند التعليمة إلى هذا المتغيّر، ولكن يوجد فرق جوهري وهو في الصيغة الأولى، فعند وجود خطأ في إدخال قيمة بغير الصيغة التي عرّفنا فيها المتغيّر، فسيوقف المحرّر الإجراء بدون معرفة ما هو نوع الخطأ، حيث سيُحدد السطر الذي يحتوي على هذا الخطأ باللون الأصفر فقط؛ أما في الصيغة الثانية، فسيُحدد المحرّر نوع الخطأ ويُظهر رسالة تُعلِم المستخدم أنه أدخل صيغة خاطئة. مثال لدينا الملف التالي الذي يحتوي على صفحتين، الأولى تسمح لنا بتسجيل الدخول عن طريق صندوقي إدخال الأول لاسم المستخدم، والثاني لكلمة المرور، وإظهار الصفحة الثانية التي تحتوي على بيانات الشركة. حيث أنّ الصفحة الثانية مخفية عن طريق تغيير قيمة الخاصية visible لها إلى القيمة xlSheetVeryHidden، وهي خاصية لا تسمح لنا بإظهار الصفحة من ملف الإكسل بالطريقة التقليدية، إنما فقط عن طريق الإجراءات أو عن طريق القائمة Property التي تحدثنا عنها في درس التعريف عن الواجهة الرئيسية للمحرّر: نبدأ الإجراء بتعريف المتغيّرات التي سنُخزن فيها القيم التي سيُدخلها المستخدِم لموازنتها فيما بعد مع القيم الصحيحة لتسجيل الدخول، وتكون لدينا الصيغة التالية: Dim UserName As String Dim Password As Double UserName = InputBox("Enter your user name", "Username", "Your Name") Password = Application.InputBox("Enter your password", "Password", Type:=1) كتبنا المُعطى Type:=1 بهذا الشكل وهو طريقة ثانية لكتابة قيم المُعطيات عندما نريد تجاوز المُعطيات التي تسبق المُعطى الذي نريده، ولو أردنا كتابتها بالصيغة الأساسية فستكون كالتالي: Application.InputBox("Enter your password", "Password", , , , ,1) بعد تعريف المتغيّرات إسناد القيم من صناديق الإدخال لها بقي لنا أن نضع شرطًا يتحقّق من أن ما أدخله المستخدِم يطابق شروط الدخول إلى صفحة البيانات أم لا ويكون الشرط بالصيغة التالية: If UserName = "Maher" And Password = 123 Then Sheets("data").Visible = xlSheetVisible Else MsgBox "Incorrect Username or Password" End If يُصبح الإجراء بالكامل كالتالي: Sub check_user() Dim UserName As String Dim Password As Double UserName = InputBox("Enter your user name", "Username", "Your Name") Password = Application.InputBox("Enter your password", "Password", Type:=1) If UserName = "Maher" And Password = 123 Then Sheets("data").Visible = xlSheetVisible Else MsgBox "Incorrect Username or Password" End If End Sub عند إدخال اسم مستخدم أو كلمة مرور غير صحيحة، سيُنفِّذ الإجراء الشق الثاني من الشرط، وهي رسالة تفيد بأن اسم المستخدِم أو كلمة المرور خاطئة؛ أما عند إدخال بيانات صحيحة، فسيُنفِّذ الشق الأول من الشرط عندها تظهر الصفحة Data. خاتمة نلاحظ أن صندوق الرسائل وصندوق الإدخال يسمح لنا بزيادة ضبط التحكم بالعمليات وتوجيه المستخدم بطريقة منظمة ودقيقة، وكلما كانت العمليات دقيقةً ومنظمةً أكثر، حصلنا على بيانات صحيحة ومنظمة ومحميّة أكثر. وبدمج صناديق الإدخال وصناديق الرسائل مع الشروط، فسنحصل على إجراءات تُنجز الكثير من الأعمال بتنظيم وسرعة في آن واحد، وبنتائج تُحقّق لنا الكثير من الفائدة. اقرأ أيضًا الحلقات التكرارية في مايكروسوفت إكسل باستخدام VBA مدخل إلى البرمجة باستخدام VBA في مايكروسوفت إكسل العمليات الشرطية في مايكروسوفت إكسل باستخدام VBA
  8. نقضي الكثير من الوقت في تكرار المهام البسيطة في إكسل، ;قد تكون هذه المهام، مثل: تنسيق نطاقات متعددة، وإخفاء أوراق متعددة، والنسخ واللصق في العديد من المصنفات، وتطبيق عوامل التصفية على جداول متعددة. وقد تكون هذه المهام مضيعةً للوقت ومملةً للغاية، لكن لحسن الحظ يمكننا استخدام الحلقات في وحدات ماكرو VBA، لتكرار الإجراءات بسرعة كبيرة، بحيث يمكن إكمال المهام التي قد تستغرق ساعات لإنجازها يدويًا في غضون ثوانٍ باستخدام حلقة تكرارية. الحلقة التكرارية For Next Loop تعمل على تكرار التعليمات وفقًا لشرط نُسنده لمُتغيّر اختياري وتكون قيمة الفحص مناسبةً لعدد مرات التكرار التي نريد تنفيذها. الشكل العام لصيغة الحلقة For variable = Start To End Code Next Element حيث أن: variable: تمثل المُتغيّر الذي سيُحدد عدد مرّات تكرار الحلقة عن طريق قيمة البداية والنهاية له. Start: تمثل قيمة البداية للمُتغيّر. End: تمثل قيمة النهاية للمُتغيّر. Code: التعليمات التي سنُنفذ عليها التكرار. Next Element: تُعيد هذه التعليمة الحلقة للبداية لتطبيقها على العنصر التالي بإضافة 1 للمُتغيّر. مثال لتكن لدينا مثلًا البيانات التالية، بحيث نريد تغيير التنسيق للنصوص في الخلايا إلى خط غامق باستخدام إجراء يعمل على ذلك. نكتب الإجراء بالصيغة التالية: Sub test1() Dim counter As Integer For counter = 1 To 10 ActiveCell.Font.Bold = True ActiveCell.Offset(1, 0).Select Next counter End Sub آلية عمل الحلقة بعد أن عرّفنا المُتغيّر وأُسندت له قيمة البداية والنهاية في الحلقة، فستعمل التعليمة ActiveCell.Font.Bold = true على تغيير تنسيق الخط من العادي إلى الغامق، حيث ActiveCell هو عنصر الخلية المفعّلة (مكان توضّع المؤشر)، والعنصر Font هو خط الخلية، أمّا الخاصية Bold فتأخذ قيمتين true للخط الغامق وFalse للخط العادي، وهي القيمة الافتراضية لتنسيق الخط. بعدها ننتقل إلى التعليمة التالية، بحيث تعمل التعليمة (Offset(value1,value2 بالانتقال إلى خلية نُحدّدها عبر نطاق التعليمة، إذ تُمثِّل الوسيطة value1 مقدار الانتقال على العمود بدايةً من الخلية الحالية، أما الوسيطة value2 فتمثّل مقدار الانتقال على الصف بدايةً من الخلية الحالية. نريد الانتقال في مثالنا لخلية واحدة فقط للأسفل على العمود، فيكون المجال لدينا (Offset(1,0، أما الأمر Select فيجعل الخلية مفعّلة (نشطة). بعدها ننتقل إلى التعليمة Next counter، حيث تنقل المُتغيّر إلى القيمة التالية وتكرر العملية إلى أن تصل لقيمة النهاية المُحددة للمُتغيّر. أشكال أخرى لكتابة الحلقة السابقة يمكن كتابة الحلقة بالشكل العكسي لمجال المُتغيّر. For variable = End To Start كما يمكننا التحكم بمقدار الزيادة في قيمة المُتغيّر للدورة التالية. For variable = End To Start Step value هنا لو كانت قيمة البداية 1 وقيمة النهاية 10 مثلًا وأردنا أن تكون خطوات الزيادة للمُتغيّر هي خطوتين في كل دورة، فستُنفذ الحلقة السابقة 5 عمليات تكرار فقط. الحلقة التكرارية For Each Next Loop تُعَد من أقوى تقنيّات الماكرو، وهذا النوع هو الأكثر شيوعًا من الحلقات، حيث تسمح لنا حلقة For Next Loop بالمرور عبر مجموعة من العناصر في إكسل وتكرار بعض العمليات عليها. وقد تتضمن مجموعات العناصر ما يلي: خلايا في نطاق. أوراق العمل في مصنف. المصنفات على الحاسوب. الجداول المحورية في ورقة العمل. الحقول المحورية في جدول محوري. الأشكال الموجودة في ورقة العمل، وأي كائن آخر تتفاعل معه في إكسل. تتمثل مهمة For Next Loop في تنفيذ نفس الإجراءات (سطور التعليمات البرمجية) على كل عنصر في المجموعة. الشكل العام للحلقة For Each Object In collection Code Next Object حيث أن: Object: تمثل الكائن الذي سننفذ الحلقة عليه. collection: تمثل مجموعة الكائنات التي تمثل الكائن Object. Code: مجموعة التعليمات التي سيكررها الإجراء. Next Object: تُعيد هذه التعليمة الحلقة للبداية لتطبيقها على الكائن التالي. مثال ليكن لدينا ملف العمل التالي الذي يحتوي على مجموعة من الصفحات المخفية. إظهار هذه الصفحات يدويًا سيستغرق بعض الوقت، ولكن يمكننا كتابة إجراء بسيط يحوي حلقةً تكراريةً تعمل على تغيير الخاصية visible لكل صفحة إلى القيمة xlSheetVisible والتي تجعل الصفحة ظاهرة، ويكون الإجراء بالصيغة التالية: Sub test2() Dim ws As Worksheet For Each ws In ActiveWorkbook.Worksheets ws.Visible = xlSheetVisible Next ws End Sub آلية عمل الحلقة عرّفنا المُتغيّر ws على أنه عنصر صفحة، ثم وضعناه في الحلقة التكرارية على أنه عنصر المجموعة. التعليمة ActiveWorkbook.Worksheets تُحدد مجموعة عناصر صفحات الملف الحالي الذي نعمل عليه لأننا نريد تكرار العملية على جميع أوراق العمل في ActiveWorkbook. يُحدد المُتغيّر ws العنصر الأول من المجموعة، بحيث تعمل تعليمة الحلقة التكرارية بالمرور على صفحات الملف واحدة تلو الأخرى، وتُستبدَل الخاصية xlSheetHidden بالخاصية xlSheetVisible، إذ أن التعليمة Next تعمل على نقل العملية إلى العنصر الثاني بالمجموعة، ثم الثالث، وهكذا إلى الوصول لآخر عنصر(صفحة) في المجموعة، وعندها يتوقف التكرار الحلقي ويستمر الماكرو إلى السطر التالي من التعليمات البرمجية وهو إنهاء الإجراء End sub. الترتيب الذي تعمل به كل حلقة تبدأ الحلقة For each دائمًا عند العنصر الأول في المجموعة ويتكرر حتى العنصر الأخير بالترتيب الذي يظهر به في إكسل، حيث يعتمد هذا على رقم فهرس العناصر في المجموعة، وفيما يلي بعض الأمثلة على الترتيب الذي تعمل به الحلقة للعناصر الشائعة: المصنفات: يبدأ في المصنف الذي فُتح أولًا، وتعمل الحلقات على المصنفات بالترتيب الذي فُتحت فيه، بحيث يتعيّن رقم فهرس للمصنفات عند فتحها. أوراق العمل: تبدأ من علامة تبويب الورقة الأولى في المصنف، وتتكرر إلى الأخيرة بالترتيب الذي تظهر به علامات التبويب في المصنف. الخلايا: تبدأ الحلقات من اليمين إلى اليسار (وبالعكس في النسخ الإنكليزية) ثم إلى الأسفل، أي يبدأ في الخلية الأولى في النطاق ويتكرر إلى العمود التالي في نفس الصف، ثم ينتقل إلى الصف التالي. الجداول والجداول المحورية: تبدأ بالعنصر الذي أُنشئ أولًا وتعمل الحلقات على عناصر الورقة بترتيب إنشاءها. ينطبق هذا المبدأ نفسه على العناصر الأُخرى التي نُنشئها في أوراق العمل، مثل: الأشكال، والمخططات، وما إلى ذلك. الحلقة التكرارية Do Loop تعمل هذه الحلقة على تكرار العمليات في الشيفرة اعتمادًا على شرط نضعه في صيغة الحلقة. الصيغة العامة للحلقة Do until Condition Code Loop حيث أن: +Condition: تمثِّل شرط تكرار التعليمات في الحلقة. Code: مجموعة التعليمات التي سيكررها الإجراء. Loop: تُعيد هذه التعليمة الحلقة للبداية لتطبيقها على العنصر التالي. مثال لتكن لدينا البيانات السابقة ونريد إعطاء خلفية بلون أحمر للخلايا غير الفارغة، ولإنجاز ذلك نكتب الحلقة التكرارية التالية: Sub test3() Do Until ActiveCell.Value = "" ActiveCell.Interior.Color = vbRed ActiveCell.Offset(0,1).Select Loop End Sub آلية عمل الحلقة تفحص الحلقة الشرط أولًا، وفي حال تحقُّقه تُنفّذ التعليمة على الخلية المُفعّلة عن طريق العنصر Interior للتحكم بخلفية الخلية عن طريق الخاصية color، وإعطاءه القيمة vbRed التي تُمثِّل اللون الأحمر، ثم التعليمة ActiveCell.Offset(0,1) Select التي تعمل على الانتقال إلى الخلية التالية وتنشيطها، بعدها التعليمة Loop التي تُعيد الحلقة للبداية لتكرار العمليات على الخلية التي أصبحت نشطةً، وهكذا إلى أن يصل الشرط إلى خلية فارغة، عندها تتوقف الحلقة. أشكال أخرى لكتابة الحلقة السابقة يمكن كتابة الحلقة بالصيغة التالية: Do while Condition Code Loop تعمل هذه الصيغة بنفس آلية الصيغة السابقة، ولكن في السابقة كان الأمر هو تنفيذ التكرار حتى يتحقّق الشرط، بينما هنا تعمل على تنفيذ التكرار طالما الشرط محقّق. ولدينا صيغة أُخرى تعمل بنفس الآلية وهي: Do Code Loop while Condition تختلف هذه الصيغة عن سابقاتها بأنها ستُنفّذ العمليات داخل الحلقة ثم تتحقّق من الشرط، أي أنّ العمليات هنا ستُنفذ لمرّة واحدة على الأقل، بينما في السابقات يمكن ألّا تُنفّذ العمليات ضمن الحلقة ولا مرّة. خاتمة نلاحظ أن العمليات الروتينية التي نُجريها على إكسل لا تُعَد ولا تُحصى، وأنّه بالتطبيق السليم لأفكار الحلقات التكرارية سنتخلص من الروتين الممل، ونوفر الوقت، ونضبط عملياتنا أكثر من الطريقة اليدوية، وكل ما علينا هو دراسة المهمة التي نكرّرها دائمًا ومعرفة عناصرها وخصائصها، وتصميم إجراء يحتوي على إحدى صيغ الحلقات التكرارية بما يتناسب مع تلك العملية، ووضع التعليمات المناسبة لتنفيذ تلك العملية داخل الحلقة التكرارية لِتُنفذها عوضًا عنّا وذلك خلال وقت قياسي. اقرأ أيضًا التعامل مع الأخطاء في VBA ضمن مايكروسوفت إكسل التفاعل مع المستخدم في مايكروسوفت إكسل باستخدام VBA العمليات الشرطية في مايكروسوفت إكسل باستخدام VBA
  9. عند كتابة الشيفرات البرمجية، تُصادِفنا العديد من التعليمات التي نحتاج تنفيذها فقط عند تحقّق أمر ما، مثل: تنفيذ شيفرة عند إدخال المستخدم قيمة معينة لإحدى الخلايا، أو عند إجراء تغييرٍ ما عليها، أو عند إدخال قيمة لا توافق الشروط التي وضعناها. بحيث تُنفَّذ الشيفرة بإظهار رسالة معّينة أو بتنفيذ أمر معين في حال تحقّق الشرط، وتنفيذ أوامر أخرى في حال عدم تحقّقه، وتُسمى هذه العملية بالعملية الشرطيّة. تعليمة IF الشرطية هي أشهر التعليمات الشرطيّة وتكتب بالصيغة التالية: IF condition Then code (if the condition is true) وهي الصيغة الأساسية لكتابة هذه التعليمة، ولكن يمكن كتابتها بشكل أوسع على الصيغة التالية: IF condition Then codes (if the condition is true) End If حيث أن: condition: الشرط الذي نريد تنفيذ التعليمات عند تحقّقه. codes: مجموعة التعليمات التي ستُنفذ عند تحقّق الشرط السابق. End IF: علامة نهاية العملية الشرطيّة. مثال لتكن لدينا البيانات التالية، حيث نريد فحص الخلايا وإعطائها رموز ترتيب في العمود D حسب نوع القسم. نطبق الشرط على الخلية A2 لفهم عمل الشرط، بحيث تعمل الشيفرة على إدخال القيمة A في الخلية D2 عند تحقّقه، ونكتب الشرط بالصيغة التالية: Sub test_if() IF Range("A2").Value = "الصحي" Then Range("D2").Value = "A" End IF End Sub الشرط هنا هو أن تكون قيمة الخلية A2 تساوي القيمة "الصحي"، وبتنفيذ الإجراء من المحرّر نجد أنّ الشيفرة تعمل بطريقة صحيحة، وتُمثّل هذه الصيغة الشروط البسيطة. تعليمة IF/Else الشرطية تعمل بنفس مبدأ التعليمة السابقة ولكن في حال لم يتحقّق الشرط نضيف للشيفرة عمليات أُخرى ليُنفّذها، وتكون التعليمة بالصيغة التالية: IF Condition Then codes (if the condition is true) Else codes (if the condition is false) End If حيث أن Else هنا تُنفّذ الأوامر التابعة لها في حال لم يتحقّق الشرط. مثال لنطبّق التعليمة الجديدة على الخلية A3 ونضع القيمة السابقة في حال تحقّق الشرط، والقيمة B في حال عدم تحقّقه، ونكتب الشرط بالصيغة التالية: Sub test_if() IF Range("A3").Value = "الصحي" Then Range("D3").Value = "A" Else Range("D3").Value = "B" End IF End Sub تعليمة الشروط المتداخلة IF/Elseif/Else تعمل هذه التعلمية على تطبيق شروط متعددة على الخلية، بحيث إذا لم يتحقّق الشرط الأول، ننتقل للشرط الثاني، ثم للثالث وهكذا. وتكون التعليمة بالصيغة التالية: IF condition Then codes (if the first condition is true) Else IF condition Then codes (if the second condition is true) Else codes (if all conditions are false) End If مثال لنطبق التعليمة الجديدة على الخلية A4 ونضع القيمة السابقة في حال تحقّق الشرط الأول، والقيمة C في حال كانت قيمتها هي "الزراعي"؛ أو القيمة D عند عدم تحقّق أي شرط سابق. ونكتب الشرط بالصيغة التالية: Sub test_if() IF Range("A4").Value = "الصحي" Then Range("D4").Value = "A" ElseIF Range("A4").Value = "الزراعي" Then Range("D4").Value = "C" Else Range("D4").Value = "D" End IF End Sub تعليمة IF الشرطية مع التعليمات AND/OR إذا أردنا أن ننفذ عمليات على الخلايا في حال تحقّق عدة شروط مع بعضها، نستخدم التعليمة AND مع تعليمة IF الشرطيّة؛ أما في حال أردنا أن ننفذ عمليات على الخلايا في حال تحقّق أحد الشروط، فسنستخدم التعليمة OR معها، لتصبح الصيغة: IF condition1 AND/OR condition2 AND/OR condition3 Then codes (if all conditions are true with AND) codes (if one of conditions are true with OR) Else codes (if all conditions are false) End If مثال لنطبّق أكثر من شرط على الخلية A5، ونضع القيمة E في حال تحقّق الشروط، أو القيمة F في حال عدم تحقّقها، ونكتب الشرط بالصيغة التالية: Sub test_if() IF Range("A5").Value = "الصحي" And Range("C5").Value=11 Then Range("D5").Value = "E" Else Range("D5").Value = "F" End IF End Sub التعليمة الشرطية Select Case تُستعمل هذه التعليمة إذا أردنا فحص عدة شروط على خلية واحدة، وتنفيذ التعليمة المقابلة للشرط في حال تحقّقه. حيث نلاحظ أنّه يمكن تنفيذ هذه العملية عن طريق التعليمة IF/Elseif/Else، ولكن التكرار الكثير للتعليمة IF في الشيفرة البرمجية سيزيد من حجم العمليات في الإجراء، كما سيؤدي إلى بطء تنفيذه، لكن باستخدام التعليمة Select Case، فسنقلل من حجم الشيفرة البرمجية وبالتالي تصبح عمليةً أكثر من التعليمة السابقة. الصيغة العامة للتعليمة Select case Element(object) Case The first case codes (if the case is true) Case The second case codes (if the case is true) Case Else codes (If all cases are false) End Select Element: العنصر الذي نُطبّق الاستعلام عليه للتحقّق. The first case: تمثل شرط التحقّق من القيمة الأولى أو قيمة الفحص الأولى. The second case: تمثل شرط التحقّق من القيمة الثانية أو قيمة الفحص الثانية. Code: التعليمات التي ستُنفَّذ عند تحقّق الحالة السابقة له. مثال لدينا الجدول التالي الذي يحتوي على الترتيب التالي، والذي يمثّل أيام الأسبوع. على فرض أنّ السبت هو اليوم الأول، نريد فحص القيمة في الخلية وإعادة ما يقابلها من أيام الأسبوع، ونطبق الصيغة التالية على الخلية A8: Sub day_name() Select Case Range("A8").value Case 1 Range("B8").value="السبت" Case 2 Range("B8").value="الأحد" Case 3 Range("B8").value="الإثنين" Case 4 Range("B8").value="الثلاثاء" Case 5 Range("B8").value="الأربعاء" Case 6 Range("B8").value="الخميس" Case 7 Range("B8").value="الجمعة" End Select End Sub عندما تكون الأوامر التي ستُنفّذها الحالة Case متشابهةً في أكثر من حالة، فسيمكننا اختصار الإجراء وتجميع الحالات ذات الأوامر المتشابهة في حالة واحدة، وذلك أيضًا يقلل من حجم الشيفرة، بحيث يصبح شكل العملية بالصيغة التالية: Select case Element(object) Case The first case, The second case, The third case Code Case The fourth case, The fifth case Code Case Else Code End Select بالعودة إلى مثالنا السابق وبفرض أن يومي الجمعة والسبت هما أيام عطلة وباقي الأيام أيام عمل، وأردنا تطبيق العملية السابقة على البيانات لمعرفة إذا كان ترتيب اليوم يقابل يوم عمل أو يوم عطلة نُطبّق التعليمة السابقة على الخلايا C2 وC5، لتصبح لدينا التعليمة كالتالي: Select Case Range("A8").Value Case 1, 2 Range("C5").Value = "يوم عطلة" Case 3, 4, 5, 6, 7 Range("C5").Value = "يوم عمل" End Select بتكرار العمليات السابقة في الخلية C2، نجد أن الشيفرة تعمل بطريقة صحيحة، ولكن بما أن شرط تحقُّق الحالة هو عبارة عن أرقام تراتبية، يمكننا الاختصار أكثر وكتابة التعليمات بالشكل التالي: Case 3 To 7 Range("C5").Value = "يوم عمل" كما يمكن كتابتها بالشكل التالي في حال كانت قيم المطابقة عددية، أي قابلة للقياس: Case IS<2 Range("C5").Value = "يوم عمل" كل الصيغ السابقة تؤدي نفس العمل ولكن تختلف السرعة في التنفيذ. مثال تطبيقي لكل ما سبق لدينا الملف التالي ونريد كتابة إجراء يعمل على فحص البيانات المُدخلة في الخلايا وإعطاء رسالة في حال كانت إحدى البيانات فارغة أو ترحيل البيانات إلى صفحة ثانية في حال كانت البيانات كاملةً عن طريق زر إدخال. في البداية نضع اسمًا للإجراء الذي سنعمل عليه وليكن DataEntry، ثم نُعرّف المتغيرات التي ستحفظ نتيجة الاستعلامات عن قيم إدخال الخلايا التي نعمل عليها. حيث لدينا ثلاثة أنواع من المتغيرات، وهي: رقمي طويلLong، ونصّي String، وتاريخ Date. بحيث ستتكون لدينا الصيغ التالية: Sub DataEntry() Dim name As String Dim nationalID As Long Dim bearthday As Date Dim place_of_birth As String name = Worksheets("صفحة الإدخال").Range("A1").Value nationalID = Worksheets("صفحة الإدخال").Range("A2").Value bearthday = Worksheets("صفحة الإدخال").Range("A3").Value place_of_birth = Worksheets("صفحة الإدخال").Range("A4").Value End Sub نضيف الآن عمليات ترحيل البيانات إلى صفحة البيانات عند الضغط على الزر إدخال، ونضيف إلى الشيفرة التعليمات التالية: Worksheets("البيانات").Range("A2").Value = name Worksheets("البيانات ").Range("B2").Value = nationalID Worksheets("البيانات ").Range("C2").Value = bearthday Worksheets("البيانات ").Range("D2").Value = place_of_birth إلى هنا نكون قد أنجزنا الجزء الأول من المطلوب ولكن ينقصه أمر أساسي، وهو أنه عند إضافة بيانات جديدة يجب أن تعمل الشيفرة أولًا على إضافة صف جديد، ثم تُرحّل البيانات إلى صفحة البيانات كي لا تُستبدل البيانات القديمة بالبيانات الجديدة، ولهذا سنحتاج إلى التعليمة التالية: Worksheets("البيانات").Range("2:2").Insert يعمل الأمر insert على إضافة خلايا ضمن النطاق المحدد في العنصر Range، وقد وضعنا المجال 2:2 لأننا نريد إضافة صف كامل. بعد إضافة الصف وترحيل البيانات إليه، فلابد من تفريغ خلايا الإدخال عن طريق الإجراء وذلك عن طريق التعليمات التالية: Worksheets("صفحة الإدخال ").Range("A1").ClearContents Worksheets("صفحة الإدخال ").Range("A2").ClearContents Worksheets("صفحة الإدخال ").Range("A3").ClearContents Worksheets("صفحة الإدخال ").Range("A4").ClearContents حيث يعمل الأمر ClearContents على تفريغ محتوى الخلية. بقي لدينا إضافة شرط فحص قيم الخلايا قبل ترحيل البيانات، ويجب ألّا تكون أي خلية من خلايا الإدخال فارغة، لذا نستعمل التعليمة OR مع التعليمة IF لفحص جميع الخلايا بشرط واحد، إذ يجب الانتباه إلى أن الخلايا النصية تُوازَن بالفراغ، أما الخلايا الرقمية فنوازنها بالقيمة 0 للتأكد أنها ليست فارغة، بحيث تكون الصيغة كالتالي: If name = "" Or nationalID = 0 Or bearthday = 0 Or place_of_birth = "" Then MsgBox "البيانات غير كاملة" بهذا تكون الشيفرة قد أصبحت جاهزةً لإجراء عملية الإدخال كما هو مطلوب والإجراء كاملًا هو التالي: Sub DataEntry() Dim name As String Dim nationalID As Long Dim bearthday As Date Dim place_of_birth As String name = Worksheets("صفحة الإدخال").Range("B1").Value nationalID = Worksheets("صفحة الإدخال").Range("B2").Value bearthday = Worksheets("صفحة الإدخال").Range("B3").Value place_of_birth = Worksheets("صفحة الإدخال").Range("B4").Value If name = "" Or nationalID = 0 Or bearthday = 0 Or place_of_birth = "" Then MsgBox "البيانات غير كاملة" Else Worksheets("البيانات").Range("2:2").Insert Worksheets("البيانات").Range("A2").Value = name Worksheets("البيانات").Range("B2").Value = nationalID Worksheets("البيانات").Range("C2").Value = bearthday Worksheets("البيانات").Range("D2").Value = place_of_birth Worksheets("صفحة الإدخال").Range("B1").ClearContents Worksheets("صفحة الإدخال").Range("B2").ClearContents Worksheets("صفحة الإدخال").Range("B3").ClearContents Worksheets("صفحة الإدخال").Range("B4").ClearContents End If End Sub خاتمة توفر لنا الشروط ضبطًا كبيرًا للعمليات بجميع أنواعها فهي تُجبر الشيفرة على تنفيذ العمليات وفق مسار معين كما أنها توفر الوقت اللازم لمعالجة العمليات التي لا تحقّق الشرط ضمن الشيفرة، لذلك يصبح تنفيذ الشيفرة أسرع، وتصبح العمليات أكثر دقة، مما يضمن لنا الحصول على بيانات تخدم هدفنا والتخلّص من أخطاء الإدخال. اقرأ أيضًا مدخل إلى البرمجة باستخدام VBA في مايكروسوفت إكسل. المتغيرات وأهم العناصر في برمجة VBA في مايكروسوفت إكسل. التفاعل مع المستخدم في مايكروسوفت إكسل باستخدام VBA الحلقات التكرارية في مايكروسوفت إكسل باستخدام VBA.
  10. تحدثنا سابقًا عن منهجية كتابة الشيفرات وتعلمنا أن كل شيء في إكسل هو كائن Object، فالملف كائن والصفحة كائن والخلية كائن، قد يكون الكائن مفردًا أو مجموعةً من الكائنات، بحيث يُحدَّد الكائن فيها بذكر اسمه بين إشارتي تنصيص داخل أقواس كائن المجموعة. نستدعي الكائنات من أجل الحصول على خصائصها، إما للإرجاع معلومة أو لتغيير قيمتها، كما لدينا الأمر المباشر Method الذي يعمل على تنفيذ أمر على هذا الكائن بدون إرجاع قيمة. أسماء أهم الكائنات في إكسل لدينا العديد من الكائنات الأساسية التي سنتعامل معها دومًا في إكسل، وهذه الأسماء معرّفة في فيجوال بيسك Visual Basic، لذا يجب كتابتها بدون أخطاء حتى يتعرّف محرّر اللغة على الكائن بطريقة صحيحة. وتُعَد الكائنات التالية من أهم هذه الكائنات: Application: هو كائن البرنامج ويعمل مع كل تطبيقات مايكروسوفت أوفيس. ("workbooks("name: هو كائن ملف الإكسل وهو مجموعة نحدد فيها الملف الذي سنتعامل معه عن طريق الاسم. ("worksheets("name: هو كائن مجموعة يضم كل الصفحات الموجودة في ملف الإكسل نفسه، وسنتعامل معه عن طريق الاسم. ("Range("name: هو كائن مجموعة يضم كل الخلايا الموجودة في صفحة الإكسل، وسنتعامل معه عن طريق موقع الخلية. ThiseWorkbook: هو كائن الملف الحالي الذي نعمل عليه. Activesheet: هو كائن الصفحة الحالية ضمن الملف المفتوح. Activecell: هو كائن الخلية الحالية ضمن الصفحة المفتوحة. Selection: هو كائن الخلايا المحددة. مثال تطبيقي لدينا البيانات التالية ونريد ترجمة النصوص في عناوين الأعمدة من اللغة العربية إلى اللغة الإنكليزية وبالعكس: نفتح برنامج محرّر الشيفرات VBE ونُنشئ نموذج module من القائمة insert أو من شريط الأدوات، ثم نكتب الإجراء التالي لتحويل النصوص إلى اللغة الإنكليزية بالصيغة التالية: Sub Translate_EN() Range("A1").Value = "Section" Range("B1").Value = "Project code" Range("C1").Value = "Number of zones" End Sub نلاحظ من الاستعلامات أننا استعلمنا عن اسم الخلية من الكائن Range مباشرةً لأننا نُشغّل الشيفرة من نفس الصفحة التي نُنفّذ عليها الإجراء السابق، ونُجري الاستعلام عن قيمتها من الخاصية value ونُغيّر قيمتها إلى القيمة الجديدة. نكتب كل استعلام بسطرٍ منفصلٍ عن الآخر، وعند تشغيل الشيفرة من شريط الأدوات نلاحظ تغيير قيم الخلايا التي تحوي البيانات إلى القيم التي وضعناها في استعلامات الإجراء السابق. وعند تطبيق العكس، أي تحويل النصوص السابقة إلى اللغة العربية نكتب الصيغة السابقة ولكن مع تغيير القيم التي ستُعدل في الخلايا بالصيغة التالية: Sub translate_AR() Range("A1").Value = "القسم" Range("B1").Value = "كود المشروع" Range("C1").Value = "عدد المناطق" End Sub عند تشغيل الإجراء السابق من الممكن أن تواجهنا مشكلة عدم فهم المحرّر للغة العربية ويظهرها بشكل رموز غير مفهومة. وأسباب هذه المشكلة هي إمّا من نظام التشغيل ويندوز لدينا أو من محرّر الشيفرات نفسه ولحل هذه المشكلة من محرّر الشيفرات، نذهب للقائمة Tools ثم نختار الأمر Options، فتظهر لنا نافذة جديدة. نختار التبويب Editor Format ونتأكد أن نوع الخط المحدد هو أحد الخطوط العربية، مثلًا (Courier New (Arabic ثم نضغط موافق. إذا لم تُحل المشكلة سننتقل إلى لوحة التحكم من قائمة ابدأ، ونختار من القائمة اللغة والوقت، ثم نختار تبويب اللغة، بعدها إعدادات اللغة الإدارية، تظهر لنا نافذة جديدة نختار منها تبويب التنسيقات ونتأكد أن تنسيق اللغة من ضمن خيارات اللغة العربية. ثم من نفس النافذة ننتقل إلى التبويب إداري، نضغط على زر تغيير الإعدادات المحلية للنظام ونتأكد من أن اللغة المخصصة للإعدادات المحلية للنظام هي العربية أيضًا. سيطلب النظام إعادة التشغيل بعد هذا التغيير. بعد أن حللنا مشكلة اللغة نُعيد تشغيل الإجراء السابق لنجد أنه يعمل بطريقة صحيحة. لإضافة أزرار تُنفِّذ عملية الترجمة بدون تشغيل المحرّر نتبع الخطوات التالية: من قائمة المطور في برنامج إكسل، نضغط على الأداة إدراج ونختار منها إدراج زر فتظهر لنا نافذة جديدة نختار منها اسم الإجراء الذي نريد من الزر أن يعمل على تنفيذه، ثم نضغط موافق، بعدها ننقر نقرةً مزدوجةً على اسم الزر لنكتب له اسمًا مناسبًا يعبِّر عنه. نكرر العملية السابقة لإضافة زر خاص بالإجراء الثاني. الآن لنُجرب تطبيق استعلامًا يعمل على إخفاء الزر غير المُفعّل، أي عند الضغط على الزر عربي يختفي الزر الآخر وبالعكس. هنا يمكننا كتابة الاستدعاء أو الاستعلام بإحدى الصيغتين التاليتين ولنا حرية الاختيار: ActiveSheet.Buttons("Button1").Visible = False أو الصيغة التالية: Worksheets("VBA").Buttons("Button1").Visible = False وبتطبيق الصيغة السابقة على الإجراءين السابقين نحصل على الصيغ التالية: Sub Translate_EN() Range("A1").Value = "Section" Range("B1").Value = "Project code" Range("C1").Value = "Number of zones" ActiveSheet.Buttons("button1").Visible = True ActiveSheet.Buttons("button2").Visible = False End Sub Sub translate_AR() Range("A1").Value = "القسم" Range("B1").Value = "كود المشروع" Range("C1").Value = "عدد المناطق" ActiveSheet.Buttons("button1").Visible = False ActiveSheet.Buttons("button2").Visible = True End Sub الآن عند الضغط على أي زر ستُنفّذ عملية الترجمة ويختفي الزر الآخر تلقائيًا. المتغيرات يُعرِّف مفهوم الخوارزميات المتغيّر على أنه مخزن للبيانات تكون قيمته ثابتة أو متغيّرة، وذلك حسب الغرض من استعماله في الشيفرة. لدينا مثال من الحياة لتوضيح الفكرة أكثر: لدينا موظف توصيل طلبات طعام في أحد المطاعم، وإجمالي الدخل اليومي لهذا الموظف يعتمد على قيمتين، إحداهما ثابتة وهي الراتب، والثانية متغيّرة وهي الإكراميّة (البقشيش) التي يتقاضاها من الزبائن ولكن هذه القيمة غير محددة فمثلًا أحد الزبائن يدفع 20 وآخر يدفع 50 وآخر لا يدفع أبدًا لذا أصبح إجمالي الراتب اليومي هنا يعادل مرتبه اليومي مضافًا إليه مجموع الإكراميّات خلال اليوم، وهنا الإكراميّة تمثل المتغيّر أي أن المتغيّر قيمته ليست مشروطة برقم ثابت. استخدام المتغيرات تُستخدَم المتغيّرات في لغات البرمجة للأسباب التالية: سهولة كتابة الشيفرات وتعديلها: وفي مثال على ذلك عندما يكون لدينا شيفرة كبيرة ونريد الاستعلام عن قيمةٍ ما ضمنها في أكثر من موضع وليكن 50 موضعًا، وبعد عدة تطويرات للشيفرة أردنا تعديل هذا الاستعلام فيجب علينا أن نعدّله في جميع المواضع، أي لدينا 50 عملية تعديل؛ أمّا إذا كنّا قد عرّفنا متغيّرًا وأسندنا له قيمة تساوي هذا الاستعلام، فسنحتاج إلى تعديل الشيفرة في موضع واحد فقط وهو مكان إسناد القيمة للمتغيّر. تسريع عمل الشيفرة: إن استخدام المتغيّرات يخفف من حجم العمليات ضمن الشيفرة البرمجية وبالتالي تصبح الشيفرة أسرع في عملها. الاستخدام المتعدد للمتغيّر: حيث يمكننا استخدامه في أكثر من مكان ضمن الشيفرة. تعريف المتغيرات في VBA تُعّرف المتغيّرات بالصيغة التالية: Dim name As type Dim هي اختصار لكلمة Dimension والتي تعني حجز جزء من الذاكرة، ويقصد بها هنا أن الاسم التالي يُعبّر عن متغيّر. name: هو اسم اختياري ولكن له عدة شروط: يبدأ بحرف ولا يبدأ برقم أو رمز. لا يحتوي على الرموز التالية (#,$;%;&;!). لا يُسمى بأسماء معرفة في اللغة مثل (IF;SUM). لا يحتوي على فراغات أو نقط. type: يُعبر عن نوع البيانات التي سيكون عليها المتغيّر الذي نعرّفه، مثل: نصي، ورقمي، ومنطقي. فيما يلي جدول يضم جميع أنواع البيانات لدينا والقيم التي يمكن أن تأخذها: حالات تعريف المتغيّرات واستدعائها يُستدعى المتغيّر في الشيفرة عن طريق كتابة اسمه فقط ولكن هنا لدينا حالتان: تعريف متغيّر ضمن الإجراء: يمكننا هنا استدعاء المتغيّر داخل الإجراء فقط ولا يمكن التعرّف عليه ضمن إجراء آخر. Sub test() Dim x As Integer Code End Sub تعريف متغيّر ضمن الإجراء وجعله عامًا: أي جعل المتغيّر قابلًا للاستخدام في أكثر من إجراء وذلك عن طريق وضع الكلمة Public قبل صيغة التعريف الخاصة بالمتغيّر. Sub test() Public Dim x As Integer Code End Sub تعريف المتغيّر خارج الإجراءات: وذلك في بداية الشيفرات، عندها سيكون المتغيّر معرّفًا ضمن كل الإجراءات في نفس النموذج module. Dim x As Integer Sub test() Code End Sub حالات تعيين قيمة متغير إسناد قيمة ثابتة للمتغيّر، مثال: Dim x As Integer X=5 إسناد قيمة متغيّرة مثل خلية مرجعية، وفي مثال على ذلك ما يلي: Dim x As Integer X=Rang("name").value إسناد معادلات للمتغيّر، مثال: Dim x As Single X=15*260/42 خاتمة إن إتقاننا للتعليمات في لغات البرمجة يجعل منّا مبرمجين، ولكن إتقان التعامل مع المتغيّرات يجعلنا مبرمجين محترفين لما للمتغيّرات من أهمية كبيرة في صناعة الشيفرات البرمجية، ولأثرها الكبير على تحسين عمل الشيفرة وتسريعها وسهولة تعديلها، إضافةً إلى تخفيف كمية الاستعلامات في الشيفرة. اقرأ أيضًا مدخل إلى البرمجة باستخدام VBA في مايكروسوفت إكسل. العمليات الشرطية في مايكروسوفت إكسل باستخدام VBA. الحلقات التكرارية في مايكروسوفت إكسل باستخدام VBA. التفاعل مع المستخدم في مايكروسوفت إكسل باستخدام VBA.
  11. تستخدِم برامج مايكروسوفت أوفيس لغة البرمجة فيجوال بيسك Visual Basic لإجراء عمليات البرمجة وكتابة الشيفرات، حيث دمجت شركة مايكروسوفت هذه اللغة مع تطبيقات مايكروسوفت أوفيس عام 1994، وكان برنامج مايكروسوفت إكسل أول برنامج تُدمج اللغة معه، حيث دُمج إصدار اللغة الموجهة للتطبيقات فقط Visual Basic for Application ليلائم بيئة عمل تطبيقات الأوفيس ومن هنا جاءت التسمية VBA. يمكننا التعامل مع هذه اللغة والشيفرات البرمجية باستخدام المحرر Visual Basic Editor، وهو برنامج صغير مدمج مع مايكروسوفت أوفيس. حيث نستطيع من خلاله كتابة الشيفرات وتحريرها وتعديلها وتشغيلها، ونستطيع الدخول إليه من خلال قائمة المطوّر Developer إذ يوجد زر محرر الشيفرات، أو من خلال الضغط على الاختصار Ctrl+F11. عند فتح محرر الشيفرات VBE سنجد أنه يعمل من خلال نافذة مستقلة تمامًا عن صفحة الإكسل التي نعمل عليها، أي أننا نستطيع العمل على النافذتين وإجراء التعديلات عليهما في آنٍ واحد. التعرف على الواجهة الرئيسية لمحرر VBE يحتوي المحرر مثل أي تطبيق آخر على العديد من القوائم وأشرطة الأدوات: شريط القوائم الاعتيادي. شريط الأدوات الأساسي، الذي يحتوي على العديد من الأدوات، مثل: أوامر تشغيل وإيقاف الشيفرة، والحفظ، والانتقال إلى إكسل. القائمة project التي يٌعرض من خلالها جميع ملفات الإكسل قيد العمل (المفتوحة) وضمن كل ملف تُعرَض جميع الصفحات التي يحتويها الملف. كما يمكن أن يحتوي على ملف اسمه PERSONAL.XLSB وهو ملف يحتوي على تسجيلات الماكرو التي أضفناها إلى برنامج الإكسل، فإذا أردنا إضافة شيفرات قابلة للتطبيق على كافة ملفات الإكسل على حاسوبنا، فعلينا أن إضافتها على المحرر مباشرةً. القائمة properties: تُظهر خصائص الصفحة المحددة في القائمة project، ويمكننا من خلالها تعديل خصائص الصفحة المحددة، مثل: إخفاء أو إظهار الصفحة من الخاصية visible في نهاية القائمة، وتغيير اسم الصفحة من الخاصية name. وتُعَد هاتان القائمتان من أهم القوائم في المحرر حيث سنتعامل معهما دائمًا. الشيفرة البرمجية وطرق كتابتها في VBA الشيفرة المصدرية Source Code هي قائمة من النصوص التي يمكن قراءتها من قِبل الإنسان، فهي مكتوبة بلغة معينة تُعبّر عن سلسلة من الأوامر بترتيب معين يَسهُل على الحاسوب فهمها وترجمتها، بحيث تؤدي هذه الأوامر إلى تنفيذ غرض محدد، مثل: إجراء عمليات على البيانات، أو إعادة قيم محددة. وتُكتَب الشيفرة البرمجية في إكسل بطريقتين: عن طريق تسجيل ماكرو وهو ما درسناه في الدرس كيفية استخدام الماكرو Macro لأتمتة المهام المتكررة في Microsoft Excel. عن طريق كتابة الشيفرة في المحرر، من خلال إنشاء شيفرة جديدة عن طريق الضغط على "إنشاء نموذج insert model" من شريط الأدوات، ليُفتَح نموذج جديد في القائمة project نكتب فيه الشيفرات، ثم نضغط على زر تشغيل من شريط الأدوات ليعمل المحرر على عرض الإجراءات المسجلة ضمن الشيفرة، ثم نختار الإجراء الذي نريد تشغيله ونضغط الأمر Run الذي يعمل على تشغيل الشيفرة وتنفيذ المهام المكتوبة فيها. كما يمكن تنفيذ الشيفرة السابقة من خلال الضغط على الزر F5 واختيار الإجراء الذي نريد تشغيله. لدينا المثال التالي الذي يوضح تشغيل الشيفرة البرمجية التي تُظهر لنا رسالة تحتوي على نصٍ معيّن: Sub test() Msgbox "hello world” End sub الإجراءات Procedures الإجراء هو مجموعة من الأوامر تهدف مجتمعةً إلى تنفيذ عملية أو مجموعة من العمليات على البيانات، ويقسم إلى نوعين: sub_routine: يقصد به الأعمال الاعتيادية أو الأوامر الاعتيادية، مثل: إضافة سطر، وتغيير قيمة خلية. Function: المعادلات التي نريد تطبيقها مثل معادلات ودوال الإكسل. الفرق الجوهري بين Function وsub_routine sub_routine يُنفذ مجموعة من المهام ولكن لا يعرض القيمة. يمكن استدعاءه من أي مكان داخل البرنامج بعد إنشائه. الصيغة العامة لبنائه: Sub Name() Our code End sub Function تعمل على إجراء المعادلات أو العمليات وتعيد لنا قيمة ضمن أي خلية نحتاج تطبيق الإجراء عليها. يمكن استخدام الشيفرة فيها مثل دالة متعارف عليها في برنامج إكسل ونستطيع تنفيذها ضمن الخلايا. الصيغة العامة لبنائه: Function Name() Our code End Function حيث أن: name: هو الاسم الذي اخترناه للإجراء ويفضل أن يكون الاسم معبرًا عن عمل الإجراء. our code: هي مجموعة الأوامر والتعليمات البرمجية التي تُشكل جسم الإجراء. End sub: دلالة على نهاية الإجراء. مثال ضمن النموذج model السابق نكتب الصيغة التالية: Function square(A as Integer) as Double Square=A*A End Function لسنا بحاجة إلى تشغيل الشيفرة هنا، لأن برنامج إكسل سيتعرف عليه تلقائيًا ويضيفه إلى مجموعة الأوامر لديه على شكل دالة معرفة ضمنه أساسًا، لتوضيح الفكرة لدينا البيانات التالية: لتنفيذ الدالة (الإجراء) السابقة في الخلية B2 نكتب الصيغة التالية: =square(A2) نلاحظ أننا حصلنا على دالة جديدة تعطينا مربع الرقم. منهجية كتابة الشيفرات تتشابه منهجية كتابة الشيفرات بشكل كبير في جميع لغات البرمجة، فالشيفرات تُكتب بنفس المبدأ وتختلف عن بعضها بالمسميات وبعض الأمور البسيطة. في البداية لدينا بعض المصطلحات التي علينا معرفتها: Object: يعبر عن الكائنات بمفهومها العام، مثل: سيارة، حاسوب، كتاب. حيث قد يكون كائنًا رئيسيًا وتتفرع منه كائنات فرعية. Property: مجموعة من الخصائص التي يملكها الكائن. Collection: مجموعة من الكائنات الفرعية تتشارك بمجموعة من الخصائص الرئيسية، وتختلف بخصائص بسيطة تميزها عن بعضها مثل (اسم الكائن). Method: تعبِّر عن عمل يُطبق على الكائن مباشرةً دون إرجاع القيمة. تعتمد منهجية كتابة الشيفرات على التسلسل الهرمي، ولفهم ذلك نأخذ سيارةً لتكون مثالًا كائن Object نريد تطبيق الشيفرة عليه: تمثل السيارة الكائن الرئيسي وله عدة خصائص Property، مثل: اللون، والوزن، والنوع، وتمثل الأبواب كائنًا فرعيًّا وتُشكِّل مع بعضها مجموعة Collection ولها عدة خصائص أيضًا. للاستعلام عن قيمة خاصية أو التعديل بأسلوب التسلسل الهرمي لدينا عدة طرق: استعلام عن خاصية في الكائن مباشرةً يكون بالصيغة التالية: Object.Property=value بالتطبيق على مثالنا: Car.color=red حيث تمثِّلcar الكائن الرئيسي، في حين النقطة تُعبر عن الاستعلام، وcolor تعبر عن الخاصية، أمّا red فتُعبِّر عن القيمة الناتجة من الاستعلام. استعلام عن خاصية كائن فرعي من الكائن الرئيسي يكون بالصيغة التالية: Object.Object.Property=value وبالتطبيق على مثالنا: Car.engine.power=400 تُمثل الاستعلام عن قوة المحرك ضمن السيارة، حيث السيارة كائن رئيسي، والمحرك كائن فرعي، وقوة المحرك خاصية للكائن الفرعي. استعلام عن خاصية كائن ضمن مجموعة ضمن الكائن الرئيسي يكون بالصيغة التالية: Object.Collection('تحديد الكائن عن طريق اسمه ').Property=value وبالتطبيق على مثالنا: Car.wheel("fr").color=black يُمثل الاستعلام عن لون العجلة الأمامية اليمنى ضمن السيارة، حيث السيارة كائن رئيسي والعجلات مجموعة تابعة للكائن الرئيسي واللون خاصية للمجموعة. الأمر المباشر، حيث تُنفَذ العملية أو الدالة مباشرةً على الكائن ولا يُرجع أي قيم كما سبق في الطرق السابقة، ويكون بالصيغة التالية: Object.Method وبالتطبيق على مثالنا: Car.stop حيث أن العملية stop تمثل أمرًا مباشرًا يعمل على إيقاف السيارة. لتوضيح ذلك لدينا ملف الإكسل التالي: يحتوي الملف على العديد من الصفحات، ونريد إدخال القيمة 45 ضمن الخلية C2 في الصفحة CODE. لدينا الاستعلام التالي لتنفيذ العملية وهو على الصيغة التالية: Application.workbook("test").worksheets("CODE").Range("C2").value=45 تفسير الكائنات في الصيغة: Application: تمثل الكائن الرئيسي وهو برنامج الإكسل. ("workbook("test: تمثل كائنًا فرعيًّا وهو ملف الإكسل واسم الملف test. ("worksheets("CODE: تمثل كائنًا فرعيًّا من الملف test وهو كائن الصفحة CODE. ("Range("C2: تمثل كائنًا فرعيًّا من الصفحة CODE وهو كائن الخلية C2. value: تمثل الخاصية التابعة للخلية والتي تمثل قيمة محتواها حيث سنعطيها القيمة 45. يُعَد الاستعلام السابق هو الطريقة الأشمل، ولكنّنا نستطيع أن نختار تسلسلًا آخر وذلك حسب موقعنا من الملف، أي إذا كنا نعمل على الملف السابق وكانت الصفحة الفعّالة لدينا هي الصفحة CODE فإننا نحتاج الجزء التالي من الهرمية السابقة وهو: Range("C2").value=45 أما إذا كانت الصفحة الفعّالة لدينا هي الصفحة CHAR ونفذّنا عليها الاستعلام السابق فإن النتيجة ستكون إسناد القيمة 45 في الخلية C2 في الصفحة CHAR، وللوصول إلى ناتج صحيح علينا العودة بالهرمية السابقة خطوةً إلى الوراء بحيث تصبح الصيغة كالآتي: worksheets("CODE").Range("C2").value=45 خاتمة قد يبدو الأمر معقدًا بعض الشيء في البداية لكن كل ما علينا فعله هو التركيز ومعرفة التسلسل الصحيح للاستعلامات، وهو ما سنتقنه من خلال التمارين لاحقًا. سنتعرّف في الدروس القادمة على المزيد من الأوامر والشيفرات البرمجية في VBA ضمن مايكروسوفت إكسل. اقرأ أيضًا المتغيرات وأهم العناصر في برمجة VBA في مايكروسوفت إكسل. العمليات الشرطية في مايكروسوفت إكسل باستخدام VBA. التعامل مع الأخطاء في VBA ضمن مايكروسوفت إكسل.
  12. يُعَد إجراء العمليات الحسابية البسيطة والمعقدة، وإعطاء النتائج بدقةٍ وسرعة؛ من أهم استخدامات برنامج الإكسل، ويوجد العديد من الدوال التي تقوم بهذه العمليات الحسابية، سنتعرف فيما يلي على أهمها وأكثرها استخدامًا، وهي: المجموعة المرتبطة بدالة العد COUNT، والتي تتألف من خمس دوالٍ أساسية: COUNT COUNTA COUNTBLANK COUNTIF COUNTIFS دالة جمع الجداء SUMPRODUCT دوال التقريب ROUND، وROUNDUP، وROUNDDOWN دوال القيم العشوائية RAND، وRANDBETWEEN دوال العد COUNT تعمل هذه الدوال على فحص الخلايا وإرجاع عددها بناءًا على الدالة المُستخدمة. الدالة COUNT تعمل هذه الدالة على حساب عدد الخلايا الرقمية فقط وذلك ضمن نطاقٍ محدد. البناء العام لصيغة الدالة COUNT(Value1, Value2, Value3, ...) تحتاج الدالة إلى المعطيات التالية: Value1: وهي العنصر أو مرجع الخلية، أو النطاق الأول الذي تريد حساب الأرقام الموجودة بداخله، وهذا المُعطى مطلوب. ….,Value2, Value3: وهي العناصر الإضافية أو مراجع الخلايا أو النطاقات التي تريد حساب الأرقام الموجودة بداخلها، ويصل عددها إلى 255، وهذا المُعطى اختياري. مثال يُوَضح الجدول التالي جزءًا من بيانات العملاء لدى أحد البنوك. نطبّق الدالة السابقة في إحدى الخلايا الفارغة، ولتكن الخلية C18، بعدها نختار الخلايا التي سنطبِّق الدالة عليها، مثل: C1، وC5، وD2، وE9، وF14. نكتب الصيغة التالية: =COUNT(C2,C5,D2,E9,F14) نرى أنّ الناتج لدينا هو 4 أي أنّ الدالة لم تعمل على حساب الخلية D2 لأن محتواها نص وليس رقم. يمكننا هنا استبدال المعطيات بنطاقٍ محددٍ حسب الحاجة، فإذا أردنا إحصاء عدد الخانات الرقمية في المجال من E2 إلى F16 مثلًا، فسنكتب الدالة بالصيغة التالية: =COUNT(E2:F16) ويكون الناتج هنا عدد جميع الخانات الرقمية ضمن هذا المجال وهو 30 خلية رقمية. الدالة COUNTA تعمل هذه الدالة على حساب عدد الخلايا غير الفارغة ضمن نطاقٍ محددٍ، بغضّ النظر عن نوعية البيانات فيها بما في ذلك الخلايا التي تحوي نصًا فارغًا " "، والخلايا التي تحوي القيم الخاطئة مثل #N/A. البناء العام لصيغة الدالة COUNTA(Value1, Value2, Value3…) نُطبق الدالة على المثال السابق لنحصل على الصيغة التالية: =COUNTA(C2,C5,D2,E9,F14) فيكون الناتج لدينا هو 5، أي أن الدالة عملت على حساب جميع الخلايا النصية والرقمية. نستبدل الآن المعطيات بنطاقٍ أوسع من النطاق المذكور في المثال السابق، وليكن النطاق B2:E16، نكتب الدالة بالصيغة التالية: =COUNT(E2:F15) فيكون الناتج هنا عدد جميع الخانات الرقميّة والنصيّة ضمن هذا المجال، وهو 56 خلية غير فارغة. الدالة COUNTBLANK تعمل هذه الدالة على حساب عدد الخلايا الفارغة فقط ضمن نطاقٍ محدد. البناء العام لصيغة الدالة COUNTBLANK(Value1, Value2, Value3,…) نُطبّق الدالة على المثال التالي ضمن المجال B2:B16. نكتب الصيغة التالية: =COUNTBLANK(B2:B16) فيكون الناتج لدينا هو 3، أي أن الدالة قد عملت على حساب جميع الخلايا الفارغة فقط. الدالة COUNTIF تعمل هذه الدالة على حساب عدد الخلايا التي تحقق شرطًا معينًا. البناء العام لصيغة الدالة COUNTIF(range,criteria) تحتاج الدالة إلى المعطيات التالية: النطاق range: وهو النطاق الذي نريد تطبيق الدالة على محتويات الخلايا فيه، والتأكد من مُطَابقتها للشرط أم لا، وهذا المُعطى مطلوب. المعيار criteria: وهو المعيار أو الشرط الذي يجب أن يتحقق في خلية من النطاق range لتُحتَسب، وهذا المُعطى مطلوب. مثال لِنُطبق الدالة على العمود D من جدول البيانات السابق، فيكون المجال لدينا هو D2:D16، والشرط هو أن يكون نوع التسديد (شهري)، فتكون صيغة الدالة كما يلي: =COUNTIF(D2:D16,"شهري") ويكون الناتج لدينا هو 4 خلايا، وهو ما يُحَقق الشرط السابق. الدالة COUNTIFS تعمل هذه الدالة على حساب عدد الخلايا التي تُحَقق شروطًا معينةً على أكثر من نطاق، وقد شرحنا كيفيّة عملها في الدرس كيفية استخدام دالة IF الشرطية في Microsoft Excel الدالة SUMPRODUCT تُستخدم هذه الدالة لحساب ناتج مجموع جداء عمودين أو أكثر. وتفيدنا هذه الدالة في حساب إجمالي مبيعات مجموعة من المنتجات على سبيل المثال. البناء العام لصيغة الدالة SUMPRODUCT(array1, [array2], [array3], ...) تحتاج الدالة إلى المعطيات التالية: array1: هو النطاق الذي يحتوي العمود المراد جدائه بعمود آخر، وهذا المُعطى مطلوب. …,[array2], [array3]: هي النطاقات التي ستُضرب محتوياتها بالعمود السابق، وهذا المُعطى اختياري. مثال لدينا جدول البيانات التالي، والذي يحوي بياناتٍ خاصة بمبيعات بعض المنتجات لدى إحدى شركات الهواتف. نريد إيجاد مبلغ إجمالي المبيعات لديها، ولهذا نطبق الدالة في الخلية D17 وتكون لدينا الصيغة التالية: =SUMPRODUCT(E2:E15,D2:D15) تفسير عمل الدالة: تعمل الدالة على ضرب الخلية E2 بالخلية D2، والخلية E3 بالخلية D3، وهكذا إلى نهاية النطاقين، ثم تجمع نواتج الضرب لِما سبق، فيكون الناتج هنا هو 167923، وهو نفس الناتج الذي سنحصل عليه لو أضفنا عمودًا يحوي عملية الجداء بالطريقة التقليدية أو عن طريق الدالة PRODUCT ثم طبّقنا الدالة SUM على النواتج الحاصلة فيه. ملاحظات هامة: يجب أن تكون نطاقات المعطيات ذات الأبعاد نفسها. فإذا كانت الأبعاد مختلفة، فسيكون الناتج هو الخطأ #VALUE!. على سبيل المثال لو أدخلنا النطاقين كالتالي (SUMPRODUCT(E2:E15,D2:D15، فسينتج لدينا الخطأ #VALUE! لأن النطاقين غير متساويين في الأبعاد. تتعامل SUMPRODUCT مع إدخالات النطاق غير الرقمي كما لو كانت أصفارًا. لنجرب تحديد النطاق في المُعطى الثاني C2:C15 بدلًا من D2:D15 سينتج لدينا هنا القيمة 0. دوال التقريب ROUND وROUNDUP وROUNDDOWN تعمل هذه الدوال على تقريب الأرقام العشرية بحسب المنزلة التي نختارها إما للأعلى أو للأسفل، وذلك وفقًا للدالة التي نستخدمها. الدالة ROUND تقرّب هذه الدالة الأرقام العشرية إلى المنزلة العشرية التي نختارها. البناء العام لصيغة الدالة ROUND(number, num_digits)‎ تحتاج الدالة إلى المعطيات التالية: number: وهو العدد العشري الذي نُريد تقريبه، وهذا المُعطى مطلوب. num_digits: وهي المنزلة التي نُريد تقريب العدد العشري إليها، وهذا المُعطى مطلوب. مثال لدينا بيانات التعديلات على رواتب موظفي إحدى المنظمات. نلاحظ أن الرواتب بعد الزيادة تحوي الكثير من الفواصل العشرية، ويَصعُب قراءتها بهذه الطريقة، ولتقريب الأرقام إلى منزلتين عشريتين فقط، نطّبق الدالة ROUND على الخلايا في عمود الراتب بعد الزيادة، ونكتب الصيغة التالية في الخلية G2: =ROUND(F2,2) فنحصل على مبلغ الراتب بمنزلتين عشريتين فقط. باستخدام مقبض التعبئة نسحب لأسفل العمود لتطبيق العملية على كامل عمود المرتبات الجديدة. تفسير عمل الدالة: تعمل الدالة على الوصول إلى المنزلة المذكورة في المُعطى الثاني وتفحص المنزلة التي تليها مباشرةً، فإذا كان الرقم أقل من 5، فستُهمِله بالكامل بعد المنزلة التي اخترناها؛ أما إذا كان أكبر من 5، فستعمل على إضافة 1 إلى قيمة المنزلة في المُعطى الثاني، أي إذا كان الرقم الذي نريد تقريبه هو 7.346 وأردنا تقريبه إلى منزلتين عشريتين فقط، فإن الرقم سيصبح 7.35، أما إذا كان 5.754 فسيصبح 5.75 فقط ويُهمَل الرقم 4. الدالتين ROUNDUP وROUNDDOWN تعمل هاتين الدالتين عكس بعضهما، حيث تعملان على التقريب إما للرقم الأعلى بحسب عدد المنازل التي نريد في الدالة ROUNDUP، أو للرقم نفسه وتُهمِل كل ما هو بعد المنزلة التي أدخلناها في الدالة ROUNDDOWN. سندرس البناء العام لإحداهما فهما تملكان نفس الصفات. البناء العام لصيغة الدالتين ROUNDUP(number, num_digits)‎ ROUNDDOWN (number, num_digits)‎ مثال عند تطبيق الدالة ROUNDUP، وROUNDDOWN على المثال السابق، فسنلاحظ أنّ الدالة ROUNDUP قد عملت على تقريب العدد في المنزلة الثانية إلى العدد الأعلى مباشرةً بغض النظر إن كان العدد في المنزلة الثالثة أكبر من 5 أو أصغر؛ أما الدالة ROUNDDOWN فقد أهملت كل ما هو موجود بعد المنزلة الثانية بغض النظر عمّا كان العدد أكبر من 5 أو أصغر. دوال القيم العشوائية RAND RANDBETWEEN تعطينا هذه الدوال قيمًا عشوائيةً (مثل الأرقام التي نحصل عليها عند شراء رقم هاتفٍ جديدٍ)، وتتميّز بأن نسبة تكرارها تكون شبه معدومة بالنسبة للأرقام العشرية أو للأرقام الصحيحة ذات المنزلة الكبيرة (ألفيّة، مليونيّة). الدالة RAND تُنتِج هذه الدالة قيمًا عشوائيةً بين 0 و1 وهي دالة لا تحوي أي معطيات. البناء العام لصيغة الدالة RAND()‎ عند تطبيق الدالة على مجموعةٍ من الخلايا سنحصل على أرقامٍ عشريةٍ أكبر من أو تساوي 0، وأصغر من 1. تفيد هذه الدالة العاملين في المجال الإحصائي خصوصًا من أجل الحصول على عينةٍ عشوائيةٍ لتحليلها من كتلة البيانات المرتبة ترتيبًا منتظمًا. مثال لدينا البيانات المنتظمة التالية (البيانات المذكورة لفهم الفكرة بحيث أن الدالة تطبّق بهذه الطريقة على البيانات الضخمة). لا نستطيع أن نحصل على عينةٍ عشوائيةٍ من البيانات المنتظمة إلا عند تَغيير ترتيب السجلات، أي عندما تصبح البيانات موزعةً توزيعًا عشوائيًا، ولنحصل على ذلك نُضيف عمودًا جديدًا يحوي القيم العشوائية الناتجة من الدالة RAND. ثم نرتّب البيانات في عمود القيم العشوائية تصاعديًا أو تنازليًا، وعندها سيتغير الترتيب لكافة سجلات الجدول (الصفوف)، وذلك بحسب ترتيب القيم العشوائية. عندها نستطيع الحصول على العينة التي نُريد لدراستها. الدالة RANDBETWEEN تعمل هذه الدالة بنفس الآلية للدالة RAND، ولكن بفرق أننا هنا نستطيع أن نحدد مجال القيم العشوائية التي نُريدها. البناء العام لصيغة الدالة RANDBETWEEN(bottom, top)‎ تحتاج الدالة إلى المعطيات التالية: bottom: وهو أصغر عددٍ صحيح تُرجعه الدالة، وهذا المُعطى مطلوب. top: وهو أكبر عددٍ صحيح تُرجعه الدالة، وهذا المُعطى مطلوب. مثال لِنَعُد إلى مثالنا السابق ونضع العدد الأكبر 10 والعدد الأصغر 1، سينتج لدينا أرقامًا عشوائيةً صحيحةً بين الرقم 1 والرقم 10. خاتمة تعرّفنا على مجموعةٍ من أكثر الدوال الرياضية شيوعًا والتي تفيدنا في إجراء الكثير من المهام، كما تختصر الكثير من الوقت والجهد. وما يَزال هناك العديد من الدوال الرياضية الأخرى والتي سنتعرّف عليها في دروسٍ لاحقةِ. اقرأ أيضًا دوال البحث المتقدم INDEX وMATCH وDGET في مايكروسوفت إكسل. دوال التاريخ الأساسية في اكسل. كيفية استخراج أجزاء من النصوص أو دمجها باستخدام الدوال النصيّة في اكسل. 7 دوال لتطبيق إجراءات مختلفة على النصوص في اكسل.
  13. يُعَد الهدف الأساسي من أَتَمتة الأنظمة هو الحصول على البيانات الصحيحة في الوقت المناسب دون تأخير، وذلك كي لا تَفقِد البيانات أهميتها عند اتخاذ قرار ما؛ لذلك لا بُدّ من طريقةٍ لتحقيق عمليات البحث ضمن البيانات بأساليب مُتقدمة. وسنتعرّف فيما يلي على بعض الدوال والأساليب المُختصة بذلك. والدوال التي سَنَتطرق إليها هي INDEX وMATCH، وهما دالتان تَتَميزان بالسرعة والقوة والإمكانيات العالية، وبالتالي يُمكن القول أنها تُغني عن دوال البحث الأخرى، وأيضًا سنتعرّف على الدالة DGET وهي إحدى دوال البحث المُتقدِّم. الدالة INDEX تُرجِع الدالة INDEX قيمةً ضمن جدول أو نطاق محدد بواسطة فهارس أرقام الصفوف والأعمدة، أي اعتمادًا على رقم الصف ورقم العمود تُرجِع قيمة التقاطع لهما. البناء العام لصيغة الدالة INDEX(array, row_num, [column_num])‎ تحتاج الدالة إلى ثلاث معطيات: المصفوفة Array: ويُمثّل نطاق الخلايا الذي يحتوي البيانات التي تَبحث فيها الدالة، وهذا المُعطى مطلوب في صيغة الدالة. رقم السطر row_num: ويُمثّل رقم السطر الذي ستبحث فيه الدالة عن التقاطع، وهذا المُعطى مطلوبٌ في صيغة الدالة أيضًا. رقم العمود column_num: ويُمثّل رقم العمود الذي ستبحث فيه الدالة عن التقاطع. مثال لدينا بيانات قروض العملاء الخاصة بإحدى المصارف ونحتاج إلى إيجاد المبلغ المسدد للعميل محمد قاسم. نضع المؤشر في الخلية التي نُريد إرجاع القيمة إليها، ونكتب الصيغة التالية في الخلية E16: =INDEX(B2:I14,10,8)‎ يُمثّل الرقم 10 رقم صف البيانات. حيث نبدأ العد من أول صف ضمن المجال B2:I14 وليس من بداية ورقة العمل، كذلك فيما يخض رقم العمود الذي يقابل الرقم 8 في مثالنا. تفسير عمل الدالة تبحث الدالة عن قيمة تقاطع الصف رقم 10 الذي يُمثّل العميل محمد قاسم، مع العمود رقم 8 الذي يُمثّل قيمة المبلغ الذي سدده وهي 122466. بالنظر إلى عمل الدالة نجدها عديمة النفع، حيث يمكنني الحصول على النتيجة مباشرةً بدون الحاجة للدالة كوني من أُحدد رقم الصف ورقم العمود يدويًا، ولكن سيكون الأمر صعبًا عندما يكون عدد سجلّات الجدول (يُقصد بالسجلات الصفوف في الجدول) 1000 سجلّ، وكلما زاد حجم البيانات زادت الصعوبة، وزادت معها أخطاء البحث اليدوي أيضًا، وهنا يأتي دور الدالة الثانية لتكمّل عمل هذه الدالة. الدالة MATCH تعمل هذه الدالة على البحث عن قيمةٍ ضمن صف أو عمود، وتُعطينا رقم هذا الصف أو رقم هذا العمود عند تطابق قيمة الخلية فيه مع قيمة البحث في الدالة. البناء العام لصيغة الدالة MATCH(lookup_value, lookup_array, [match_type]) تحتاج الدالة إلى ثلاث معطياتٍ argument: قيمة البحث lookup_value: وهي القيمة التي تُريد مُطابَقتها لإيجاد رقم صفها أو عمودها، وهذا المُعطى مطلوبٌ في صيغة الدالة. مصفوفة البحث lookup_array: وهو نطاق الخلايا الذي يحتوي البيانات التي تبحث فيها الدالة، وهذا المُعطى مطلوبٌ في صيغة الدالة أيضًا. نوع المطابقة match_type: وتحدد هذه الوسيطة أسلوب المطابقة الذي ستنفذه الدالة، حيث تأخذ القيم التالية: (القيمة 1) إذا أردنا الحصول على نتائج أكبر قِيمةً من قيمة lookup_value أو نتائج مساويةً لها. (القيمة 0) إذا أردنا الحصول على نتائج مساوية تمامًا لقيمة lookup_value. وغالبًا نستعمل هذه القيمة لأننا نُريد نتائج مطابقةً لما نبحث عنه. (القيمة 1-) إذا أردنا الحصول على نتائج أصغر قيمةً من قيمة lookup_value. نُطَبق الدالة على المثال السابق، حيث نُريد تطبيق الدالة على الصفوف لنعرف رقم الصف الخاص ببيانات العميل محمد القاسم، فنكتب الصيغة التالية في الخلية E16: =MATCH("محمد قاسم",B2:B14,0) ستبحث الدالة ضمن المجال، وتُعِيد لنا رقم الصف عند تطابق قيمة البحث مع القيمة الموجودة في أول خليةٍ مطابقةٍ لقيمة البحث وهو الصف رقم 10. والآن لنطبّق الدالة على الأعمدة لنعرف رقم العمود الذي يحتوي المبلغ المسدَّد، ونكتب الصيغة التالية في الخلية E16: =MATCH("المبلغ المسدد",B2:I2,0) ستبحث الدالة ضمن المجال، وتُعِيد لنا رقم العمود عند تطابق قيمة البحث مع القيمة الموجودة في أول خليةٍ مطابقةٍ لقيمة البحث وهو العمود رقم 8. كما نُلاحِظ أنه يمكننا إيجاد رقم السطر أو العمود الآن بأسلوبٍ سهل ودقيق، والآن لندمج الدالتين معًا: INDEX(array, MATCH(lookup_value, lookup_array, [match_type]), MATCH(lookup_value, lookup_array, [match_type]))‎ وبالعودة إلى المثال السابق يُصبِح شكل الدالة كالآتي: =INDEX(B2:I14,MATCH("محمد قاسم",B2:B14,0),MATCH("المبلغ المسدد",B2:I2,0))‎ وستكون نفس النتيجة التي حصلنا عليها في المثال الأول وهي 122466. ولزيادة قوة الدالة أكثر، نعتمد خليتين مرجعيتين لأخذ قيم البحث منهم، ونُعدّل صيغة الدالة، حيث نستبدل قيمة البحث "محمد قاسم" بالخلية C17، ونستبدل قيمة البحث "المبلغ المسدد" بالخلية C18، ونضع النصوص داخل هاتين الخليتين لنحصل على الصيغة التالية: =INDEX(B2:I14,MATCH(C17,B2:B14,0),MATCH(C18,B2:I2,0))‎ الآن عند تغيير قيمة البحث لدينا إلى عميلٍ آخر، أو للبحث عن عدد دفعات العميل مثلًا، نستطيع ذلك من خلال تبديل القيم في الخلايا C17 وC18. وبذلك تمكّنّا من البحث عن قيمةٍ ما ضمن البيانات بوجود شرطين مختلفين، أحدهما في الصفوف والآخر في الأعمدة. ويمكننا دمج هذه الدوال مع دوال بحثٍ أُخرى مثل دمج الدالة MATCH مع الدالة VLOOKUP، حيث ستُعيد لنا الدالة MATCH رقم العمود دون أن نعدّه يدويًا من خلال وضع اسم العمود في قيمة البحث لتعمل الدالة VLOOKUP بدقة وبطريقةٍ أكثر تقدمًا. الدالة DGET هي إحدى دوال البحث المتقدمة كونها تجاوزت الكثير من عيوب دوال البحث الأخرى مثل دالة VLOOKUP، فمن خلال هذه الدالة لن نكون مُلزَمين بأن يكون عمود البحث هو العمود الأول في نطاق البيانات، إذ يُمكن لهذه الدالة البحث على جانِبَي عمود البحث، وتُعَد من دوال قواعد البيانات database، ولهذا يجب أن تكون البيانات لدينا مجدولة، أي أن مصدر البيانات (الجدول الذي نريد إرجاع القيم منه) يجب أن يحتوي على الرؤوس (تسميات الأعمدة)، كما يجب تصميم جدول لتحديد قواعد البحث (خلايا مرجعية للبحث). سنوضِّح الفكرة أكثر من خلال المثال لاحقًا. البناء العام لصيغة الدالة DGET(database, field, criteria)‎ تحتاج الدالة إلى ثلاث معطياتٍ: قاعدة الببانات Database: وهو نطاق الخلايا الذي تَتَألف منه القائمة أو قاعدة البيانات، وهذا المُعطى مطلوبٌ في صيغة الدالة. الحقل Field: وتشير إلى العمود الذي تستخدمه الدالة، وهذا المُعطى مطلوبٌ في صيغة الدالة أيضًا. وتتعرف عليه الدالة بإدخال تسمية العمود مع تضمينها بين علامتَي اقتباس مُزدوجتيْن، مثل: "اسم العميل"، أو "رقم العقد"، أو رقم يُمثّل موضع العمود في القائمة (بدون علامات اقتباس) مثل 1 للعمود الأول، و2 للعمود الثاني، وهكذا، أو عن طريق خلية مرجعية. المعيار Criteria: وهو نطاق الخلايا التي تحتوي على الشروط المحددة من قِبَل المستخدم. يُمكن استخدام أي نطاقٍ لوسيطة المعايير، طالما أن الوسيطة تحتوي على تسمية عمود واحد على الأقل وخلية واحدة على الأقل أسفل تسمية العمود لتحديد شرط للعمود. وهذا المُعطى مطلوبٌ في صيغة الدالة. مثال نُريد البحث ضمن البيانات التالية عن نوع العقد والرقم الخاص بالموظف احمد احمد باستعمال الدالة DGET. نجد أن الشروط لدينا مُحَققة والأعمدة تَحوي على رؤوسٍ، لذا نُصمم الجدول الصغير التالي لإجراء العمليات. من خلال جدول البيانات السابق، نَجد أن اسم العمود الذي يحوي قيمة البحث (شرط البحث) هو عمود الاسم، وأنّ اسم العمود الذي نُريد إرجاع البيانات منه هو العمود نوع العقد والعمود الرقم، بحيث يكون شرط البحث هنا هو الموظف احمد احمد من العمود الاسم. نطبق الدالة في الخلية I4 ونكتب الصيغة التالية: =DGET(A1:F12,I3,H3:H4) سَيَتعرف البرنامج على الوسيطة الثالثة على أن اسم عمود البحث هو القيمة الموجودة في الخانة H3، وأن قيمة تحقيق الشرط هي القيمة الموجود في الخلية H4، ويكون الناتج هو نوع العقد الخاص بالموظف أحمد أحمد وهو نصف سنوي. لنغير الآن قيمة الوسيطة الثانية Field في الدالة، ونضع بدلًا من نوع العقد اسم العمود الأول الرقم، لنجد أن الدالة تعمل جيدًا بغضّ النظر عما إذا كانت البيانات التي نُريد البحث عنها قبل عمود الشرط (الاسم) أو بعده، وبتطبيق المعادلة لِتُرجَع القيمة 605865 التي تقابل رقم الموظف أحمد أحمد، والدالة عَمِلت جيدًا. يُمكننا التعامل مع المُعطى الثاني Field في هذه الدالة يدويًا إما عن طريق كتابة اسم العمود بين اشارتي تنصيص "اسم العمود"، كما يلي: =DGET(A1:F12,”نوع العقد”,H3:H4) =DGET(A1:F12,”الرقم”,H3:H4) أو يمكننا الاستعاضة عنها برقم العمود كما يلي: =DGET(A1:F12,5,H3:H4) =DGET(A1:F12,1,H3:H4) وكل هذه الصيغ صحيحةٌ وتُعطي نفس النتيجة. خاتمة مما سبق نجد أن دوال البحث عديدة وكل حالةٍ يمكن أن نستعمل لها دالة بحثٍ تُناسبها، وكما أن لكل دالةٍ خصائص تميزها عن الدالة الأخرى، إلا أن لكل دالةٍ عيوبها أيضًا، لذا يجب الانتباه إلى توظيف الأداة المناسبة بحسب الحالة التي نعمل عليها. اقرأ أيضًا أكثر الدوال الرياضية شيوعا في مايكروسوفت إكسل. مدخل إلى البرمجة باستخدام VBA في مايكروسوفت إكسل. كيفية استخراج أجزاء من النصوص أو دمجها باستخدام الدوال النصيّة في اكسل. دوال الوقت الأساسية في اكسل.
×
×
  • أضف...