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

التعامل مع الأخطاء في VBA ضمن مايكروسوفت إكسل


محمد Albittar

عند كتابة الإجراءات نُجهّز كل شيء للتعامل مع أوامر المستخدم النهائي للتطبيق، ولكن بغض النظر عن مدى خبرتك في كتابة الشيفرات في VBA، فإنّ الأخطاء دائمًا ستكون جزءًا من الشيفرة سواءً كنت مبتدئًا أو خبيرًا، ولكن الفرق هنا بين المبتدئ والخبير هو معرفة كيفية التعامل مع الأخطاء واستخدامها فعّالية.

أنواع الأخطاء

في البداية لابد لنا من معرفة الأنواع المختلفة للأخطاء التي من المحتمل أن تواجهنا في عملية البرمجة، فهناك أربعة أنواع من الأخطاء في VBA وهي:

  • أخطاء في بنية التركيب البرمجي (الشيفرة البرمجية) Syntax errors.
  • أخطاء التجميع Compilation errors.
  • أخطاء التشغيل Runtime errors.
  • أخطاء منطقية Logical Errors.

أخطاء في بنية التركيب البرمجي Syntax errors

هي أخطاء تحدث في بناء الشيفرة، مثل: نسيان قوس مفتوح، أو نسيان كتابة جزء من تعليمة.

001Error.PNG

نجد في الإجراء الموضَّح بالصورة أن التركيب خاطئ، حيث أنّ الشرط يفتقد لكلمة Then، وعند كتابة التعليمات في VBA، فسيتحقق المحرّر من كل الجملة بمجرد الضغط على الزر Enter، فإذا وجد شيئًا مفقودًا في بناء التركيب، فسيعرض رسالةً على الفور تحتوي بعض النص الذي يمكن أن يساعدك في فهم الجزء المفقود.

للتأكد من رؤية المحرّر لأخطاء التركيب البرمجي كلما كان هناك شيء مفقود، فنحتاج إلى التأكد من تمكين التحقّق من بناء الجملة Auto syntax check، وذلك من قائمة Tools في واجهة المحرّر، حيث نضغط على الخيار options لتظهر لنا النافذة التالية:

002Error.PNG

نتأكد من تبويب Editor بأن الخيارAuto syntax check مُفعّل، فإذا كان غير مُفعّل فإن المحرّر سيُحدد لك السطر الذي يحوي الخطأ ويُلّونَه بلون أحمر ولكن بدون إعلامنا ما هو نوع الخطأ.

أخطاء التجميع Compilation errors

تحدث عندما يكون هناك جزء مفقود من النص ومطلوب في نفس الوقت، تتشابه هذه الأخطاء قليلًا مع المجموعة السابقة لكن الفرق بينهما بينهما يكمن في كون الأخطاء في بنية التركيب تُظهر الخطأ في حال كان السطر البرمجي فيه جزء مفقود، أمّا أخطاء التجميع فتظهر عند تشغيل الشيفرة ويكون سطر بالكامل مفقود، أي أن صيغة الشيفرة صحيحة في سطر ما ولكنها غير صحيحة عند معالجة جميع شيفرة الإجراء أو المشروع ككتلة واحدة، ومن الأمثلة على ذلك:

  • تعليمة IF الشرطيّة بدون عبارة End IF المقابلة لها.
  • حلقة For التكرارية بدون عبارة Next المقابلة لها.
  • استدعاء إجراء غير موجود، أو موجود ولكن فيه معلومات خاطئة.
  • عدم تعريف أحد المتغيّر ات.

003Error.PNG

أخطاء التشغيل Runtime errors

هي الأخطاء التي تحدث أثناء تشغيل الشيفرة، وذلك عندما نكون قد تجاوزنا النوعين السابقين من الأخطاء، أي في حال وجود خطأ من أحدهما فله أولوية الظهور بين الأخطاء ولا يظهر خطأ التشغيل قبل معالجته، ومن الأمثلة على الأخطاء وقت التشغيل:

  • إدخال بعض البيانات في صفحة ما ضمن الملف الذي نعمل عليه ولكن هذه الصفحة غير موجودة (سواءً حُذفت أو تغيّر اسمها).
  • تصميم إجراء يحتوي عمليات على ملف ما وعند التشغيل لم يَجِد المحرّر هذا الملف، عندها نحصل على خطأ التشغيل.

004Error.PNG

في هذا النوع من الأخطاء نجد أن المحرّر سيُظهر لنا نافذةً تحتوي على خطأ من النوع أخطاء التشغيل Runtime errors، ولكنها مفيدة أكثر من النوعين السابقين، حيث نجد أن محتوى الرسالة هو تفصيل شبه كامل عن الخطأ وسببه، وعند الضغط على الزر Debug، فسيعمل المحرّر على تمييز جزء الشيفرة الذي يؤدي إلى الخطأ.

005Error.PNG

أخطاء منطقية 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.

006Error.gif

يفيدنا هذا النوع من المعالجات في تحديد موقع الخطأ ولكن له عدة مساوئ، حيث لا يمكن للمستخدِم الاستمرار بالعمل على التطبيق دون إصلاح هذا الخطأ، ويُعَد التطبيق غير مناسب للمستخدِم النهائي، وهو يُعَد من الأخطاء غير المهنية وتجعل التطبيق غير مستقر.

المعالجة باستخدام on Error Resume Next

يؤدي استخدام هذا النوع إلى تجاهل السطر الذي يحتوي على الخطأ والمتابعة بدون تنفيذه. هناك مواضع محددة قد يكون هذا النوع من الحلول مفيدًا، ولكن في الغالب يُفضّل عدم استخدامه إلا للضرورة، لأنه من الممكن أن يؤثِّر الخطأ على كتلة التطبيق وينتهي بنا المطاف بالحصول على بيانات خاطئة أو غير صالحة، حيث أن المستخدِم لن يعلم بحدوث الخطأ أثناء التشغيل.

مثال

لنأخذ نفس المثال السابق، حيث عند استعمال هذه الصيغة يصبح شكل الإجراء كالتالي:

Sub UsingDefault()

On Error Resume Next 
   Dim x As Long, y As Long    
    x = 6
    y = 6 / 0
End Sub

007Error.gif

نلاحظ أنه عند تشغيل الشيفرة بدون التعليمة، فسيُظهر لنا المحرّر رسالة الخطأ، أي أنه يعمل على النوع 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

008Error.gif

عند حدوث خطأ ما هنا فستُنفذ الأسطر قبل سطر الخطأ، حيث أنه يُسند القيمة 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

009Error.gif

عند معالجة الخطأ الأول تستمر الشيفرة بتنفيذ ما تحتوي الأسطر التي بعد قسم معالجة الخطأ، ولكن عند الوصول لخطأ ثانٍ فسنحصل على خطأ من أخطاء التشغيل 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

010Error.gif

خاتمة

إن للأخطاء أهمية كبيرة في عمليات البرمجة فهي تعمل على تصحيح عمل الشيفرة ولكن بطريقة غير مباشرة، حيث تكمن أهميتها في اكتشاف المشاكل والأجزاء المفقودة من التعليمات، كما أن التطبيقات موجّهة لمستخدمين ربّما لا يكون لديهم معرفة بتعديل الأخطاء، أو حتى فهمها لذا يجب علينا أن نُعالج كافة الأخطاء وتقدير احتمالات حدوثها، ووضع حلول مسبقة لها ولهذا تُعَد معالجة الأخطاء من المهام الأساسيّة في عمليّة صناعة البرمجيات، ويجب إتقانها جيدًا لصناعة تطبيقات خالية من العيوب.

اقرأ أيضًا


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...