JWDStructure

دروس VBA AutoCAD 

تطبيقات برمجة أوتوكاد - التطبيق الثاني - حساب مجموع مساحات

تم نشر هذا التطبيق في موقع ملتقى المهندسين العرب بعنوان (تمرين 1: استخدام vba وأوتوكاد)، وللتفاعل معه يمكنكم المشاركة على الرابط التالي:

http://www.arab-eng.org/vb/t135680.html

المستوى

  • مبتدئ

مقدمة

سأقوم في هذا الموضوع بتقديم تمرين حول استخدام لغة Visual Basic for Application (اختصاراً VBA) المدمجة مع أوتوكاد عن طريق شرح برنامج بسيط يقوم بعملية حساب مجموع مساحات أشكال مختارة.

المهارات المطلوبة لفهم الموضوع

  • معرفة بسيطة باستخدام برنامج أوتوكاد.
  • معرفة بالأوامر الأساسية للغة البرمجة Visual Basic.
  • يفضل قراءة الدرس الثاني المشروح في هذا الموقع.

النقاط الرئيسية

سنتعلم في هذا التمرين ما يلي:

  • اختيار الكائنات.
  • التنقل بين الكائنات المختارة ومعرفة نوع كل منها.
  • قراءة خصائص كائن ما.

نص المسألة

المطلوب كتابة برنامج يقوم بحساب مجموع مساحات الأشكال المغلقة التي يقوم المستخدم باختيارها، هذه الأشكال من النوع Polyline مغلق أو Region.

خطوات الحل

يفضل قراءة البرنامج أولاً وهو في آخر الصفحة للاطلاع عليه فقط حتى لو لم يكن مفهوماً الآن.

1- افتح بيئة البرمجة بالضغط على Alt+F11 من ضمن أوتوكاد فتظهر بيئة البرمجة Microsoft Visual Basic.

2- أضف وحدة برمجية Module من قائمة Insert، يختلف Module عن User Form بأن الأخير هو عبارة عن نافذة يمكن أن تحوي عدة كائنات برمجية، أما ال Module فهو يحوي برامج جزئية فقط، وفي هذا المثال لا نحتاج أكثر من هذا.

3- تم الآن إضافة وحدة برمجية اسمها Module1 وتظهر لنا صفحة بيضاء فارغة.

4- ضمن الصفحة الفارغة اكتب العبارة التالية : Public Sub CalcTotalArea ثم اضغط Enter فيتم إضافة السطر End Sub تلقائياً، كما في الشكل (1).

الشكل (1)
الشكل (1): بداية ونهاية البرنامج الجزئي CalcTotalArea

حتى هذه المرحلة قمنا بإضافة برنامج جزئي Sub اسمه CalcTotalArea، أما كلمة Public فهي تشير إلى أن هذا البرنامج يمكن الوصول إليه من خارج هذه الوحدة البرمجية وبالتالي يمكن استدعاؤه من أوتوكاد على أنه ماكرو.

أما عبارة End Sub فهي تشير إلى انتهاء البرنامج، وسنقوم بكتابة برنامجنا بين السطرين السابقين.

5- قبل البدء بكتابة البرنامج اذهب إلى أوتوكاد ثم اختر الأمر Macros من قائمة Tools->Macro فتظهر نافذة Macros التي تحوي ضمنها اسم البرنامج السابق، لتشغيله اختر الاسم ثم انقر على زر Run، حتى هذه النقطة لم نقم بكتابة أي شيء ضمن البرنامج لذلك فإن تنفيذه لن يؤدي إلى شيء.

6- نقوم بتعريف متحول اسمه TotalArea ليحمل ضمنه مجموع المساحات (أسماء المتحولات اختيارية ويفضل أن تكون معبرة عن قيمة المتحول).

كما هو معروف في VB فإن هناك عدة عبارات لتعريف (حجز) المتحولات لا مجال لذكرها، منها عبارة Dim ثم نكتب اسم المتحول ثم As ثم نوع المتحول وهو في حالتنا رقم حقيقي من النوع Single أو Double، سنستخدم Double، فتصبح العبارة:

Dim TotalArea As Double

7- حتى يقوم البرنامج بسؤال المستخدم أن يقوم باختيار مجموعة كائنات سنستخدم كائن من النوع AcadSelectionSet، وسنسميه ss (اختصار SelectionSet، كما قلنا الاسم اختياري)

نحجز المتحول ss كما سبق:

Dim ss As AcadSelectionSet

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

Set ss = ThisDrawing.SelectionSets.Add("TEMP")

في السطر السابق قمنا بإضافة SelectionSet جديدة اسمها (Temp) إلى لوحة أوتوكاد الحالية ThisDrawing، ثم جعلنا المتحول ss يشير إليها عن طريق العبارة Set.

أي يمكننا الآن الوصول إلى ال SelectionSet الجديدة عن طريق التعامل مع المتحول ss.

