عند كتابة الإجراءات نُجهّز كل شيء للتعامل مع أوامر المستخدم النهائي للتطبيق، ولكن بغض النظر عن مدى خبرتك في كتابة الشيفرات في 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 [Label
وحدوث خطأ آخر يليهK فإن المحرّر يعود للوضع الافتراضيon Error GoTo 0
تلقائيًا.
المعالجة باستخدام 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
خاتمة
إن للأخطاء أهمية كبيرة في عمليات البرمجة فهي تعمل على تصحيح عمل الشيفرة ولكن بطريقة غير مباشرة، حيث تكمن أهميتها في اكتشاف المشاكل والأجزاء المفقودة من التعليمات، كما أن التطبيقات موجّهة لمستخدمين ربّما لا يكون لديهم معرفة بتعديل الأخطاء، أو حتى فهمها لذا يجب علينا أن نُعالج كافة الأخطاء وتقدير احتمالات حدوثها، ووضع حلول مسبقة لها ولهذا تُعَد معالجة الأخطاء من المهام الأساسيّة في عمليّة صناعة البرمجيات، ويجب إتقانها جيدًا لصناعة تطبيقات خالية من العيوب.
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.