TOP

VBA-Lesson 9. الإجراءات والوظائف

توجد في أي لغة برمجة مفاهيم مثل الإجراءات والوظائف. تم تضمينها أيضًا في لغة البرمجة المضمنة VBA لـ Excel.

  • الوظيفة هي روتين يقوم بإرجاع نتيجة. استدعاء الوظيفة هو تعبير ويمكن استخدامه في تعبيرات أخرى أو على الجانب الأيمن من عبارة الإسناد (يُشار إليه في VBA كـ "Function") ؛
  • الإجراء هو أي روتين ليس وظيفة. تم تعليمه في VBA كـ "Sub" (من كلمة "روتين فرعي").

  • الإجراءات (Public - Private)

    في هذه المرحلة ، تكون جميع الإجراءات التي أنشأناها من النوع Public ، مما يعني أنه يمكن الوصول إليها من أي وحدة نمطية.

     Sub example()
     
     'مطابقة ل:
     Public Sub example()
    

    لجعل الإجراء متاحًا فقط في وحدة نمطية معينة ، يتم استخدام الكلمة الأساسية Private:

    Private Sub example()
    

    تشغيل إجراء من منتصف إجراء آخر

    لتنفيذ إجراء من داخل إجراء آخر ، ما عليك سوى إدخال اسمه.

    فيما يلي مثال بسيط جدًا على هذا:

    Private Sub warning()
        MsgBox "Caution !!!" '"تحذير!"
    End Sub
    
    Sub macro_test()
        If Range("A1") = "" Then
            warning '=> تنفيذ الإجراء "warning"
        End If
        'إلخ...
    End Sub
    

    الحجج

    تجعل الوسيطات من الممكن استخدام قيم من إجراء في إجراء فرعي (تذكر أنه افتراضيًا ، لا تتوفر المتغيرات إلا من الإجراء الذي تم التصريح بها).

    Private Sub warning(var_text As String)
        MsgBox "Caution : " & var_text & " !"
    End Sub
    
    Sub macro_test()
        If Range("A1") = "" Then
            warning "empty cell"               '"خلية فارغة"
        ElseIf Not IsNumeric(Range("A1")) Then
            warning "non-numerical value"      '"قيمة غير رقمية"
        End If
    End Sub
    

    تمت إضافة وسيطة إلى الإجراء "warning" ، وهي في هذه الحالة متغير "var_text" من النوع "String" (الشريط):

    Private Sub warning(var_text As String)
    

    يأخذ هذا الروتين وسيطًا ، لذلك نحتاج إلى وضع قيمة بعد "warning" لتنفيذه:

    warning "empty cell"
    

    عندما نريد كتابة عدة وسيطات ، فيجب فصلها بفواصل.

    الحجج الاختيارية

    بشكل افتراضي ، إذا كان الإجراء يحتوي على وسيطات ، فيجب توفيرها ، وإذا لم يتم توفيرها ، فلن يتم تنفيذ الإجراء.

    يمكن إضافة وسيطة اختيارية بعد الوسيطة الإلزامية باستخدام الكلمة الأساسية الاختيارية. مثال:

    Private Sub dialog_boxes(last_name As String, Optional first_name, Optional age)
    

    يمكن الآن تنفيذ هذا الإجراء باستخدام وسيطة اختيارية أو بدونها ، كما هو الحال هنا:

     'مثال 1: اعرض الاسم الأخير:
     dialog_boxes last_name1
       
     'مثال 2: نعرض اللقب والاسم الأول:
     dialog_boxes last_name1, first_name1
       
     'مثال 3: اعرض الاسم الأخير والعمر:
     dialog_boxes last_name1, , age1
       
     'مثال 4: عرض الاسم الأخير والاسم الأول والعمر:
     dialog_boxes last_name1, first_name1, age1
    

    يجب إدخال الوسيطات بالترتيب الصحيح.

    لاختبار ما إذا كانت الوسيطة الاختيارية موجودة في إجراء ما ، نستخدم وظيفة IsMissing. هذه الوظيفة متوافقة فقط مع بعض أنواع الوظائف (من النوع Variant) وهذا أمر بالغ الأهمية لأنه لم يتم التصريح عن نوع الوسيطات الاختيارية (نوع غير معرّف = Variant).

    فيما يلي مثال يستخدم مقتطفات التعليمات البرمجية التي تمت مناقشتها أعلاه:

    Sub macro_test()
    
        Dim last_name1 As String, first_name1 As String, age1 As Integer
       
        last_name1 = Range("A1")
        first_name1 = Range("B1")
        age1 = Range("C1")
    
        'مثال 1: اعرض الاسم الأخير:
        dialog_boxes last_name1
       
        'مثال 2: نعرض اللقب والاسم الأول:
        dialog_boxes last_name1, first_name1
       
        'مثال 3: اعرض الاسم الأخير والعمر:
        dialog_boxes last_name1, , age1
       
        'مثال 4: عرض الاسم الأخير والاسم الأول والعمر:
        dialog_boxes last_name1, first_name1, age1
    
    End Sub
    
    Private Sub dialog_boxes(last_name As String, Optional first_name, Optional age)
       
        If IsMissing(age) Then 'إذا كان متغير العمر مفقودًا ...
           
            If IsMissing(first_name) Then 'إذا كان المتغير first_name مفقودًا ، فحينئذٍ
            							  'سيتم عرض الاسم الأخير فقط
               MsgBox last_name
            Else 'خلاف ذلك ، سيتم عرض الاسم الأخير والاسم الأول
               MsgBox last_name & " " & first_name
            End If
           
        Else 'إذا كان متغير العمر موجودًا ...
    
            If IsMissing(first_name) Then 'إذا كان المتغير first_name مفقودًا ، فحينئذٍ
                                          'سيتم عرض اسم العائلة والعمر
               MsgBox last_name & ", " & age & " years old"
            Else 'خلاف ذلك ، سيتم عرض الاسم الأخير والاسم الأول والعمر
               MsgBox last_name & " " & first_name & ", " & age & " years old"
            End If
       
        End If
           
    End Sub
    

    يرى الصورة أدناه (المثال 1):

    ByRef - ByVal

    بشكل افتراضي ، تكون الوسائط من النوع ByRef ، مما يعني أنه إذا تم تمرير متغير كوسيطة ، فسيتم أيضًا تمرير مرجع إليه. بمعنى آخر ، إذا تم تغيير متغير بواسطة إجراء فرعي آخر ، فسيتم تغييره أيضًا في الإجراء الخارجي الذي يستدعي هذا الإجراء الفرعي.

    مثال:

    Sub macro_test()
        Dim var_number As Integer
        
        var_number = 30
        calcul_square var_number
       
        MsgBox var_number
    End Sub
    
    Private Sub calcul_square(ByRef var_value As Integer) 'ByRef اختياري
                                                          '(هي القيمة الافتراضية)
        var_value = var_value * var_value
    End Sub
    

    لتوضيح ذلك ، يوجد أدناه مثال لما سيحدث إذا بدأ تنفيذ الماكرو:

     var_number = 30
     'القيمة الأولية للمتغير "var_number" هي 30
    
     calcul_square var_number
     'يتم تشغيل الإجراء الفرعي باستخدام "var_number" كوسيطة
    
     Private Sub calcul_square(ByRef var_value As Integer)
     'المتغير "var_value" يخدم إلى حد ما للوصول السريع إلى المتغير "var_number" ،
     'مما يعني أنه إذا تم تغيير المتغير "var_value" ، فسيتم أيضًا تغيير المتغير "var_number"
     '(وليس لديهم نفس الاسم)
     var_value = var_value * var_value
     'تم تغيير قيمة المتغير "var_value" (وبالتالي يتم تغيير "var_number" أيضًا في نفس الوقت)
    
     End Sub
     'نهاية الإجراء الفرعي
    
     MsgBox var_number
     'تم تغيير المتغير "var_number" لذلك سيتم عرض 900 الآن في مربع الحوار
    

    الطريقة الثانية هي استخدام ByVal.

    بخلاف ByRef ، الذي يمرر مرجعًا (تسمية) ، يمرر ByVal قيمة ، مما يعني أن القيمة التي تم تمريرها كوسيطة لم يتم تعديلها.

    يمكنك أدناه معرفة كيفية عمل الكود السابق و ByVal:

     var_number = 30
     'القيمة الأولية للمتغير "var_number" هي 30
    
     calcul_square var_number
     'يتم تشغيل الإجراء الفرعي باستخدام "var_number" كوسيطة
    
     Private Sub calcul_square(ByVal var_value As Integer)
     'المتغير "var_value" ينسخ قيمة المتغير "var_number" (المتغيران غير مرتبطين)
    
     var_value = var_value * var_value
     'تم تغيير قيمة المتغير "var_value"
    
     End Sub
     'نهاية الإجراء الفرعي (في هذا المثال ، ليس للإجراء الفرعي أي تأثير على أي شيء)
    
     MsgBox var_number
     'لم يتم تغيير المتغير "var_number" وبالتالي سيتم عرض 30 في مربع الحوار
    

    ما تحتاج إلى تذكره: استخدم ByVal عندما لا يجب تغيير المتغير.

    المهام

    الفرق الرئيسي بين الإجراء والدالة هو أن الدالة ترجع قيمة.

    اليك مثال بسيط:

    Function square(var_number)
        square = var_number ^ 2 'ترجع الدالة "التربيعية" قيمة "الجذر التربيعي"
    End Function
    
    Sub macro_test()
        Dim result As Double
        result = square(9.876) 'يتم تعيين القيمة التي تم حسابها بواسطة الدالة إلى متغير النتيجة
        MsgBox result 'يتم عرض النتيجة (في هذه الحالة مربع 9.876)
    End Sub
    

    يمكن استخدام الوظيفة في ورقة عمل تمامًا مثل أي دالة أخرى في Excel.

    على سبيل المثال ، للحصول على مربع القيمة التي تم إدخالها في الخلية A1: