• 0
فواز الشمري

السلسلة الذهبية في تعلم البرمجة

سؤال

في هذا الموضوع لن أخوض بشرح نظري ولكن سيكون التركيز في الشرح عن الأدوات التي سيتم استخدامها عمليا في الكود :

ما هي البرمجة باستخدام OOP أو البرمجة الهدفيه :

كلمة OOP اختصار من Object Oriented Programming وهي عبارة عن أسلوب برمجي تم ابتكاره على أساس مساعدة المبرمجين في ترتيب الشفرة المصدرية والاستفادة من إمكانية إعادة الترتيب والاستخدام في برامج أخرى.

كانت اكبر مشكلة يعاني منها المبرمجين وهي مشكلة التكرار الذي يصاحب البرنامج فمثلا لو أردنا أن نكتب برنامج ما وليكن مثلا أننا نريد أن نظهر نافذة ما في منتصف الشاشة مع الميلان قليلا ناحية اليسار :

سنحتاج في هذا إلى إنشاء الكود التالي :

Private Sub Command1_Click()
 Dim H As Long, W As Long
   
   H = ((Screen.Height - Form1.Height) / 2)
   W = ((Screen.Width - (Form1.Width + 2145)) / 2)
     
   Form1.Move W, H
   Form1.Show vbModal
End Sub

في الكود السابق تم تعريف متغيرين من نوع Long وذلك لأخذ موقع النافذة بالنسبة للشاشة ولقسمة على الرقم 2 ليجعل ظهور النافذة في المنتصف.

نلاحظ أيضا استخدام الدالة Move التابعة للنافذة Form1 ووظيفة هذه لداله هوا تحريك النافذة على المستوى الأفقي والعمودي وهي تقوم بعمل الخصائص Top و Left . ولإستخدامها في هذه الحالة اسرع بكثير من الدوال Top و Left . في تنفيذ التحريك .

لاحظ لو حاولنا أن نظهر نافذة أخرى في البرنامج في نفس القياسات السابقة ستلاحظ أننا يجب أن نكتب الكود التالي :

Private Sub Command1_Click()
 Dim H As Long, W As Long
   
   H = ((Screen.Height – Form2.Height) / 2)
   W = ((Screen.Width - (Form2.Width + 2145)) / 2)
     
   Form2.Move W, H
   Form2.Show vbModal
End Sub

هذا الكود يقوم بوضع النافذة في المنتصف مائل لليسار لكن : تخيل لو أن عدد النوافذ لديك في البرنامج تفوق 16 نافذة إذا يجب علينا أن نكرر هذا الكود على مستوى 16 نافذة .

كانت هذه مشكلة كبيرة جدا وهي تكرار الشفرة لاحظ كيف تم تكرارها :

لم يتم تغير أي شي في الشفرة سوى اسم النافذة .

من هنا قام مهندسو البرمجيات بعمل حل لهذه المشكلة وهي استخدام الدوال ولإجراءات لحل هذه المشكلة :

تتمثل هذه الفكرة بما يلي :

الإجراء :

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

وبالتالي فهي تساعد في أن تشارك في إعطاء العديد من المهام في البرنامج دون الحاجة لإعادة كتابه الكود أو الشفرة :

في لغة Visual Basic يتم التعريف عن الإجراء على النحو التالي :

[Private | Public | Protected | ] Sub Sub_Name ([Parameters])


End Sub

الأنواع [Private | Public | Protected | ] :

هما عبارة عن أدوات الحماية للإجراء . كيف :

قلت في الأعلى أن الإجراء والد اله هما عبارة عن كتله برمجية يمكن الوصول إليهما من أي مكان في البرنامج . ولكن هنا نوع الوصول قد يتم منعه . كيف :

كلمة Private :

تعني أن هذا الإجراء يمكن أن استخدمه في المكان الحالي الذي أنا فيه . فمثلا لو عرفت إجراء على النحو التالي :

 Private   Sub Sub_Name ()

 End Sub

وكان هذا التعريف في النافذة Form1 :

كلمة Private تعني انه ممكن أن استخدم هذا الإجراء بعني استدعيه من داخل Form1 فقط ولا يمكن أن أستدعيه من Form أخر غير Form1 . مثلا :

لو كنت في Form2 وأردت أن أستخدمه كما يلي :

Form1.Sub_name

لاحظ عند وضع علامة Dot أي النقطة بعد كلمة Form1 لم يظهر اسم الإجراء Sub_name وذلك لأن كلمة Private قد منعت استدعاء هذا الإجراء من خارج Form1 وأنا في هذه الحالة قمت باستدعائه من Form2 .

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

أقوم بتغير كلمة Private إلى Public وهي بمعني يمكن من أي مكان في البرنامج أن استدعي هذا الإجراء وبالتالي يمكن أن أستدعيه من أي نافذة في البرنامج . وهوا يظهر في نافذة الإكمال التلقائي بمجر وضع Dot بعد Form1 .

الكلمة Protected : تعني لايمكن الوصول إلى الإجراء إلى داخل الفئات المشتقة أو Class المشتق او المورث من Class أخر ولا يمكن الوصول إليه عند الاستخدام . دعك من هذا الآن سوف أتحدث عنه عند البدء باستخدام الـ Classes في لغة Visual Basic .

يجب عليك أن تختار احد الثلاثة المذكورة إما Private أو Public أو Protected .

بعد ذكر نوع محدد الوصول إلى الإجراء نذكر كلمة Sub وهي تعني أن هذه الكتلة هي عبارة عن إجراء ثم بعد هذه الكلمة أسم الإجراء بعد ذلك الوسطاء أو Parameters التي تمرر للإجراء .

مثال :

اكتب التالي في النافذة Form1

 Private   Sub SetName ()

 End Sub

هذا الإجراء أسمه SetName و عند استدعائه نكتب التالي :

ضع زر أمر وضع به التالي :

 
Private Sub Command1_Click()
   SetName
End Sub

عند الضغط على زر الأمر سوف يبحث مترجم البرنامج عن لإجراء اسمه SetName فإذا وجدته يتم تنفيذ ما بداخلة من كود برمجي , لنضع الكود التالي في الإجراء SetName ليصبح كما يلي :

 Private   Sub SetName ()
         MsgBox "hi"
 End Sub

الآن قم بالضغط على زر الأمر ماذا تلاحظ , ظهور رسالة تحمل نص Hi .

انتقل إلى النافذة Form2 وحاول أن تستدعي الإجراء . سوف تلاحظ أنه لا يمكنك الوصول إلى الإجراء لأنه هنا خاص بالنافذة Form1 لذلك غير محدد الوصول أو نوع حماية الإجراء من Private إلى Public . ثم حاول أن تستدعيه من Form2 .

ملاحظة مهمة :

تعتبر Form1 شبيهه بالمنزل تحتوى على عدد من الغرف فعند ما أود أن أصل إلى غرفه وأنا بداخل المنزل اذكر اسم الغرفة مباشره .أما لو كنت خارج المنزل وأريد أن أصل للغرفة فإنه يجب أن أذكر اسم المنزل ثم الغرفة .

فلو كنت في Form2 وأود أن أصل لأجزاء من النافذة Form1 يجب أن أذكر اسم النافذة Form1 وبعد ذلك اسم الإجراء أو الشئ الذي أريده .

	Form1.SetName

طيب ما هي آل Parameters أو الوسطاء :

نحن فعلا استفدنا من الإجراء ولكن ما ذا لو أردنا أن نغير الرسالة التي تظهر وهي نص Hi

هنا دعت الحاجة لإيجاد أسلوب أكثر مرونة لتعامل مع مثل هذه الحالة . وهو تعريف الإجراء بحيث يتم تمرير قيمة له من أي مكان في البرنامج ليتم استخدامها في الإجراء.

 Private   Sub SetName (txt As String)
         MsgBox txt
 End Sub

لاحظ أن الوسيط هوا عبارة عن متغير له اسم ونوع بيانات ولكن تعريفة بدون عبارة Dim . والوسيط هنا في الإجراء هوا المتغير txt ونوع البيانات التي سيأخذها هي بيانات نصية . لاحظ أبضا أني غيرت الرسالة التي ستظهر للمستخدم ووضعتها بقيمة المتغير . أما عند استخدام الإجراء مع الوسيط فيكون كما يلي :

من داخل Form1

	SetName "My Name"

من خارج الـ Form1

	Form1. SetName "My Name"

تم ذكر اسم الإجراء ثم بين علامة تنصيص تم وضع كلمة My Name وهي البيانات التي سيستقبلها المتغير txt في الإجراء يعني المتغير txt في الإجراء هوا أي نص ذكر بعد اسم الإجراء . وسيكون ناتج استدعاء الإجراء هوا ظهور رسالة بها نص My Name .

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

Public Sub CenterForm(frm As Form)
 Dim H As Long, W As Long
   
   H = ((Screen.Height - frm.Height) / 2)
   W = ((Screen.Width - (frm.Width + 2145)) / 2)
     
   frm.Move W, H
   frm.Show vbModal
End Sub

هذا عبارة عن إجراء كتلة Block لها بداية من Public Sub ونهاية عند End Sub . اسم الإجراء CenterForm يحتوى على وسيط واحد وهوا frm ولكن يجب النظر إلى نوع البيانات التي أخذها المتغير frm .

يجب أن نعرف انه من أنواع البيانات بيانات قياسية مثل integer , string ,long وغيرها وبيانات اخرى من نوع Object من هذه الأنواع Form,Picture,Command وغيرمن هذه الأنواع .

حيث أنه تم تعريف المتغير frm من نوع Form أي من نوع نافذه وبالتالي فإن القيمة التي يجب ان يستقبلها المتغير frm يجب أن تكون اسم نافذة . ويكون استدعاء الإجراء كما يلي :

	CenterForm Form5

من خارج الـ Form1

	Form1. CenterForm Form5

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

حاولت قدر الاستطاعة تبسيط هذا الدرس أتمتا للجميع الاستفادة منه وهوا موجه للمبتدئين :

سير الدرس سيكون حول الإجراءات Procedures و الدوال Functions و الخصائص Properties ثم الوحدات النمطية Module ثم الفئات Classes . والخوض في تفصيلها وكيفية التعامل معها حتى يتحول الدرس إلى دروس متقدمه وذلك بالتطبيق .

ملاحظة جميع هذه الدروس مرجعي الوحيد هوا ما يحتويه عقلي وتسلسل الدرس من تدفقات التعبير لدي لذا اعتذر لمن لم يفهم الشرح جيدا وأتمنا للجميع التوفيق وفي انتظار التعليقات . وللدرس بقية ؟

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

59 إجابة على هذا السؤال .

  • 0

السلام عليكم

ماشاء الله عليك اخى الكريم فواز,,

موضوع اكثر من رائع بالفعل

ننتظر البقية,,,

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

الموضوع جميل جدا اخي فواز

نرجو منك ان تكمل الموضوع كي نستفيد من علمك

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

يا سلام عليك يا أخي فواز

انت معلم بالشرح .....

عن جد ولا احلى من هيك

اتمنى ان تستمر على هذه الطريقة المبسطة والجميلة

منتظرين بفارغ الصبر يا معلم

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0
لازلنا منتظرين باقية شرحك الجميل اخي فواز
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