أما الاسم Temp فهو يشير إلى الاسم الداخلي لل SelectionSet هذه في أوتوكاد، وقد اخترت لها الاسم Temp للإشارة إلى أنها مؤقتة Temporary لأننا سنقوم بحذفها لاحقاً.

8- نقوم بتنفيذ الأمر SelectOnScreen التابع لل SelectionSet السابقة عن طريق المتحول ss كما يلي:

ss.SelectOnScreen

عند وصول البرنامج إلى هذه النقطة سيقوم أوتوكاد بسؤال المستخدم أن يقوم باختيار الكائنات في لوحة الرسم الحالية، ويقوم بتخزين هذه الكائنات في ss.

9- للتنقل بين الكائنات المختارة والتي وضعها أوتوكاد في ss سنستخدم الأمر المعروف في Visual Basic وهو حلقة For Each...Next، ونحتاج لتعريف متحول لنستخدمه ضمن هذه الحلقة وسنسميه ent وهو من النوع AcadEntity على اعتبار أن ss تحوي فقط كائنات أوتوكاد وجميعها لها النوع AcadEntity.

نكتب السطرين التاليين:

For Each ent In ss
Next

يمكننا ترجمة الحلقة السابقة كما يلي: من أجل كل كائن موجود في ss إجعل المتحول ent يشير إليه ثم نفذ الأوامر الموجودة ضمن الحلقة ثم انتقل إلى الكائن التالي وهكذا حتى الانتهاء.

فإذا كنا قد اخترنا كائنين في الخطوة 8 سيقوم البرنامج عند الأمر For بإسناد الكائن المختار الأول إلى المتحول ent ثم ينفذ الأوامر بعد For وقبل Next وعند الوصول إلى Next يسند الكائن المختار الثاني إلى المتحول ent ويعيد تنفيذ الأوامر حتى يصل إلى Next، وبعد الانتهاء من جميع الكائنات في ss ينتقل إلى خارج الحلقة أي إلى بعد سطر Next.

مابين السطرين السابقين سنقوم بإضافة الأوامر التي تقوم بجمع المساحة كما يلي.

10- من نص المسألة نريد جمع مساحات الكائنات من النوع Polyline و Region، والتي أسماؤها في VBA هي AcadLWPolyline و AcadRegion على الترتيب، لذلك يجب أن نختبر نوع كل كائن عن طريق أمر Visual Basic وهو If مع TypeOf كما يلي:

If TypeOf ent Is AcadLWPolyline Then

ترجمتها: إذا كان نوع الكائن الذي يشير إليه المتحول ent هو AcadLWPolyline نفذ الأوامر التالية، حيث نضيف الأوامر في السطر الذي يليه، ويجب أن نتذكر أن نضيف عبارة End If التي تشير إلى انتهاء العبارات البرمجية التي سينفذها البرنامج في حال تحقق الشرط.

سنقوم بقراءة مساحة الكائن عن طريق الخاصية Area التابعة له، ولكن هذه الخاصية ليست من خصائص ent لأنه من النوع AcadEntity، وإنما هي من خصائص كائن من النوع AcadLWPolyline لذلك سنقوم بتعريف متحول آخر من النوع AcadLWPolyline اسمه pl سيشير إلى نفس الكائن الذي يشير إليه المتحول ent ولكنه يمكّننا من الوصول إلى خصائص أكثر خاصة بالكائن Polyline، لذلك سنقوم بإضافة العبارات التالية:

Dim pl As AcadLWPolyline
Set pl = ent

الآن يمكننا معرفة مساحة هذا الكائن عن طريق الخاصية Area للمتحول pl وسنقوم بجمع هذه المساحة إلى المتحول الذي قمنا بتعريفه في بداية البرنامج TotalArea كما يلي:

TotalArea = TotalArea + pl.Area

ولكننا نريد جمع المساحة فقط في حالة كان هذا ال Polyline مغلقاً لذلك نضع الشرط If pl.Closed قبل العبارة السابقة لتصبح:

If pl.Closed Then TotalArea = TotalArea + pl.Area

تصبح العبارات كما يلي:

If TypeOf ent Is AcadLWPolyline Then
    Dim pl As AcadLWPolyline
    Set pl = ent
    If pl.Closed Then TotalArea = TotalArea + pl.Area
End If

11- نكرر نفس الخطوات السابقة من أجل الكائن من النوع AcadRegion، كما يلي:

If TypeOf ent Is AcadRegion Then
    Dim rg As AcadRegion
    Set rg = ent
    TotalArea = TotalArea + rg.Area
End If

12- نلاحظ أننا وضعنا شرطين متتاليين لا يمكن تحققهما معاً لذلك يمكننا تقليص العبارات السابقة بأن نضع الشرط الأول بدون End If ثم العبارات التابعة لهذا الشرط ثم ElseIf بدلاً من If الثانية ثم العبارات البرمجية التابعة للشرط الثاني ثم End If، كما هو موضح في البرنامج النهائي المبين أدناه.

13- نضيف سطر ss.Delete لحذف ال SelectionSet التي قمنا بإنشائها لأننا لن نحتاجها.

14- نظهر قيمة المساحة عن طريق أمر VisualBasic وهو MsgBox والذي يظهر صندوق رسائل كما يلي:

MsgBox TotalArea

أو يمكننا جعله أكثر وضوحاً للمستخدم كما يلي:

MsgBox "Total Area is: " & TotalArea

15- لتجربة البرنامج أضف كائنات Polyline مغلقة وكائنات Region في لوحة الأوتوكاد ثم نفذ البرنامج كما في الخطوة 5، سيسألك البرنامج أن تختار كائنات، اختر الكائنات السابقة ثم اضغط Enter وسيعطيك البرنامج قيمة مجموع المساحات.

ملاحظة: لإضافة برنامج جزئي آخر (ماكرو) ليس من الضروري إضافة وحدة برمجية جديدة، إنما يمكن أن نكتب البرنامج الجديد تحت عبارة End Sub السابقة، أي أن الوحدة البرمجية يمكن أن تحوي أكثر من برنامج جزئي (ماكرو)

ملاحظة2: قمت في هذا المثال بإطالة الشرح أحياناً (كما في 4،6،7،9،10،12) وذلك من أجل المبتدئين جداً في لغة Visual Basic، وفي المرات القادمة -إن شاء الله- سأفترض أن هذا أصبح مفهوماً ولن أطيل فيه.

نص البرنامج النهائي

Public Sub CalcTotalArea()
    Dim TotalArea As Double

    Dim ss As AcadSelectionSet
    Set ss = ThisDrawing.SelectionSets.Add("TEMP")
    ss.SelectOnScreen

    Dim ent As AcadEntity
    For Each ent In ss
        If TypeOf ent Is AcadLWPolyline Then
            Dim pl As AcadLWPolyline
            Set pl = ent
            If pl.Closed Then TotalArea = TotalArea + pl.Area
        ElseIf TypeOf ent Is AcadRegion Then
            Dim rg As AcadRegion
            Set rg = ent
            TotalArea = TotalArea + rg.Area
        End If
    Next
    ss.Delete

    MsgBox "Total Area is: " & TotalArea
End Sub 

تحميل

ملحق

سأل أحد الإخوة: كلما أقوم بتشغيل البرنامج تظهر رسالة خطأ تقول بأن اسم ال SelectionSet موجود، هل هناك طريقة للتخلص من هذا الخطأ بدلاً من تغيير اسم المجموعة في كل مرة؟

الجواب: الخطأ هو بسبب وجود SelectionSet اسمها Temp في قاعدة بيانات ملف الأوتوكاد الحالي، وهذا لأن البرنامج قد توقف في إحدى مرات تشغيله قبل أن يصل إلى سطر حذف هذه ال SelectionSet والتي اسمها Temp.

وعند التشغيل التالي للبرنامج حاول إضافة واحدة جديدة بنفس الاسم وعندما وجدها لم يستطع إضافتها وحصل الخطأ.

حقيقة كنت متوقعاً حصول هذا الخطأ ولكن تركته حتى لا أعقد البرنامج، والآن يمكنني كتابة أسطر معالجة هذا الخطأ كما سيلي وأعتقد أن فهمها الآن سيكون أسهل من لو أنني عالجته في بداية التمرين.

سنقوم بإضافة السطر التالي قبل إنشاء ال SelectionSet

On Error Resume Next

هذا السطر يخبر Visual Basic أنه في حال حدوث خطأ بعد هذا السطر تجاهله وانتقل إلى السطر الذي يليه:

الآن سنضيف سطراً بعد إنشاء ال SelectionSet وهو:

If Err.Number <> 0 Then Set ss = ThisDrawing.SelectionSets("Temp")

عند حدوث خطأ يتم تخزين رقم الخطأ في الكائن Err، لذلك نختبر الرقم بعد السطر الذي نتوقع حصول خطأ فيه، فإن كان مساوياً للصفر فهذا يعني عدم وجود خطأ وإلا فالخطأ موجود.

في حالتنا فإن الخطأ هو وجود هذه ال SelectionSet والتي اسمها Temp لذلك سنسندها إلى المتحول ss بدلاً من إنشاء واحدة جديدة كما هو مبين أعلاه.

بعد السطر السابق نكتب On Error Goto 0 لإلغاء وضع تجاهل الأخطاء، فهو عادة غير محبذ.

تصبح بداية البرنامج كما يلي:

Dim ss As AcadSelectionSet
On Error Resume Next
Set ss = ThisDrawing.SelectionSets.Add("Temp")
If Err.Number <> 0 Then Set ss = ThisDrawing.SelectionSets("Temp")
On Error GoTo 0
ss.SelectOnScreen

يمكن معالجة الخطأ السابق بعدة طرق والطريقة التي شرحتها أعلاه هي إحداها.