شكرا اخي hanysaad على مرورك , وكذلك yasserstars أتمنا ان تستفيد من كل كلمة في هذا الموضوع فهوا هدفي الإفادة والأجر من الله , اخي rsh76 اشكرك على كلماتك والحمد لله ان وفقت في اسلوب عرض الموضوع (الشرح ) . :rolleyes:

سوف أتابع السلسلة التي بدأت الحديث عنها وهي كيفية الاستفادة من هندسة البرمجيات وطريقة الاستخدام الأمثل لها في برنامج Visual Basic :

تصنيف هذا الدرس:

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

بعد أن تعرفنا على الإجراء وكيفية استدعائه سوف أخذ الآن بعض الأمثلة :

في بداية الأمر نحن اتفقنا على أن الإجراء هوا عبارة عن كتله برمجية يتم استدعائها عند اللزوم , وهنا يجب أن أنوه إلى أن الـ Form هوا عبارة عن كتلة برمجية كيف :

جميع ما يكتب في Form من إجراءات ودوال وغيرها من متغيرات وغيرة تعتبر كتله برمجية أي أن Form هوا عبارة عن كتلة برمجية تحتوى على كتل برمجية . يمكن أن أقول أن Form حاوية تحتوى على كتل برمجية (إجراءات – دوال – متغيرات – أحداث)

مثال :

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

سوف نستخدم لمثل هذه الحالة TextBox :

كود منع الكتابة الأحرف في صندوق النص :

Private Sub Text1_KeyPress(KeyAscii As Integer)

End Sub

الكود الموضح هوا عبارة عن إجراء حدث تابع للكائن Text1 , وهذا الحدث هوا KeyPress وهوا القسم المسؤل عن تحديد بعض مفاتيح الـ Keyboard .

Private Sub Text1_KeyPress(KeyAscii As Integer)
   Dim str As String
   str = "0123456789" & vbBack
   If InStr(str, Chr(KeyAscii)) = 0 Then
   KeyAscii = 0
   End If
End Sub

هذا الإجراء المسمى Text1_KeyPress له وسيط KeyAscii من نوع بيانات رقمية نوعها Integer :

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

شرح الكود :

الفكرة في الكود تتمثل بتحويل الرقم الذي يحتويه المتغير KeyAscii إلى الحرف المقابل لهذا الرقم . إذا كان الحرف واقع بين النص Str دل على أن القيمة التي يحملها المتغير KeyAscii هي عبارة عن رقم وإلا فإن القيمة التي يحملها هي حرف أبجدي لذلك تم تصفير المتغير KeyAscii حتى يمنع من الكتابة على صندوق النص Text1.

نعود لمربط الفرس من هذا المثال :

لدي في النافذة Form1 أكثر من 5 TextBox وأريد أن أمنع الكتابة لكل هذه الصناديق سيكون الحل بتكرار الكود المذكور 5 مرات لكل صندوق نص .

وبالتالي سوف يظهر لديك تكرار كبير في الكود وستزدحم اسطر صفحة Form بكودات مكررة , كيف يمكننا حل هذه المشكلة .

سوف استخدم في هذه الحالة الدوال لحل هذه المشكلة :

ماهي الدالة :

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

التعريف : يتم تميز الدالة عن الإجراء بذكر Function بدل من Sub كما يلي :

تعريف دالة

[Private | Public | Protected Function fun_name (Parameters ) As DataType 

End Function

As DataType تمثل نوع القيمة التي يجب أن تعيدها هذه الدالة وهي أي نوع من أنواع البيانات سواء كانت بيانات قياسية أو بيانات كائنيه. كما ذكرت سابقا عن أنواع البيانات .

مثال :

Private Function GetName(sec As Integer) As String
   Select Case age
       Case 1
           GetName = "علوم حاسوب"
       Case 2
           GetName = "نظم معلومات"
   End Select
End Function

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

عندما نود من الدالة أن تعيد قيمة يعني تعطي قيمة لمن قام باستدعائها يتم ذكر اسم الدالة ثم إعطائها القيمة المراد إرجاعها كما في المثال:

GetName = "نظم معلومات"

كيف يمكن أن استخدم الدالة لحل المثال المذكور :

يجب أن تضع في بالك دائما أنه لو تكرر معاك كود برمجي أكثر من مره فإنه يحب عليك (أفضل من وجهة نضري ونظر مهندسو البرمجيات) أن تقوم بوضع هذا الكود في دالة أو إجراء بحسب الحاجة.

لحل المشكلة من تكرار الكود السابق بالنسبة لمنع الأرقام في أكثر من TextBox . سوف اعرف دالة باسم GetNumberOnly وأدع هذه الدالة تعيد قيمة من نوع رقم فيكون التعريف كما يلي :

Private Function GetNumberOnly(KAsc As Integer) As Integer
  Dim str As String  
   str = "0123456789" & vbBack
   If InStr(str, Chr(KAsc)) > 0 Then
        GetNumberOnly = KAsc
   Else
        GetNumberOnly = 0
   End If    
End Function

التغير الذي حصل :

جعلت الدالة تستقبل قيمة رقمية ثم قمت بعمل الفحص كما في الكود السابق لكن هنا السطر GetNumberOnly = KAsc يعني ان يعيد نفس القيمة التي مررت للدالة أما في حال لم يتحقق الشرط فإن الدالة تعيد قيمة صفر >

GetNumberOnly = 0 .

كيف يتم إستدعاء الدالة :

كما في الكود التالي سوف يتم استخدام الدالة في كل الصناديق TexBox1 :

Private Sub Text1_KeyPress(KeyAscii As Integer)
  KeyAscii = GetNumberOnly(KeyAscii)
End Sub

في حال استخدام الدوال فإن لابعد من معرفة التالي :

يجب ان يكون الإستدعاء مكون من طرفين مفصولين بعلامة التساوية بمعني أن الدالة يجب ان تعيد قيمة يستقبلها متغير وفي مثالنا هذا فإن المتغير KeyAscii يساوي القيمة التي تعيدها الدالة GetNumberOnly .

والقيمة التي تعيدها الدالة هي إما صفر أو نفس قيمة المتغير الذي تم تمريرة للدالة .

توضيح :

قام المستخدم بالضغط على حرف a وهوا في هذه الحالة يعيده المتغير KeyAscii بالرقم 97 (الرقم 97 هوا الحرف a في جدول Ascii) نمرر هذه القيمة التي حصل عليها المتغير KeyAscii من قبل visual basic إلى الدالة GetNumberOnly الآن داخل الدالة قمنا باستقبال هذا الرقم في المتغير KAsc وهوا من نفس نوع القيمة الممررة Integer . ثم قمنا باستخدام الدالة chr لتحويل الرقم هذا 97 إلى حرف تم الفحص هل الحرف a واقع في str الناتج بالطبع لا لذلك ستعيد الدالة قيمة صفر . الآن يعود المترجم إلى الإجراء المستدعي للدالة وهوا الحدث Text1_KeyPress نلاحظ أن الدالة أرجعت قيمة سيأخذها المتغير KeyAscii . وبالتالي صفرنا قيمة المتغير KeyAscii ولن يطبع على النص الحرف هذا .

ملاحظة :

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

Private Sub Text1_KeyPress(KeyAscii As Integer)
  KeyAscii = GetNumberOnly(KeyAscii)
End Sub

Private Sub Text2_KeyPress(KeyAscii As Integer)
  KeyAscii = GetNumberOnly(KeyAscii)
End Sub

Private Sub Text3_KeyPress(KeyAscii As Integer)
  KeyAscii = GetNumberOnly(KeyAscii)
End Sub

Private Sub Text4_KeyPress(KeyAscii As Integer)
  KeyAscii = GetNumberOnly(KeyAscii)
End Sub

الإستفادة هوا عدم تكرار الكود في كل صندوق نص , حصلنا علي كود صغير , لنا الفدرة على تتطوير الكود الموجود في الداله , وبالتالي فإن التطوير سوف يسري على جميع من يستدعي هذا الإجراء او الدالة .

يتم تميز الدالة والإجراء في قائمة الإكمال التلقائي بوضع أيقونه المساحة وهي تفيد بأن هذه دالة أو أجراء يمكنك ملاحظتها (اضغط Ctrl + Space )

تمرين :

ضع حل أخر لمعالجة منع طباعة الأرقام. ثم مكن زر المسافة (أتمنا من الجميع المشاركة فيه )

في الموضوع القادم سوف نواصل اخذ أمثلة ولكن متقدمة مع تخفيض في شرح الكود حتى لا نخرج من إطار ما وضع هذا الموضوع له , كذلك سوف نبدأ بالتعامل مع Module والتعرف علية .

وللدرس بقية ............ B)

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

موضوع اكثر من رائع

بارك الله فيك

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

جزاك الله كل خير أخي فواز عاي هذا الجمال الذي تقدمه لنا من خلال شرح المميز

وارجو ان توضح لنا الفرق بين الفئة class و الاجراء عند وضعه في مديول

ولك جزيل الشكر

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

جزاك الله خيرا أخي فواز علي هذا الشرح الجميل

جعله الله في ميزان حسناتك

وفقك الله

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

السلام عليكم

الاخ فواز,

بارك الله فيك على هذه الدروس الاكثر من رائعة,

وفى انتظار باقى الدروس,,,

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

في البداية اشكر الجميع على الردود وأتمنا للجميع الإستفادة وبسبب ضيق الوقت لدي لم اسهب في هذا الدرس ولكن سوف اعوض بإذن الله في الدرس القادم .

الدرس الثالث :

استخدام الدوال والإجراءات على مستوى الفورم :

كيف يمكن للإجراء أن يستدعي إجراء أخر :

لنأخذ هذه الحالة :

لو فرضت انه لدي هذه الحالة وهي أن أقوم بتخزين اسم الصورة في قاعدة البيانات لنفرض انه لدي برنامج وعن طريق هذا البرنامج استطيع أدع المستخدم يدخل صورة الطالب ويكمل باقي البيانات :

لدي مشكلة وهي أنه هناك احتمالية وقوع تكرار في اسم الصورة التي سوف أقوم بوضعها في البرنامج مثلا قد تكون اسم صورة الطالب احمد هي a.jbg ومع الأيام أضفت طالب ولكن صورة الطالب هذا تحمل اسم a.jbg إذا لدي مشكلة وهي ان البرنامج سوف يقوم بوضع الصورة الجديدة فوق الصورة الأولى وبالتالي عند استخراج بيانات الطالبين سوف أجد أن الصورة للاثنين معاً .

طبعا فكرة الحل هي أني سوف أقوم بعمل مجلد خاص بالصور واسمية Images وأضع فيه الصور ثم أضع اسم الصورة في قاعدة البيانات .

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

طيب الآن أريد أن أقوم بعمل توليد اسم عشوائي الحل أن أقوم بعمل دالة سوف أسميها GetRandomName كما يلي :

Private Function GetRandomName() As String
   
End Function

لاحظ أن الدالة نوع البيانات التي يجب أن تعيدها هي String .

فكرة عمل خوارزمية توليد الاسم العشوائي :

هي فكرة تولدت لدي حاليا والرغبة لمن يريد تطويرها : وهي أن أقوم بتحديد 36 خانة تتكون من الأحرف والأرقام كما يلي :

Const str As String = "0123456789abcdefghijklmnopqrstuvwxyz"

متغير ثابت يحتوى على الأرقام والحروف الفكرة هي أن أوزع هذه السلسلة إلى خانات بحيث أن طول السلسة

Str هي عدد الأرقام + الحروف 36 خانة سوف اقوم بالمرور العشوائي بحيث اخذ الخانة رقم واحد والأخرى الخانة رقم 10 ومرة 30 وهكذا حتى يتولد لدي مجموعة من الخانات ملخبطة وبعد ذلك سوف اعيد هذه السلسلة العشوائية كنتيجة معادة من الدالة GetRandomName :

المثال كما يلي :

Private Function GetRandomName() As String
   Const str As String = "0123456789abcdefghijklmnopqrstuvwxyz"
   Dim nStr As String
   
   Dim i As Integer, OffSet As Integer
   
   For i = 1 To 36
       Randomize
       OffSet = (36 * Rnd + 1)
       nStr = nStr & Mid(str, OffSet, 1)
   Next i
   
   GetRandomName = nStr
End Function

نظرة سريعة على الشفرة :

دوران 36 مرة حتى اضمن أكثر دقة في توليد الاسم أو السلسلة العشوائية:

Randomize دالة تستخدم في تضبط التوليد العشوائي مقاسه بالملي ثانية.

السطر ( OffSet = (36 * Rnd + 1

تولد رقم عشوائي عن طريق Rnd هذا الرقم الناتج يتم ضربة في 36 حتى يكون الموقع المتولد من الدالة العشوائية Rnd واقع في هذه الخانة . الزيادة بمقدار واحد لإهمال الصفر . ليش :

شوف في كل دورة احدد خانة مثلا المتغير offset كان الرقم الوقع هوا رقم 12 ماهي الخانة في السلسة str التي موقعها 12 ان لم يخني العدد فهوا الحرف b . طيب اخذت هذا الحرف عن طريق الداله Mid وهي اجتزاء حرف من السلسة str من الموقع offset وهوا 12 وبطول واحد يعني الناتج بيكون الحرف b . طيب عود مرة ثانية لنفترض ان العدد الناتج في offset أي الرقم العشوائي هو 0 هذه المره , الدالة Mid سوف تجتزء من السلسلة str من الموقع 0 وهي غير مقبولة لأن الدالة mid تعتبر أول خانة في السلسة str هي 1 وليس صفر إذا هنا سيكون لدينا خطأ عند الدالة mid لذلك زدت المتغير offset عند توليد الرقم العشوائي برقم 1 حتى يهمل الصفر من الحساب .

الآن بعد أن أصبح الإجراء جاهز للإستخدام يمكنني لزيادة الضمان أن أقوم بالتأكد من ان الإسم الجديد غير موجو من قبل يعين ليس مخزن بإسم صورة .

سوف اقوم بالتأكد من هذه العملية في داله اخرى :

Private Function UploadImageFile()

End Function

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

Private Function UploadImageFile() As String
   Dim newImageName As String, Extent As String
   Dim Path As String
   
   With CommonDialog1
       .Filter = "jpg File|*.jpg |Gif File|*.gif"
       .ShowOpen
       If .FileName <> "" Then newImageName = GetRandomName
       Extent = Mid(.FileName, InStrRev(.FileName, "."), 4)
       
       Path = IIf(Mid(App.Path, Len(App.Path) - 1) = "\", App.Path, App.Path & "\")
       
        Do While Dir(Path & newImageName & Extent) <> vbNullString
           newImageName = GetRandomName
        Loop
        FileCopy .FileName, Path & newImageName & Extent
   End With
   
   UploadImageFile = newImageName & Extent
End Function

سوف ادع المثال التالي للدراسة وسوف أعقب علية فور توفر الوقت المناسب:

هذا الأسلوب في البرمجة ارتاح له كثير فإن صدفت هناك مشكلة ما في عدم الفهم سوف أحاول تبسيط الشفرات بقدر الاستطاعة . B)

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

مشكور اخي فواز نرجو منك المزيد

وياريت توضح النقطة التي كنت اثرتها وهي الفرق بين الاجراء عند كتابته في مديول والاجر اء في الفئة class

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

السلام عليكم ورحمة الله

بارك الله فيك اخى العزيز وجعل الله هذا الجهد فى ميزان حسناتك

ارجو منك سرعة استكمال الموضوع بالاخص بناء الفئات بكل ما تشمل من(خصائص-احداث-طرق)

ولكم جزيل الشكر والعرفان

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

جميل هوا التفاعل منكم إخواني الكران لكن حتى اثري الموضوع بالنقاط المهمة سوف انتقل خطوه خطوه بالدرس حتى يكتمل الموضوع بالمفهوم العام له لذى سوف يكون حديثي في الدرس المقبل مهم جدا لكم . :)

تعقيب على الدرس الثالث:

سوف أعيد النقاط الأساسية التي عالجها الدرس السابق:

وهي انه لدينا مثال يتطلب منا أن ندخل بيانات طالب مع صورة له :

في البرمجة يجب:

أولاُ أن نقوم بتحديد المهمة التي يجب علينا عملها .

ثانياً : تحديد المشاكل التي قد تصادفها هذه الطريقة أو المهمة .

ثالثاً :نقوم بتحديد مجموعة من الحلول لهذه المهمة .

رابعاً نقوم باختيار الأسلوب الأفضل من الحلول المحددة .

وهذا الاختيار يجب أن يكون على ساس تفاضل برمجي يعني الحل الأفضل من ناحية السرعة – سهولة التحديث للكود في المستقبل – الأسلوب المستخدم للنظام أو البرنامج الذي أقوم بعملة مثلا قد يكون هناك حل أفضل من حل أخر لكن طبيعة البرنامج الذي اعمل عليه قد يحتم علي أن اختار هذا الحل . نضرا لكبره أو للأمان الذي فيه أو غيره من التفاصيل التي سوف تتضح مع سياق الأمثلة التاليه في الدروس المتبقية :

خامسا : نوع الوظيفة هل سوف استخدمها أكثر من مرة وأقصد بالوظيفة المهمة التي يجب أن أقوم بعملها.

سادساً : بناء ألأسلوب البرمجي .

الأسلوب البرمجي : هو الطريقة التي أفضلها في العمل أو البرمجة يعني ماهي الأدوات التي سوف أستخدمها في الحل وأين سوف أضع الحل في البرنامج .

سوف اقطع المقدمة النظرية الحالية بالعودة للمثال المذكور للتطبيق , ومن ثم سوف أواصل الحديث عن الأساليب البرمجة المتقدمة والتي يجب علينا كمبرمجين أن نتحلى بها :

تحديد الوظيفة: (تطبيق لما ذكر من الكلام ) :

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

هذه الوظيفة بالطبع هي من ضمن وظائف البرنامج ككل. لذا سوف أخذ هذه الوظيفة حتى أطبق عليها أسلوب الحل . وسوف اعتبر هذه مهمة يجب علي تنفيذها (استخدم هذا الأسلوب في حال كان هناك تقسيم للعمل بين أفراد فريق التطوير للنظام يعني إذا كان هناك أكثر من شخص عامل في النظام أو البرنامج )

سوف احدد المشاكل التي قد أعاني منها عند عمل هذه الوظيفة :

ماهية المشاكل :

أين أضع الصور – كيف أقوم بترتيبها – كيف أقوم بحمايتها . – كيف أتخلص من كبر حجمها . الخ

بعد ذلك سوق احدد مجموعة للحلول :

الفكرة الأولى :

أن أقوم بخفض الصور في قاعدة البيانات :

هذه الفكرة جيدة في حال أردت أمان وعدم وصول أي شخص إلى الصور إلا عن طريق البرنامج لكن في هذه الحالة يجب عليك تحديد نوع قاعدة البيانات التي سوف تتعامل معها فلو تعاملت مع Access فهناك مشكلة سوف تواجهك وهوا كبر حجم الجدول المتعلق بالصور وبالتالي سيولد مساحة كبيرة في قاعدة البيانات ونحن نعرف أن قاعدة البيانات Access لا تتعدى 2GB من المساحة .

فبدل أن أهدر الحجم في قاعدة البيانات للصور ولو كانت لدي البينات كبيرة سوف اضطر لعمل قاعدة بينات أخرى وادوخ بعدين في عملية البحث في القاعدة الأولى ثم القاعدة الثانية يعني سيكون لدي مجهود للتعامل مع قاعدتين . وهذا الموضوع لا أريد أن أطول فيه ولكن يجب عليك اختيار الحل المناسب بما يتناسب مع طبيعة النظام فمثلا برنامج مؤسسة صغيرة مش معقول تشتري له قاعدة بينات Oracle وشف بس كم سعرها (في حال البلدان إلي فيها حقوق طبع) , لذلك قد تضطر لاستخدام قواعد بيانات أخرى أقل تكلفة .

ملاحظة :

هناك مواضيع في هذا المنتدى تتحدث عن التفاضل بين قواعد البينات والبرمجيات من ناحية الوظيفة وطبيعة العمل مواضيع مهمة جدا قد تفيد في هذا الموضوع من أرد المزيد لأني لا أريد أن أخرج عن الموضوع .

الحل المقترح الثاني :

هوا أن أقوم بحفظ الصور بمجلد بجانب البرنامج واسمية مثلا Images .

لهذا المقترح نقاط في الحل وهي :

نسح الصورة التي قام المستخدم باختيارها ووضعها في مجلد images الموجود بجانب دليل البرنامج .

بعد أن أقوم بهذا العمل أقوم بتخزين كافة بينان الطالب وأنشأ حقل في جدول الطلاب باسم img اخزن فيه اسم الصورة التي نسختها في مجلد images .

وعند الاستدعاء سوف استدعي اسم الصورة من قاعدة البينان ثم أقوم بتحميل الصورة من مسار مجلد الصور بالاسم الذي استخرجته من قاعدة البيانات.

لكن في هذه الحالة كما ذكرت سيكون لدي مشكلة احتمالية تكرار اسم الصورة كيف:

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

الحل الأول :

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

الحل الثاني :

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

ملاحظة : يجب على المبرمج دائما وضع جميع الاحتمالات التي قد تحدث في البرنامج (على كل مهمة أو وضيفه منه ) حتى يضمن تفادي الأخطاء ويكون البرنامج شبه خالي من الأخطاء بالذات أخطاء وقت التشغيل التي تعبر من الأخطاء القاتلة للبرنامج ) .

في المرحلة الرابعة سوف اختار الحل الأخير وهوا الحل الثاني لتخزين الصور وفي مجلد بجانب البرنامج .

ملاحظة : من ناحية الأمان يمكن عمل خوارزميات تشفير للصور عند حفظها بحيث لا يمكن التعديل أو الفتح أو الحذف وغيرة من عمليات الأمان التي يتطلبها البرنامج - ويمن استخدام Sql-Server أو Oracle لحل هذا النوع من الأمان بحيث كما ذكرت تخزن الصورة في قاعدة البيانات .

خامسا :

في هذه المرحلة سوف احدد هل سوف احتاج هذه الو ضيفه أو المهمة في البرنامج ليش :

هل البرنامج يحتاج أن اعمل رفع صور اقصد نسخ صور ما ,

قد يكون نعم مثلا صور من الإنذارات و التعهدات التي يحصل عليها الطالب .

أيضا صور للمدرسين .

يتضح لدي أنه لدي 3 حالات سوف استخدم فيها وضيفة أو مهمة نسخ الصور .

نحن اتفقنا من البداية أنه في حال حصل تكرار ما لأي (كود أو وضيفة أو مهمة ) كلها نفس المعنى - يعتبر خلل في البرنامج وهذا الخل هوا من وجه نضر هندسة البرمجيات كما ذكرت سابقا في الدروس .

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

أخيرا بناء الأسلوب البرمجي :

1- بناء دالة تستخدم لعمل اسم عشوائي

2- استخدم داله أخرى تستخدم لفتح مربع حوار للمستخدم حتى يستطيع أن يحدد الصورة التي يجب أن تضاف ثم تقوم هذه ألداله بنسخ الصورة الجديدة مع الاسم الجديد لها بعد أن تتحقق من مسار الصورة وكذلك الاسم الجديد بحيث تكون هناك أكثر ضمانه لتوليد الاسم العشوائي بحيث ى يكون مولك من قبل .

3- تحديد الأدوات والدوال التي سوف استخدمها والتي هي معدة من قبل اللغة مثل mid , FileCope وغيرها من الدوال التي سوف احتاجها في الحل .

4- بناء الوظيفة وتحديد الهيكل العام للعمل معها من بقية أجزاء البرنامج, فنحن هنا سوف نتعامل مع وضيفة أو نسميها مهمة أو عملية أي اسم القصد منها هوا كيف سأستدعي هذه المهمة التي تقوم بنسخ الصورة في البرنامج مع الثلاث الحالات وهي (إضافة طالب – مدرس – الإنذارات والتعهدات )

بمعنى : أنه لدي حاليا دالتين هي توليد الرقم العشوائي و تنفيذ النسخ . هذا معنى الهيكل العام للوظيفة .

5- مراعات الحجم في الكود والسرعة في التنفيذ و قله هدر الذاكرة .

الدالتين معاُ في الكود التالي :

Private Function GetRandomName() As String
   Const str As String = "0123456789abcdefghijklmnopqrstuvwxyz"
   Dim nStr As String
   
   Dim i As Integer, OffSet As Integer
   
   For i = 1 To 36
       Randomize
       OffSet = (36 * Rnd + 1)
       nStr = nStr & Mid(str, OffSet, 1)
   Next i
   
   GetRandomName = nStr
End Function

Private Function UploadImageFile() As String
   Dim newImageName As String, Extent As String
   Dim Path As String
   
   With CommonDialog1
       .Filter = "jpg File|*.jpg |Gif File|*.gif"
       .ShowOpen
       If .FileName <> "" Then newImageName = GetRandomName
       Extent = Mid(.FileName, InStrRev(.FileName, "."), 4)
       
       Path = IIf(Mid(App.Path, Len(App.Path) - 1) = "\", App.Path & "imges\", App.Path & "\imges\")        
        Do While Dir(Path & newImageName & Extent) <> vbNullString
           newImageName = GetRandomName
        Loop
        FileCopy .FileName, Path & newImageName & Extent
   End With
   
   UploadImageFile = newImageName & Extent
End Function

الداله : GetRandomName تم التعليق عليها في الدرس السابق :

الداله UploadImageFile :

ماهو محتوى هذه الدالة :

في بدايتها متغير newImageName سوف اخزن فيه الاسم العشوائي , متغير أخر Extent أخزن في امتداد الصورة .

CommonDialog1 معروف مربح الحوار فتح و محدد انه يفتح فقط الصور jpg , gif . عن طريق الخاصية Filter .

بعد ذلك يأتي السطر :

If .FileName <> "" Then newImageName = GetRandomName

وفيه أتحقق هل أن المستخدم قد اختار صورة فعلاً : إذا كان نعم :

استدعي الدالة GetRandomName حتى تقوم بتوليد سلسلة عشوائية بعد ذلك تعيد هذه الدالة GetRandomName السلسة العشوائية للمتغير newImageName .

في الدوال عند الاستدعاء ينفذ أولاً الطرف الأيمن ثم الناتج من الطرف الأيمن يعطى للطرف الأيسر . لاحظ ما هوا نوع البيانات التي يأخذها المتغير newImageName .

ملاحظة : لمعرفة نوع البيانات ضع الموشر فوق المتغير ثم قم بالضغظ بالزر Ctrl + I .

سوق تلاحظ أننا عرفنا المتغير newImageName من نوع String , وبالتالي فإنه يجب على الداله GetRandomName أن تعيد نوع بيانات String حتى يقبل المتغير newImageName هذه البيانات .

عد إلى تعريف الداله GetRandomName لاحظ أننا عرفناها تعيد نوع بينات String .

بعد هذا العمل :

أريد معرفة إمتداد الصور التي قام المستخدم بإختيارها : لنفرض انه اختار a11.gif أريد الحصول على .gif

لدي داله هي InStrRev مشابه لعمل الدالة InStr وضيفتها البحث من اخر خانة في النص عن نص إلى بدايه السلسلة .

لذلك سوف أبحث من نهاية السلسلة والتي تمثلها الخاصية FileName طبعا تعيد مسار الصور كما يلي :

C:\My Pic\a11.gif سوف أبحث عن النقطة (.) وأبدأ البحث من نهاية السلسة .

. الداله InStrRev : الصيغة العامة لها InstrRev(Text, Search) حيث Text يمثل النص او السلسلة النصية المراد البحث بها , Search يمثل عنصر البحث . أو الكلمة التي اود البحث عنها , تعيد الدالة موقع الكلمة التي اود البحث عنها في السلسة النصية .

في حالتنا هذه سيكون الموقع الذي تعيده ألداله هوا 14 . والذي يمثل موقع النقطة في النص.

طبعا الامتداد في الغالب يكون من 4 خانات مثل .jpg أو .gif لذلك سوف استخدم ألداله mid وضيفتها إرجاء نص من نوقع محدد وبطول محدد من نص أخر

Mid(text,Start,End) : يمثل text النص المرد القطع منه , Start الموقع الذي سوف يبدأ منه الاقتطاع , End يمثل نهاية الإقتطاع .

نحن هنا نود أن نعيد أو نقطع النص التالي .gif من النص C:\My Pic\a11.gif

Extent = Mid(.FileName, InStrRev(.FileName, "."), 4)

الداله Mid بدأت من الموقع الذي تعيد الدالة InStrRev , ورجعت نص بطول 4 خانات ابتدأ من الموقع الذي تعيده الدالة InStrRev . هذا النص المعاد من الداله Mid تم خزنه في المتغير Extent .

بعد ذلك سوف احدد مسار تواجد المجلد image والداله app.path تعيد لي المسار إلى موقع الملف التنفيذي للبرنامج . وبالتالي سوف ازيد عليها فقط اسم المجلد image حتى يكون المسار بالكامل مع اسم المجلد الخاص بالصور .

ملاحضة :

المسار التذي تعيده الداله app.path أحياننا يكون على الصيغة التاليه :

C:\My Project

أو

C:\My Project\

يعني أحياننا تعيد في نهاية المسار العلامة \ والتي تحدد نهاية المسار وأحياننا لا : لذلك كان لابد التأكد أولا من وجود هذه العلامة في حال كان موجودة أضيف اسم المجلد الخاص بالصور مباشرة :

C:\My Project\images\

أما إذا لم تكن موجود أقوم بإضافة العلامه \ ثم اسم المجلد :

C:\My Project\images\

هذا الحل متمثل بشرط استخدمت الداله iiF لعمل هذا الشرط وهي مشابه للـ If

الصيغة العامة :

Iff(الشرط ,إذا كان صحيح  , إذا كان خاطئ)

وهي تعيد إحدى الحالتين الناتجة من الشرط :

مثال لتوضيح :

	B = iif(a <1 ,"OK","No")

إذا كان a إقل من 1 فستعيد الدالة iif القيمة OK للمتغير B وإلا ستعيد القيمة No للمتغير B .

المثال في الداله الخاصة بنا أيضا :

Path = IIf(Mid(App.Path, Len(App.Path) - 1) = "\", App.Path & "imges\", App.Path & "\imges\")

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

سوف استخدم حلقة دوران Loop للتأكد من ذلك : في حال انه تم توليد اسم عشوائي موجود من قبل تعيد الدالة توليد اسم عشوائي أخر وتعيد الفحص هل هذا الاسم قد تم حفظ صورة به من قبل أم لا :

Do While Dir(Path & newImageName & Extent) <> vbNullString
           newImageName = GetRandomName
        Loop

ألداله Dir تأخذ المسار وتعيد قيمة فارغة في حال كان غير موجود ولا تعيد المسار نفسة في حال كان موجود .

لذلك شرط التكرار Do While هوا أن يغير اسم جديد إذا لم تعد الدالة Dir قيمة فارغة (القيمة الفارغة تعني ان الإسم غير موجود والبحث هنا في السمار بالكامل اقصد الملف يمرر للدالة dir المسار ثم اسم الصورة ثم الامتداد ) .

بعد ضمان ان الإسم المتولد لم يخزن من قبل بإسم صورة أو لا توجد صورة تحمل نفس هذا الإسم :

نقوم بنسخ الصورة بالاسم الجديد إلى المسار المحدد :

FileCopy .FileName, Path & newImageName & Extent

[code]

بعد هذا العمل أريد أن أنفذ أخر خطوه وهي أن أخزن اسم الصوره هذا في قاعدة البينات :

وهذا بدوره له معالجة أخرى , وهوا أن أضيف هذا الاسم في الاستعلام عند حفظ بيانات الطالب :

لذلك سوف ادع الدالة UploadImageFile تعيد فقط الإسم العشوائي الذي نسخت الصورة به مع الامتداد

وأترك بقية المعالجة للإجراءات الأخرى التي استدعت هذه الداله لتقوم بعملية تنفيذ حفض البينات في القاعدة .

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

في نهاية الموضوع أتتمنا للجميع الاستفادة والتطبيق الفعلي لهذه الدروس , أتمنا أيضا من الجميع الدعاء فهوا خير معين .

في الدرس القادم سوف أخوض في تفاصيل أنواع البينان و تمرير المتغيرات بين الإجراءات والدوال وكذلك إن ساعد الوقت سيكون هناك مقدمة عن الـ Module بحيث يبنى الدرس من بالتسلسل .

وللسلسة بقية . B)

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

مش لاقي كلام اقوله لك اخي فواز غير

جزاك الله كل خير وبالتوفيق دائما

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

جزاك الله خيرا اخى الكريم على المعلومات القيمة

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

جازاك الله خيرا على هذا الموضوع

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

جازاك الله خيرا على هذا الموضوع

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

السلام عليكم

بارك الله فيك اخى العزيز

اتمنى منك مواصلة هذا المجهود الرائع

جزاكم الله خير الجزاء

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

عندما رأيت عدد القراءات لهذه السلسلة والتعليقات من الزوار الأفاضل زادني ذلك حماس في إكمال هذه السلسلة التي بدأت الجزء الأول منها عن بناء Classes أو الفئات .

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

موضوع الدرس : تمرير المتغيرات بين الإجراء والدوال :

] مقدمه للمبتدئين - والمحترفين [

المتغير أولا ما هوا المتغير :

هوا عبارة عن قيمة , قد تكون هذه القيمة رقم أو نص أو حرف أو منطق أو غيره من القيم .

كيف يتم التعامل معه في اللغات البرمجية :

المتغير هوا عبارة عن اسم يشير إلى قيمة في الذاكرة .

القيمة أو البيانات التي يأخذها المتغير.

جميع القيم أو البينانات تقسم إلى الأنواع التالية : بيانات رقمية Number وهذه البينات تقسم أيضا رياضيا إلى بيناتا رقمية كسريه , وأخرى غير كسرية , من أنواع البيانات أيضا بيانات نصية قد تكون حرفية char أو سلسلة نص String , وهناك أيضا بينانات أخرى عديدة تقسم بتصنيف دقيق حتى يسهل معالجة هذه البيانات عند الاستخدام .

هذا النوع من التصنيف (رقمي بأنواعه – نصي بأنواعه – منطقي [True-False]... الخ ) يسمى بالتصنيف القياسي Standard Data Type .

هناك تقسيم أخر لنوع البيانات Data Type التي يمكن للمتغير أن يأخذها هذا التقسيم يسمى Object أي كائني

من هذه الأنواع الـ Classess .

مثال :

عند تعريف متغير نستخدم عبارة Dim للتعريف ثم نحدد اسم المتغير Variable name ثم بعد ذلك الكلمة As والتي تحدد نوع البيانات التي سوف يأخذها المتغير (أو ما هي البيانات التي سيتم وضعها في الذاكرة هل هي نص أم حرف أم رقم أم إيش بالضبط)

Dim Fawaz As String 
Dim F
Dim Al-hassel as Integer
Dim Value as Double

جميع التعريفات السابقة تعتبر من نوع البيانات القياسية :Stander Data Type .

[String- Integer- Double ] .

ملاحظة السطر الثاني تم تعريف متغير ولكن لم يحدد نوع البيانات له لذلك سوف يقوم visual Basic بإعطاء المتغير F نوع بيانات افتراضي هذا النوع من البيانات أسمه Variant وهذا النوع من التعريفات لا يفضل لأنه يأخذ حجم كبير في الذاكرة تقريبا 16Byte .

ما هي الفائدة من تعريف وتحديد نوع البيانات للمتغيرات :

من الأساسيات المهمة لأي متعلم لغة برمجية أن يدرك هذه الفائدة بالذات لأنها من النقاط المهمة والتي تميز المبرمجين المحترفين عن الغير محترفين .

كيف :

لدي الرقم 10 أريد أن أضعه في متغير ما ودعت الحاجة لذلك .

سوف أقوم بتعريف متغير من نوع بيانات Data Type رقمية Number ولكن ما هوا نوع هذا الرقم لأن البيانات الرقمية تنقسم إلى قسمين الأول بيانات صحيحة وبيانات حقيقية (كسرية وغير كسريه) لذلك يجب أن أحدد هل القيمة 10 كسرية إذا كانت سوف أستخدم إحدى البينات التاليه [Double Single] هذه الأنواع من البيانات تقبل الأرقام الكسرية أي خصصت لهذه المهام أما في حالتنا فالقم 10 غير كسري لذلك سوف أخذ بيانات رقمية غير كسرية وهذه البيانات [Byte Integer - Long] يمكنني أن أختار واحد منها .

لكن معيار الاختيار هنا ليس عشوائي بل يجب أن يكون دقيق لماذا لأن أنواع البيانات الثلاثة المذكورة تحجز في الذاكرة مساحات متفاوتة حيث Byte حدوده من 0 إلى 255 رقم , فإن وقع معاك رقم في هذا الإطار قم بحجز نوع البيانات للمتغير من نوع Byte . أما إذا زادة القيمة فهيا في الترتيب التالي Integer يحجز في الذاكرة 2Byte نوع البيانات الأخر Long يحجز 8Byte .

هنا نقطة مهمة في اختيار أنواع البيانات :

يجب أن تكون بخيل في إعطاء المساحات للمتغيرات لماذا حتى لا تهدر الذاكرة , ألحين برنامج ككل لو أخذ من الذاكرة 3Mb وهوا برنامج صغير لا يحتاج لهذه المساحة كلها , لديك خلل واعرف أنك هدرت مساحات في الذاكرة على ألفاضي . قد تقول أن الذواكر حاليا كبيره جدا قد تصل إلة 1GB لكن خلي بالك أن كلامي هنا عن هندسة البرمجيات , وهي مفهوم شامل للبرامج الضخمة التي تصمم وفق معاير دقيقة جدا وتخضع لمقارنه في السرعة وفي حجم التخزين في الذاكرة , حتى لا نهدر مساحات الحجز في ألذاكره وندع المستخدم بما تبقى له من الذاكرة أن يقوم بتنفيذ برنامج أخر , لذلك برامج الرسم ومعالجة النصوص هي من أهم البرنامج التي يتم التعامل مع الذاكرة فيها بشكل دقيق جدا حتى نكسب السرعة كما ذكرت وأيضا لا ترهق المعالج وتسبب بطئ في النظام ككل أقصد بالنظام نضام التشغيل والبرنامج نفسه .

ملاحضة أخرى :

بعض المبرمجين المحترفين ومهندسى البرمجيات وبالذات بانو Clasess يفضلون وبشده عدم الإكثار من تعريف المتغيرات في البرامج إلا إذا دعت الحاجة له .

ليش : :blink:

(المشكلة أن الموضوع يجب أن يغذى بالمعلومات بشكل جيد , وأشعر أنه سيسب بعض الإرباك لدى القارئ لكن أتمنى أن لا يكون ضني صحيح )

شوف نحن عندما نعرف متغير ماذا يحصل في الحاسوب : يتم حجز خانه أو مساحة حجم هذه المساحة مبني على نوع البيانات Integer أو String أو غيره . فلو فرضنا أنه تم حجز 2Mb في الذاكرة , ماهي العمليات التي تتم في هذه الحالة . طبعا التخزين في الذاكرة يتم بشكل عشوائي . بحيث يتم البحث عن مساحة فارغة في الذاكرة ثم بعد ذلك يتم تحديد عنوان لهذه الخانة في الذكرة بحيث يعطى عنوان من بداية الخانة وعنوان في نهاية الخانة ليوضح حدود ألخانه التي تم حجزها , طيب هذا العنوان عادة ما يتم تكوينية بالنظام الست عشري Hex Decimal . هذه العمليات ألتي تتم في ألذكره لحجز هذه الخانة تتطلب وقت في المعالجة , عند كثرتها تسبب بطئ في النظام , طبعا هذا العمليات تتم في لمح البصر لكن أقصد تكرارها يسبب بطئ خاصة إذا كانت الذاكرة شبه ممتلئة ,

للمزيد من المعلومات قم عزيز القارئ بالبحث عن كيفية تخزين البيانات في الذكرة وما هي الطرق المتبعة لهذه العمليات , فهذا علم بحد ذاته والحمد الله أن هذه العمليات يقوم بها نظام التشغيل وليس المبرمج وإلا لكنا دخنا في مسائل لن أقول معقدة لكن تحتاج نوع من الذكاء والحذر لأنه لو حدث خطأ في الذاكرة وتداخلات في العناوين بالذات العناوين التي يحجزها نضام التشغيل لنفسه في الذاكرة تسبب انهيار كامل في نضام التشغيل .

تجد هذه المواضيع في أنظمة التشغيل (لطلاب الجامعات في مادة نضم تشغيل الحاسوب ) أتمنا من كل شخص يريد أن يزيد معرفته , التركيز على هذه المادة لما لها من أهمية بالغة في فهم التعمليات البرمجية كيف تحدث .

لذلك سيكون من المهام الأساسية لنا عدم الإكثار من تعريف المتغيرات . (شوف على سبيل المثال نظام التشغيل Windows Me فيه العديد من المشكل منها أنه ينهار بسرعة كبيرة جداُ وذلك لعدم قدرته على إدارة موارد النظام بالشكل المضبوط , لذلك تم تفادي هذه المشاكل وتم إعادة هندسة نظام التشغيل من جديد وظهر WinXp ليدير موارد النظام بشكل منفصل عن مهامه وبذلك لم يحدث انهيار إلا في حالات نادرة , وإن حدث خطأ ما فإن النظام يقوم بتحديد المسبب للخطأ ثم يقوم بإلغاء وتوقيف جميع الأوامر المتعلقة به وبذلك يعزل بقية العمليات من الاشتباك في الخطأ الذي حدث وبذلك يضمن سير العمليات الأخرى بأمان .

أعرف أني عقدتها شويه بس أتمنى أن يكون القصد مفهوم وإن لم يكن كذلك قم بعمل تراجع لهذا الكلام وبدأ معي من هنا :rolleyes:

كيف أمرر المتغير عن طريق الإجراء :

Dim Pi AS  Double 
Pi = 180/360

SubName Pi

من الكود المذكور تم تعريف متغير من نوع بيانات رقمية كسرية Double ثم تم إعطاء المتغير القيمة 180/360 بعد ذلك تم استدعاء الإجراء المسمى SubName وهذا الاسم افترضت أنك قد قمت بتعريفه من قبل وكتابه الكود اللازم به , تم تمرير المتغير Pi إلى الإجراء هذا وسيقوم الإجراء باستقبال القيمة التي حملها المتغير Pi ويتعامل معها بعذ ذلك بحسب الحاجة .

Private SubName (val As Double)
---------
---------
MsgBox val
End Sub

الإجراء SubName أستقبل قيمة المتغير Pi ولكن الذي استقبل هذه القيمة هوا المتغير val في الإجراء ولاحظ أن نوع البيانات للمتغير المستقبل يجب أن تكون نفس بيانات المتغير العاطي أو الممرر للإجراء .

ملاحظات مهمة :

هنا ظهرت مشكلة وهي أنه لدي متغير اسمه Pi من نوع Double تم الحجز له في الذاكرة 8Byte وتم وضع ناتج القسمة 180/360 في هذه المساحة .

في الإجراء تم تعريف المتغير val في الذاكرة من نوع Double تم الحجز له في الذاكرة 8Byte . بعد ذلك تم وضع القيمة الخاصة بالمتغير Pi وتم وضعها في الخانة التي تم حجزها للمتغير val .

لاحظ من الكلام : ماذا تستنتج : أنه تم تعريف خانتان في الذاكرة كلاهما تحمل نفس القيمة . يعني هذا تكرار في البيانات في الذاكرة , طيب أيش الحل في هذه الحالة . (المتغير Pi له ناتج القسمة في المساحة الخاصة به , والمتغير val أعطاه المتغير Pi نسخة من إلي معا ه وخزنها المتغير val في المساحة الخاصة به)

قام خبراء مهندسو البرمجيات بإيجاد حل لها على النحو التالي :

[فكر بها قبل أن ترى الحل – و شوف هل عقلك قادك للنتيجة التي تم معالجة هذه المشكلة بها .]

بما أن المتغير يحجز في الذاكرة بعنوان وقلت أن العنوان هذا الذي يشير إلى مكان ألخانه فيزيائيا على الذاكرة يعني وين موجودة خانه المتغير Pi في الذاكرة . يوجد عنوان يشير إلى وجود هذه الخانة يعني مكانها ,

طيب هذا العنوان يحصل علية المتغير Pi فعندما نريد أن نظهر رسالة MsgBox للمتغير Pi فإنه يتم البحث عن اسم المتغير هل هوا معرف أم لا ثم بعد ذلك هناك جدول في الذاكرة يحمل اسم المتغير والعنوان الخاص بهذا المتغير إلى الذاكرة يقوم المعالج بالبحث في الذاكرة باستخدام العنوان الذي أعطاه نضام التشغيل ليمثل الطريق إلى موقع ألخانه فيزيائيا على الذاكرة . بعد ذلك يقوم المعالج بمتابعه المعالجة وتفسير الطلب وهوا جلب القيمة التي يشير إليها العنوان ثم عمل معالجة لإظهارها في MsgBox .

هذا باختصار شديد حتى لا أدع الفهم والتركيز لدى القارئ غير مشتت , (هذا إذا لم يشتت ). :rolleyes:

كيف نستفيد من هذه الحالة :

لحل مشكلة تكرار القيم أو البيانات في الذاكرة في هذه الحالة : وضع الحل التالي :

وهوا تم تعريف متغيرين Pi و val من نفس نوع البيانات ولكن الفرق أنه الأول له خانه في الذاكرة محجوزة وبها قيم عندما أود أن أعطيها للمتغير val لن أعطيه القيمة وإنما سوف أعطيه نفس العنوان الفيزيائي لمعطى للمتغير Pi لذلك سوف يشير هذا العنوان إلى مكان الخانة الخاصة بالمتغير Pi ولن يتم حجز خانه للمتغير val في الذاكرة لأنه يشير إلى خانه موجودة مسبقاً . وبالتالي فهناك متغيران يشيران لخانة واحدة وبالتالي : من هذه الملاحظة أستنتج أنه لو غير المتغير Pi وأعطى قيمة أخرى غير القيمة التي هي مخزنه في الخانة على الذاكرة والتي هي في مثالنا 180/360 سوف تتغير القيمة عند المتغير val ليش لأنه يشير لنفس الخانة أو الموقع في الذاكرة , والعكس صحيح فلو غيرت قيمة المتغير val سوف يحدث التعديل على الخانة في الذاكرة وبالتالي سيتم تغير الخانة التي يشير إليها المتغير Pi , أصلاً هي خانة واحدة الاثنين هما يشيران لها فلو وحد غير فيها شي التغير ساري لأثنين .

لكن ظهرت مشكلة أخرى أنه لو سلمت لإجراء ما متغير وهذا المتغير مررته للإجراء ليس بقيمة أي نسخة من القيمة التي يحتويها وإنما بالمرجع (العنوان) , فلو غير الإجراء هذه القيمة فرضياُ وعدت إلى الدالة التي استدعت المتغير ستكون خانه المتغير لذي قمت بتمريره مغيرة , وهذه الحالة اعتبرت مشكلة وهي أحيانا لا أود أن يحدث أي تغير في القيمة للمتغير الممرر . لذلك تم اقتراح إحدى الحالتين وهي :

الحالة الأولى : والحالة الثانية :

وهي أن أمرر نسخة من قيمة المتغير للإجراء وهذا بدورة سيولد بيانات مكررة في الذاكرة ولكن الحاجة قد تستدعي منى ذلك ,

أما الحالة الثانية وهي أن أقوم بتمرير عنوان هذا المتغير وليس قيمته وبالتالي سوف أقلل من تكرار البيانات في الذاكرة وكذلك هدر السعة التخزينية .

كيف يمكن تطبيق هذه الحالات في Visual Basic :

التمرير بالقيمة By Value و التمرير بالمرجع By References :

يعتبر Visual Basic التمرير دائما بين الإجراءات والدوال وهو التمرير باستخدام أسلوب By References افتراضيا , يعني إذا لم تحدد نوع التمرير هل بالقيمة أم بالمرجع (العنوان)

ففي الإجراء التالي يعتبر التمرير للمتغير Name هوا بالمرجع By References:

Private Sub Command1_Click ()
Dim Name As String
Name = "Fawaz M. Al-Shamri"

SetName Name
MsgBox Name
End Sub

Private Sub SetName (n AS String)
MsgBox n
n = "Sami Ali"
End Sub

لاحظ أني لم أحدد نوع التمرير لذلك سوف يفترض فيجول بيسك التمرير بالمرجع أو العنوان بدليل أنه مررت قيمة للمتغير Name إلى الإجراء ليستقبل هذه اليقمة المتغير n وبالتالي عملت MsgBox للمتغير n الناتج سيكون هوا القيمة Fawaz M. Al-Shamri . بعد ذلك غيرت القيمة التي حصل عليها المتغير n إلى Sami Ali .

لو كان التمرير في هذه الحالة بالمرجع فإن المتغير n يشير إلى الخانة التي يشير إليها المتغير Name وبالتالي وليس لدى المتغير n خانه أو مساحة في الذاكرة وإنما اعتبرت خانته هي خانه المتغير Name وبالتالي سوف يعدل البرنامج على الخانة التي يشير إليها العنوان الفيزيائي الخاص بالمتغير n وهي نفس الخانه التي يشير إليها العنوان الفيزيائي الخاص بالمتغير Name . من خلال هذا الكلام سيعود المترجم إلى زر الأمر Command1_Click بعد تنفيذ الإجراء SetName تتوقع ما هي نتيجة السطر التالي بعد استدعاء الإجراء إذا كان التمرير بالمرجع (أو العنوان) :

MsgBox Name

إذا كانت بالمرجع سوف تكون النتيجة هي : Sami Ali أما إذا كانت بالقيمة فستكون Fawaz M. Al-Shamri

طبعا الناتج هنا هو Sami Ali لماذا لأن التمرير قد مرر بالمرجع لأن visual Basic أعتبره افتراضي لأنه لم يحدد .

عند التمرير بالقيمة نعدل الإجراء إلى التالي عند تعريف المتغير n لنخبره أنه سيستقبل عنوان حتى لا يحجز خانه.

Private Sub SetName(ByVal n As String)
   MsgBox n
   n = "Sami Ali"
End Sub

الناتج من الإجراء بعد التعديل سيكون Fawaz M. Al-Shamri : ليش عود لبدايه الشرح :blink: .

يمكن أيضا تحديد نوع التمرير بالمرجع كما يلي :

Private Sub SetName(ByRef n As String)
   MsgBox n
   n = "Sami Ali"
End Sub

عمر المتغير :

المتغير n في الإجراء متى يتم حذفه .

يجب أن تعرف أن المتغيرات لها نوعين من التعريف

النوع الأول يسمى تعريف محلي وهوا يستخدم بين الإجراءات والدوال يعني بداخل Block برمجي أيا كان نوعه

ثانيا تعريف عام : وهوا عام يمكن لكل Block الوصول إلية أي انه عام على مستوى البرنامج ككل .

التعريف المحلي يتم التخلص منه وحذفه من الذاكرة لحظة الانتهاء من الـ Block البرمجي , ففي مثالنا تم تعريف المتغير n في الإجراء وبذلك سيتم مسحة من الذاكرة لحظة الخروج من الأجراء End Sub يعني انه هنا فقط للاستخدام الخاص .

عند عملية الحذف :

ماذا يحدث في الذاكرة : تحديد العنوان الفيزيائي للخانة التي تم حجزها للمتغير n البحث عن الحدود للخانة وهناك عنوانين لها عنوان البداية للخانة وعنوان لنهاية الخانة يتم مسح هذه العناوين ثم مسح العنوان الفيزيائي بعد ذك اسم المتغير . وهذه العمليات لها عدد من الطرق تنفذ بحسب الأسلوب المتبع في نضام التشغيل في إدارة الذاكرة . راجع مادة نظام التشغيل في هذا الجانب النضر في عمليات الترحيل والإزاحة وغيره من هذه المصطلحات .

المتغيرات من نوع Object :

قلت أنها من نوع Clasess وهي فئات . من الأمثلة علها (CommandButton , TextBox,Form……)

جميع الأدوات في صندوق الأدوات تعتبر متغيرات من نوع Object .

مثال :

	Dim frm As Form
   Dim Button As CommandButton
    Dim Text  As TextBox

جميع هذه المتغيرات تعتبر من نوع فئات Classess أو Object وهذا الموضوع سوف نتعرف على كيفية تصميمه في بقية السلسة بإذن الله .

التمرير بنفس الفكرة التي يتم فيها تمرير المتغيرات بين الإجراءات والدوال :

مثال :

سوف أقوم بتوليد نافذه تظهر في زمن التنفيذ Run Time :

Private Sub Command2_Click()
   Dim f As Form
   Set f = New Form1
   
  With f
        .Caption = "My Form"
        .Width = 180
        .Show
        .Move 150, 150
  End With

End Sub

مثال أخر عن وضع مصفوفة TextBox في نافذة Form1 في زمن التنفيذ Run Time

ضع text Box على النافذة وغير الخاصة Index إلى 0 ثم ضع الكود التالي في زر امر Command

Private Sub Command2_Click()
  Dim index As Integer

   index = Text1.Count
   Load Text1(index)
   Text1(index).Top = Text1(index - 1).Top + _
       Text1(index - 1).Height + 30
   Text1(index).text = "Text1(" & Format$(index) & ")"
   Text1(index).Visible = True
End Sub

بقدر الوقت المتاح لهذا الدرس لم استطيع أن أوصل الحديث عن هذا الموضوع لذا سوف أتوقف عند هذه النقطة

وأترك البقية لبقية الدروس بإذن الله تعالي .

تمنياتي للجميع استيعاب الدر س فقد حاولت قدر الاستطاعة أن أتحدث بالشكل الذي يستطيع كل من المبتدى والمتقدم أن يفهم ما أحاول توصيلة من أفكار , لذلك أكرر أعتذاري إذا وجد نقص في إثراء إحدى النقاط أو للبس في شرحها .

وللسلسلة بقية إلى القاء .( أتمنى الدعاء لي بالنجاح فلدي اختبارات حالياُ). B)

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

اخي فواز أولا يجب أن أقول لك ان شرحك أكثر من ممتاز وادعو لك الله ان يوفقك في اختبراتك ان شاء الله

واتمني منك شرح دروس الفئات بنفس المستوي ان شاء الله

وكان لي اسفسار في الجزء السابق من الموضوع وهو

المتغيرات التي تكون علي مستوي النافذة او المحلية تأخذ قيمة من الذاكرة فعند الانتقال الي نافذة أخري هل انها تأخذ قيمة من الذاكرة أيضا

واتمني لك التوفيق في اختباراتك ان شاء الله

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

السلام عليكم/ اخى العزيز

بارك الله فيك على ما تقدم لنا من جهد وفير

عندى سؤالين:

1- كيفية استدعاء الداله uploadimagefile

فى المثال السابق

2-

Do While Dir(Path & newImageName & Extent) <> vbNullString

newImageName = GetRandomName

Loop

ما سبق يمكن ان يطبق فى حالة العوده بقيمه فارغه

لكن اذا حصل العكس الحلقه التكراريه سوف تستمر الى مالانهايه؟!

ارجو منكم الافاده على ذلك ونتمنى مواصلة جهدكم المشكور

السلام عليكم

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

بالنسبة لسؤالك أخي yasserstars :

المتغيرات لها عمر أو مدى حياتها تكون على مستوى الـ Block البرمجي بشكل عام لذلك فهي تنتهي و يتم تدميرها من الذاكرة فور أنتها الـ Block البرمجي من الاستخدام .

كيف :

أشرت في الدروس السابقة أن النافذة Form هي عبارة عن كتله برمجية Block يمكن أن أعتبرها حاوية لمجموعة مكن الـ Blocks وبذلك فهي تحتوي على إجراءات ودوال وأحداث وخصائص .

وبذا يكون هنا تعريف المتغيرات تحت التصنيف هذا بحيث لو عرف متغير داخل النافذة Form في قسم Declaration أو التصريحات العامة كان هذا المتغير عام على مستوى النافذة يعني أنه يمكن أن يستخدمه أي Block داخل النافذة , وفي هذه الحالة لن ينتهي عمر المتغير هذا , لو انتهى احد الإجراءات من استخدامه لأنه لم يعرف على أساس أنه محلي داخل الإجراء , أو ألداله أو الخاصية أو غيره . إذا متى ينتهى المتغير الذي من نوع عام في النافذة Form :

فور إلغاء تحميل النافذة بالكامل من الذاكرة .

Unload Form1
Set Form1 = Nothing

بهذه الحالة يتم إلغاء النافذة بما تحتويه من الذاكرة .

وفي نفس اللحظة يتم تحميل النافذة في الذاكرة وإنشاء المتغيرات العامة والكتل في النافذة لحظة تحميل النافذة في الذاكرة عند السطر التالي :

Form1.Show

أخي thelast_pharon :

بالنسبة لسؤالك حول الدوران Loop : في الدالة UploadImageFile :

الحلقة Do While الشرط الأساسي لها حتى تنفذ هوا أن يكون الشرط صحيح True , وفي حالتنا أو مثالنا كان الشرط أن الدالة Dir لا تعيد قيمة فارغة vbNullString . طيب متى لا تعيد الدالة Dir القيمة vbNullString عندما يكون المسار المعطى لها صحيح أي أنه بالفعل هذا المسار موجود والذي هو مسار الصورة في هذه الحالة تعيد الدالة Dir نفس المسار المعطى لها . وإذا كان المسار غير موجود فهي تعيد vbNullString .

الشرط طالما أن الدالة Dir تعيد نفس المسار (أي أنه موجود ) ولد أسم عشوائي جديد ثم تحقق هل الاسم العشوائي موجود عن طريق الدالة Dir في حال لم يكن هذا المسار الجديد (اسم الصورة موجود في مجلد الصور ) ستعيد الدالة Dir القيمة vbNullString وبالتالي لن يحقق شرط الدوران Loop لأن الشرط هوا لا يساوي vbNullString , وبالتالي سوف ينتقل المفسر للكود بعد Loop ولن يحدث أي Loop مالا نهاية (ولن يحدث Over Flow) .

بالنسبة لكيفية استخدام الدالة سوف أتحدث عنه في الدرس التالي :

الدرس الخامس :

استخدام Module :

مقدمة حتى الوصول إلى Module :

تحدث في الدروس السابقة التطورات التي لحقت مجال البرمجيات بفضل مهندسوها والتخلص من التكرار ومشاكله واستخدام الإجراءات والدوال لحل هذه المشكلة .

وكانت الأمثلة السابقة في الدروس تتحدث عن التخلص من التكرار بقدر الاستطاعة , ولكن هناك اساليب دعت إلى معالجة أكثر دقة لتكرار الكود , لوجود مشاكل قد تظهر ليس فقط في تكرر الكود ولكن قد تكون في هدر مساحات في الذاكرة وبطئ المعالجة . كيف :

لنأخذ هذه الحالة :

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

القراء المتابعين معي لهذه السلسة من الدروس سيجدون أن النافذة الخاصة بالفواتير أو سندات القبض تحتوي على أكثر من TextBox وبالتالي فإن معالجة منع المستخدم من إدخال الأرقام سوف يكون لأكثر من TextBox وبالتالي سوف يظهر لدينا تكرار في الكود . من خلال الدروس السابقة تعرفنا كيف يمكن التخلص من هذه المشكلة بعمل إجراء في النافذة Form هذا الإجراء يقوم بمعالجة منع كتابة الأحرف .

لو أردت نافذة حسابات العملاء أو نافذة دليل الحسابات :

سوف ألاحظ أن هذه النافذة أيضا بها إدخال رقمي فقط وبالتالي سوف احتاج إجراء أو دالة لهذه النافذة حتى أمنع التكرار .

طيب كم عدد النوافذ في البرنامج ؟

هنا ظهرت مشكلة وهي أنه لا زال هناك تكرار فعليا للكود في البرنامج ككل هذا التكرار يتمثل بتكرار الـ Block البرمجي (الإجراء أو الدالة ) , بحيث أني قمت بعمل إجراء لمعالجة 6 صناديق نص في النافذة Form1 وإجراء في النافذة Form3 ليعالج 3 صناديق نص TextBox .

يعتبر هذا الإجراء مكرر في النافذتين إذا عند كبر البرنامج ظهرت مشكلة وهي في تكرار الإجراءات والدوال في البرنامج .

قام خبراء البرمجيات بوضع حل لهذه المشكلة وهوا متمثل بما يلي :

قالوا طالما أن الوظيفة لدينا هي واحدة (منع المستخدم من الكتابة بالحروف) . إذاُ يمكننا أن نستفيد من الوظيفة الموجودة في البرنامج ككل وبدون أن نكرر هذه الوظيفة يعني كيف :

أين هي الوظيفة :

لنفترض أن الوظيفة (الإجراء الخاص بمعالجة عدم الكتابة بالأحرف ) موجودة في النافذة Form1 ولدي الحالة في Form3 بها 3 صناديق نص وأريد أن امنع المستخدم من الكتابة بالحرف فيها .

قالوا لا داعي أن تعرف دالة أخرى وهى نفس الدالة الموجودة في النافذة Form1 وإنما يمكنك استخدامها من النافذة Form1 لتعيد لك الحل .

كيق :

ضع 2 Form وضع في النفاذة الأول 3 صناديق نص والثانية 5 صناديق نص : ضع الدالة الخاصة بمعالجة منع الأرقام في النافذة From1

ولتكن الدالة كما يلي( سوف أضع الكود التالي غير المذكور في الدروس السابقة حتى تعم الفكرة في تنوع الأساليب البرمجية في كتابة الكود ) :

Private Function GetNumberOnle(Key As Integer)
   If IsNumeric(Chr(Key)) Or (Chr(Key) = vbBack) Then
       GetNumberOnle = Key
   Else
       GetNumberOnle = 0
   End If
   
End Function

طبعا في النافذة سوف استدعي الدالة كما تعودنا مباشرة في حدث KeyPress التابع للـ TextBox

Private Sub Text1_KeyPress(KeyAscii As Integer)
KeyAscii = GetNumberOnle(KeyAscii)
End Sub

وهكذا بالنسبة لبقية الـ TextBox :

طيب هذا على مستوى النافذة Form1 كيف سأقوم باستدعاء هذه الدالة أو أستفيد منها من نافذة أخرى .

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

في النافذة Form2 في حدث KeyPress التابع للـ TextBox استدعي الدالة كما يلي :

Private Sub Text1_KeyPress(KeyAscii As Integer)
KeyAscii = Form1.GetNumberOnle(KeyAscii)
End Sub

هنا تمكنا من استخدام الدالة الموجودة في النافذة Form1 لتعمل لنا المعالجة المطلوبة وبذلك تخلصنا من مشكلة تكرار الدالة (يعني ما فيش داعي أني أعملها مره ثانية في النافذة Form2 يكفي أن أستدعيها فقط )

وفي هذه الحالة يجب أن أحدد نوع الوصول للدالة GetNumberOnle ليعرف المفسر انه يمكن أن تستخدم هذه الدالة في النافذة Form1 من أي مكان في البرنامج .

وبذلك سوف أغير تعريف الدالة GetNumberOnle من Private إلى Public .

هنا عملنا انجاز وتخلصنا من مشكلة تكرار الدوال والإجراءات , ولكن لتم تتم الفرحة بل ظهرت مشكلة أخرى تعتبر مشكلة كبيرة نوعاً ما :

تحدث في ردي على سؤال الأخ yasserstars بالنسبة لعمر المتغيرات عن الـForm وما تحتوية من كتل ومتى يتم إنهائها من الذاكرة :

الذاكرة : هي دائما ما يجب علينا الحفاظ عليها وكل وجع الرأس هوا بسببها ,

عند تنفيذ البرنامج للمرة الأولى يتم تحميل ما يستفاد منه فقط في الذاكرة كيف :

الحين انا فتحت Form1 ماذا يتم : يتم وضع ما تحتوية النافذة Form1 في الذاكرة فإن كان هناك تعريف متغيرات عامة سوف يتم تحميلها وحجز المساحات لها في الذاكرة والإجراءات والدوال كل الكتل البرمجية يتم تحميلها في الذاكرة . المشكلة الأكبر أن المتغيرات التي من نوع Object وهي الأدوات تعتبر من المثقلات في البرنامج , من هذه الأنواع الأدوات Ocx مثل Command و Picture Box و TextBox وغيرها من الأدوات التي هي موجودة في صندوق الأدوات :

ملاحظة :

جميع الأدوات هذه تنتج بتقنية ActiveX والتي يكون امتدادها Ocx وقد تكون Dll .

أحيانا يقوم المبرمج بوضع خلفية صورة للنافذة Form1 فتخيل أنت معي كم من الوقت يستغرق معالجة تصعيد النافذة بما تحتويه إلى الذاكرة . (طبعا هذا الكلام بالملي ثانية يعنى سريع وليس بطيء كما تتوقع لكن البطء يزاد ويسبب بطء ملحوظ في البرنامج وأحيانا قد يكون كبير إذا كانت النافذة تحتوى على أدوات وصور كثيرة ) .

فلو قمت بفتح النافذة Form1 في بداية البرنامج ثم بعد أن انتهيت من عملي فيها قمت بإغلاقها , وبالتالي سيتم مسح جميع محتويات النافذة من الذاكرة .

طيب الأن ذهب للنافذة Form2 وفي هذا النافذة إستدعاء للدالة التي موجودة في Form1 ماذا يحدث , لاحظ سيقوم المفسر الخاص باللغة بالبحث عن النافذة Form1 في الذاكرة هل هي موجودة حتى يستخدم الدالة GetNumberOnle لأن Form2 قد استدعاها , فأن لم يجدها في الذاكرة ماذا يعمل , يقوم المفسر باستدعاء النافذة Form1 إلى الذاكرة , وبالتالية عندما تستدعى نافذة سوف تقوم بتحميل جميع ما تحتويه من تعليمات برمجية وأدوات أخرى في الذاكرة . وبعد ذلك سيقوم المفسر باستدعاء الدالة GetNumberOnle من النافذة .

من خلال ما حصل ماذا تلاحظ :

أنك قمت بإستدعاء النافذة Form1 إلى الذاكرة وبالتالي فإن الذاكرة تعبت بأشياء أنت لا تريد منها إلا جزء من هذه الأشياء .

الشي الثاني :

تجد بطئ وهذا البطء ناتج من عملية تحميل النفاذة Form2 إلى الذاكرة .

طيب السؤال لي يطرح نفسه الآن وبعد استخدام الدالة , أنك قمت بإغلاق النافذة Form2 هل ستضل النافذة Form1 في الذاكرة .

من خلال تجاربي وجت فعلاً أن النافذة Form1 ستضل في الذاكرة موجودة . وبالتالي يعتبر هذا خلل فاذح في هندسة البرمجيات وهوا وجود كمية كبيرة قد تكون من البرنامج في الذاكرة دون الفائدة في استخدامها .

ملاحظة :

يمكنك في بعض الحالات أن تتخلص من هذه الإشكالية بالنسبة لوجود النافذة في الذاكرة بعمل Unload لها بعد استخدام أجزاءها . عند إغلاق النافذة Form2 , ولكن هذه النوع من العمل يتطلب خبرة في معرفة متى يجب ان تلغي النافذة المستدعاه من الذاكرة يعني فين بتحط الكود بالضبط . وهذا موضوع لا أريد أن أخوض في تفاصيل جودة الكود Optimize Code مع أن هذا الموضوع من أهم المواضيع التي يجب علينا أن نعرفها .

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

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

لحل جميع هذه النقاط تم وضع ما يسمى Modules أو الوحدات النمطية :

ما هوا الـ Module:

عبارة عن كتله برمجية (حاوية مجموعة من الكتل) بها مجموعة من الكتل Block تتمثل بالإجراءات والدوال والأحداث والخصائص والمتغيرات .

الفرق بينها وبين Form هوا :

أنها عامة تدمر عند انتهاء البرنامج , ولا تحتوى على واجه رسومية كما Form .

الغرض الأساسي لها هوا وضع الدوال وغيرها من العمليات البرمجية للاستخدام العام في البرنامج ككل .

كيفية الاستخدام :

من قائمة Project اختر Add Module

مثال يوضح كيف يمكن أن استفيد منه في البرنامج : قم بوضع Module في البرنامج ثم بداخلة عرف متغير من نوع عام Public كما لي :

Public SetName As String

لماذا Public ليحدد أن هذا المتغير يمكن الوصول إليه من أي مكان في البرنامج.

في النافذة Form1 ضع صندوق نص وكذلك في النافذة Form2 ضع صندوق نص

في النفاذة Form1 ضع الكود التالي في زر أمر :

SetName = Text1.Text

لاحظ كيف استخدمت المتغير في النافذة Form1 والذي تم تعريفة في الوحدة النمطية Module .

بعد ذلك توجه للنافذة Form2 وضع الكود التالي في زر أمر :

Msgbox SetName

بعد ذلك قم بتقيد البرنامج على Form1 قم بإغلاق النافذة Form1 وفتح النافذة Form2 سوف تلاحظ ظهور الرسالة بالقيمة التي تم كتابتها في النافذة From1

متى يتم إنها المتغير SetName:

يتم ذلك عند أنها البرنامج بالكامل.

وللسلسة بقية, في الدرس المقبل سوف نتعرف على Module عن قرب ونأخذ أمثلة . B)

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

الدروس جميلة وفقك الله والي الامام دائما

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

شكر لوجودك اخي ياسر وأتمنا لك التوفيق

الدرس السادس :

تعرفنا في الدرس السابق عن الداعي لوجود الوحدات النمطية Module والأهمية من وجودها .

وعرفنا أنها تستخدم لمشاركة جميع ما تحتويه من كتل برمجيه إذا كانت من نوع Public على مستوى البرنامج ككل بحيث يمكن الوصول إليها من إي مكان في البرنامج .(من أكثر من نافذة أو Class أو غيرة )

لماذا استخدم Module على الرغم من إمكانية استخدام ما يحتويه على Forms :

الدرس السابق يجيب على هذا السؤال .

الأمر الأخر هوا عمل تقسيمات للدوال التي غالباً ما يتم استخدامها بكثرة في الأنظمة والبرامج التي تستخدمها كيف :

يمكنك وضع دوال أو إجراءات في Module وهذه الدوال المهمة والتي تستخدمها بكثرة , فلو كان لديك برنامج أخر وتريد استخدام دالة ما فبدل أن تقوم بإعادة كتابتها يمكنك فقط إرفاق Module الذي قمت بعملة في البرنامج السابق لك وإضافته إلى برنامجك الجديد وبالتالي سوف تقوم فقط باستدعاء الدالة بدون أن تقوم بإعادة برمجتها من جديد .

هذا يساعد في إنتاج البرامج بشكل سريع ودون تضيع للوقت في إعادة بناء الدوال وغيرها.

مثال :

سوف أذكر مثال مهم جداُ وهوا حماية البرنامج من النسخ :

الأخوة المبرمجين الذين لا يستخدمون الـ Class أي ملفات DLL في البرامج أو أي ملفات أخرى مساعدة للبرنامج يكون البرنامج سهل جدا نسخة ونقلة إلى جهاز أخر فقط ما علية إلى تحديد الملف التنفيذي وقاعدة البيانات ثم نسخة وبذلك برنامجك يمكن لشخص أخر استخدامه , أما إذا كان البرنامج مرفق به Dll ومحطوطة في مجلد النظام System أو غيرة فهي تسبب إرباك نوعا ما لمن يحاول نسخ برنامجك لماذا بسبب بسيط هوا عدم معرفته باسم الملفات التي وضعت في مجلد النظام والتابعة للبرنامج . هذا على سبيل المثال .

لكن على العموم حتى وإن كان كذلك فبرنامجك لا يزال معرض للنسخ وبسهولة أيضا بسبب بسيط أيضا وهوا إمكانية معرفة الملفات التي تم نسخها عن طريق الملف المرفق للـ Setup التابع لبرنامجك هذا الملف يتم تخزين الملفات التي يجب على Uninstall Setup أن يعرف ما هي الملفات التي يجب علية حذفها , فلو فتحت هذا الملف (أنت وشطارتك بعدين في نقل البرنامج ).

على العموم بغض النظر عن أسلوب الحماية المتبع سواء بتخزين ملفات أو عن طريق الـ Registry . أو غيره .

إلا أن أفضل طريقة للحماية هوا معرفة الرقم التسلسلي للـ Drive . (هذا الرقم لا يتكرر )

الرقم التسلسلي هوا عبارة عن رقم يعطى لكل قسم من أقسام الـ Hard . وبذلك يمكنك فحص هذا الرقم حتى في بداية تشغيل البرنامج ومن من ثم يمكنك عمل ألازم في معالجة البرنامج .

هناك دالة Api عن طريقها يمكن الحصول على معلومات أو خصائص الـ Drive هي تحت اسم

GetVolumeInformation

لأننا أكيد سوف نحتاج هذه الدالة في برامجنا لذلك سوف أضعها في Module مع أني لو وضعتها في النافذة frmLogin وهي نافذة اول نافذه في البرنامج فليست مشكلة لأني لن استدعيها إلا مرة واحدة ولكني سوف أضعها في Module حتى لو أردت استدعائها مرة أخرى في برنامج أخر سوف أرفق هذا الـ Module وآيا يحلو لك قم بعملة .

في حدث Form_Load وهي اول نافذة سيتم بدا البرنامج منها ضع الكود التالي :

Private Sub Form_Load()
Dim Path As String
Dim SerialNumber As Long

Path = Mid(App.Path, 1, InStr(App.Path, "\"))
SerialNumber = GetSerialNumber(Path)

If SerialNumber = 0 Then
   MsgBox SerialNumber
   If SerialNumber <> "1028397051" Then
       MsgBox "ملفات البرنامج غير مكتملة الرجاء إعادة تثبيت البرنامج", vbCritical
        End
   End If
Else
   MsgBox "خطأ في فحص إعدادات النظام"
   End
End If
End Sub

ملخص عن الشفرة المذكورة :

فكرة البرنامج تتمثل بتمرير اسم القرص الذي يعمل علية البرنامج حاليا وتمريره للدالة GetSerialNumber ولمعرفة القرص الموجود على البرنامج تم ذلك عن طريق السطر .

Path = Mid(App.Path, 1, InStr(App.Path, "\"))

الدالة App.Path تعيد المسار بالكامل إلى البرنامج كما مر معنا سابقا في الدروس لذلك قمت بقطع أول قسم من ما تعيده الدالة App.Path والمتمثل باسم القرص كان البحث عن موقع الخانة التي تحتوي العلامة / بعد ذلك الدالة Mid تبدأ بالقطع من الموقع الأول 1 بطول ما تعيده الدالة InStr (إلى موقع العلامة /) .

بعد ذلك تم وضع اسم القرص في المتغير Path .

بعد التمرير للدالة GetSerialNumber كما في السطر :

SerialNumber  = GetSerialNumber(Path)

الدالة GetSerialNumber تعيد الرقم التسلسلي للقرص الحالي وإلا تعيد صفر .

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

If SerialNumber = 0 Then
   MsgBox SerialNumber
   If SerialNumber <> "1028397051" Then
       MsgBox "ملفات البرنامج غير مكتملة الرجاء إعادة تثبيت البرنامج", vbCritical
        End
   End If
Else
   MsgBox "خطأ في فحص إعدادات النظام"
   End
End If

يتمثل هذا الجزء من الشفرة فقط باستدعاء الدالة GetSerialNumber أما شفرة الدالة GetSerialNumber فهي في Module على النحو التالي :

Private Declare Function GetVolumeInformation Lib "kernel32.dll" Alias "GetVolumeInformationA" (ByVal lpRootPathName As String, ByVal lpVolumeNameBuffer As String, ByVal nVolumeNameSize As Integer, lpVolumeSerialNumber As Long, lpMaximumComponentLength As Long, lpFileSystemFlags As Long, ByVal lpFileSystemNameBuffer As String, ByVal nFileSystemNameSize As Long) As Long

Public Function GetSerialNumber(DriveName As String) As Long

   Dim SerialNumber As Long, Result As Long
   Dim Buffer1 As String, Buffer2 As String
   
   Buffer1 = String(255, Chr(0))
   Buffer2 = String(255, Chr(0))
   
   Result = GetVolumeInformation(DriveName, Buffer1, Len(Buffer1), SerialNumber, 0, 0, Buffer2, Len(Buffer2))
   
   GetSerialNumber = IIf(Result > 0, SerialNumber, 0)
End Function

بهذا القدر ينتهي الدرس السادس وسوف أواصل بعون الله في الدروس المتبقية فور توفر الوقت لإكمال الدروس.

وللسلسلة بقية .

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

  • يستعرض القسم حالياً   0 members

    لا يوجد أعضاء مسجلين يشاهدون هذه الصفحة .