منتدى فيجوال بيسك لكل العرب | منتدى المبرمجين العرب
اغتنم أكوادك - نسخة قابلة للطباعة

+- منتدى فيجوال بيسك لكل العرب | منتدى المبرمجين العرب (http://vb4arb.com/vb)
+-- قسم : قسم لغة الفيجوال بيسك VB.NET (http://vb4arb.com/vb/forumdisplay.php?fid=182)
+--- قسم : قسم مقالات VB.NET (http://vb4arb.com/vb/forumdisplay.php?fid=184)
+--- الموضوع : اغتنم أكوادك (/showthread.php?tid=4806)



اغتنم أكوادك - RaggiTech - 02-10-12

كاتب الموضوع : نور نبهان


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

وعندما تنتهي من توزيع أدواتك على النموذج Form ومن كتابة الاكواد في المحررCode تقوم بتشغيل برنامجك وتجربته و التأكد من خلوه من الأخطاء.

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

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

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

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




اغتنم أكوادك - RaggiTech - 02-10-12

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




ستستخدم الكود


كود :
[align=left]TextBox3.Text = Val(TextBox1.Text) + Val(TextBox2.Text
TextBox4.Text = Val(TextBox3.Text) / 2[/align]
لاحظ المستطيل الأحمر نستطيع الاستغناء عن هذه الأداة لان المهم بالنسبة لنا هو الناتج النهائي لذلك نقوم بحذف الأداة وتعديل كودنا إذا كان الأمر سهل فيمكن دمج الكود ومثال الدمج:


كود :
[align=left][FONT=Courier New]TextBox4.Text = (Val(TextBox1.Text) + Val(TextBox2.Text)) / 2[/FONT][/align]
[FONT=Courier New]
[/FONT]


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


كود :
[align=left][FONT=Courier New]Dim A As Double [/FONT]
[FONT=Courier New]A = Val(TextBox1.Text) + Val(TextBox2.Text) [/FONT]
[FONT=Courier New]TextBox4.Text = A / 2[/FONT][/align]
قد تجد المثال بسيط وليس بحاجة لتخزين القيمة ولكن لو أردت العمل على القيمة بعدة عمليات فليس من المعقول أن نخزن كل ناتج في صندوق نص ومثال تعدد العمليات

كود :
[align=left][FONT=Arial]Dim A As Double[/FONT]
[FONT=Arial]A = Val(TextBox1.Text) + Val(TextBox2.Text)[/FONT][FONT=Arial]
[FONT=Arial]A = A \ 2[/FONT]
[FONT=Arial]A = A ^ 2[/FONT]
[FONT=Arial]A = A * (5 / 100)[/FONT]
[FONT=Arial]TextBox4.Text = A[/FONT][/FONT][/align]
[FONT=Arial]
[/FONT]


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

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




كود :
[align=left][FONT=Courier New]Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click[/FONT]
[FONT=Courier New]If TextBox1.Text = "عبدالله العنيق" Then[/FONT][FONT=Courier New]
[FONT=Courier New]MsgBox("تفضل")[/FONT]
[FONT=Courier New]Else[/FONT]
[FONT=Courier New]Button2.PerformClick()[/FONT]
[FONT=Courier New]End If[/FONT]
[FONT=Courier New]End Sub[/FONT][/FONT][/align]
[FONT=Courier New]

[align=left][FONT=Courier New]Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click[/FONT]
[FONT=Courier New]MsgBox("يبدو أنك عضو جديد غير مصرح لك بالدخول")[/FONT]
[FONT=Courier New]End Sub[/FONT][/align]
[/FONT]
ففي الكود السابق استعينا حدث الزر الثاني Button2_Click طبعا يقوم المستخدم عادة بإخفاء هذا الزر بجعل خاصية Visible = False لكنه يبقى استعماله للكود المسئول عنه هذا الزر
ففي هذه الحالة الأفضل أن نقوم بعمل إجراء وبالتالي نستغني عن وجود الزر لاحظ الكود التالي :


كود :
[align=left][FONT=Courier New]Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click[/FONT]
[FONT=Courier New]If TextBox1.Text = "عبد الله" Then[/FONT][FONT=Courier New]
[FONT=Courier New]MsgBox("تفضل ")[/FONT]
[FONT=Courier New]Else[/FONT]
[FONT=Courier New]ERRRRR()[/FONT]
[FONT=Courier New]End If[/FONT]
[FONT=Courier New]End Sub[/FONT][/FONT][/align]
[FONT=Courier New]

[align=left][FONT=Courier New]Private Sub ERRRRR()[/FONT]
[FONT=Courier New]MsgBox("يبدو أنك عضو جديد غير مصرح لك بالدخول")[/FONT]
[FONT=Courier New]End Sub[/FONT][/align]
[/FONT]

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


اغتنم أكوادك - RaggiTech - 02-10-12

3. استدعاء الصور: من المزايا الجميلة التي ستتعامل معها في الدوت نت هي Resources وبسهولة تامة فعندما تريد إضافة صورة لبرنامجك يفضل أن تضيفها إلى Resources العام للمشروع My Project والسبب هو انك تستطيع استخدامها مرارا دون زيادة حجم برنامجك .



تخيل معي صورة تريد أن تكررها في برنامجك عشر مرات وان حجم الصورة 100 كيلو بايت أي إن الصورة لوحدها ستأخذ 1 ميغا بايت لكن بالاعتماد على أل Resources فإن الحجم يصبح 105 كيلو بايت لذلك عند إدخالك الصور تأكد من الطريق التالية وذلك بإدخالها للريسورس العام للمشروع بدل المحلي لكل فورم local لان ذلك يوفر عليك الكثير عند تكرار التعامل مع الصورة أكثر من مرة



وحتى إن كان الاستدعاء سيتم في وقت التشغيل run time


كود :
[FONT=Arial][FONT=Arial]Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click[/FONT]
[FONT=Arial]PictureBox2.Image = My.Resources.nourvb[/FONT]
[FONT=Arial]End Sub[/FONT]

[/FONT]
حيث nourvb اسم الصورة في الكود السابق
نفس العملية بالنسبة للأيقونات

كود :
[FONT=Arial] Me.Icon = My.Resources.Floppy[/FONT]


حيث Floppy اسم الأيقونة في الكود السابق
ويمكن الاستدعاء من فورم لأخر

كود :
[FONT=Arial][FONT=Arial]Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load[/FONT]
[FONT=Arial]Me.Icon = Form1.Icon[/FONT]
[FONT=Arial]End Sub[/FONT]

[/FONT]

وكذلك الأمر بالنسبة للمؤشرات و الأصوات والقيم النصية ....الخ .....



اغتنم أكوادك - RaggiTech - 02-10-12

4.استخدام المؤقت



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


كود :
[FONT=Arial]Timer.Enabled = True Or False[/FONT]


الخاصية الثانية وهي الفترة الزمنية Interval


كود :
[align=right][FONT=Courier New][FONT=Courier New][FONT=Courier New][FONT=Courier New][FONT=Courier New][FONT=Arial]Timer.Interval = 5000[/FONT][/FONT][/FONT][/FONT][/FONT][/FONT][/align]
[FONT=Courier New]

[/FONT]


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






كود :
[align=right]Private Sub Timer_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer.Tick
'Label1.Left = Label1.Left + 1
If TextBox1.Text = "سامر سلو" Then
Timer.Enabled = False
MsgBox("يا مرحباً")
Else
'no
End If
End Sub[/align]
في الكود السابق التايمر يعمل منذ بدء تشغيل الفورم ومع ان المستخدم ليس بالضرورة مستعد لادخال الاسم فورا فإن المؤقت يفحص صندوق النص كل لحظة وربما تكون الفترة الزمنية له 1 أو10 وسيظل يفحص طوال فترة عمل البرنامج وهذه استهلاك سلبي. اجعل الفترة 1000 فالاستهلاك أقل .

حالة اقتصادية أكثر في هذه الحالة نريد الفحص الدائم لعنصر معين فيفضل تشغيل التايمر عند تغيير الاسم فقط ثم الفحص ثم الإغلاق كالتالي :


كود :
Private Sub Timer_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer.Tick
If TextBox1.Text = "سامر سلو" Then
Timer.Enabled = False
MsgBox("يا مرحباً")
Else
Timer.Enabled = False
End If
End Sub
Private Sub TextBox1_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox1.TextChanged
Timer.Enabled = True
End Sub
فيما سبق لاحظ اننا عطلنا المؤقت عند إقلاع الفورم من الخصائص (افتراضي)
ولم نقم بتشغيل ولكن ربطنا تشغيله بتغير الاسم فعند كتابة أي حرف في صندوق النص يعمل التايمر ثم يفحص المدخل ويقوم بالمطلوب ثم يغلق بهذا نكون قمنا بتشغيله عند الحاجة اليه فقط أي نوع من الحيلة لا أكثر وبنفس المردود لك مع استهلاك أقل للموارد
هل انتهى الأمر ؟ يمكننا أن نستغني هنا عن المؤقت كليا كالأتي:


كود :
Private Sub TextBox1_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox1.TextChanged
If TextBox1.Text = "سامر سلو" Then
MsgBox("يا مرحباً")
Else
'no
End If
End Sub
إن تغيير اسم المستخد يتطلب تغير النص في الصندوق أي الكتابة فيه فيمكننا مراقبة المدخلات عبر
Text Changed و نحصل على نفس النتيجة السابقة لكن بدون استخدام المؤقت
هذا ما أحببت أن أنوه إليه أننا نستخدم الأداة عند لزومها فقط وفي حالة استخدمناها فبالشكل الأمثل





اغتنم أكوادك - RaggiTech - 02-10-12

5. التنقل بين النماذج:
عندما تنتقل من نموذج إلى أخر تستخدم x.show الآن إخفاء نموذج معين لماذا؟


كود :
Me.Hide()
لا أويد هذا الاجراء الا لوقت قصير فقط وإلا فالاولى

كود :
Me.Close()
تخيل معي هذا النموذج البسيط




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

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

كود :
Form2.Show()
Me.Close()
وبذلك نضمن اغلاق البرنامج أو أي جزء منه والتخلص من عبئه على الموارد


اغتنم أكوادك - RaggiTech - 02-10-12


6.
الاتصال بتابع أو إجراء معين:

هذه العملية تستخدم كتسهيل للتعامل مع الكود والتعديل عليه تخيل معي النموذج التالي:


سوف نستخدم كود مشابه للتالي:

كود :
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

If TextBox1.Text = "5055050" Then

MsgBox("صح")

Else

MsgBox("خطأ")

End If

End Sub



Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click

If TextBox2.Text = "العراق" Then

MsgBox("صح")

Else

MsgBox("خطأ")

End If

End Sub



Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click

If TextBox3.Text = "الاخضر" Then

MsgBox("صح")

Else

MsgBox("خطأ")

End If

End Sub
فالنتيجة إما صح أو خطأ ولكن أريد تغيير النتيجة إلى yes or no

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

كود :
Private Sub yyy()

MsgBox("صح")



End Sub

Private Sub xxx()

MsgBox("خطأ")

End Sub



Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

If TextBox1.Text = "5055050" Then

yyy()

Else

xxx()

End If

End Sub



Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click

If TextBox2.Text = "العراق" Then

yyy()

Else

xxx()

End If

End Sub



Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click

If TextBox3.Text = "الاخضر" Then

yyy()

Else

xxx()

End If

End Sub
الان لو اردنا تعديل الجمل فسنذهب للاجراء ونعدل فيه فقط وكذا الامر لاي اداة

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


اغتنم أكوادك - RaggiTech - 02-10-12


7. التعامل مع الأخطاء:

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

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

فمن الأفضل تجاوز هذه الصورة وإخراجها بمظهر أجمل باستخدام Try


الآن بعد أن اتضحت لنا فكرة معالجة الأخطاء و الاستثناءات سنقوم بعمل برنامج صغير كالتالي :

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


كود :
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

PictureBox1.Image = System.Drawing.Bitmap.FromFile("D:\selverligt.bmp")

End Sub
الآن بفرض عدم وجود الصورة فعند الضغط على الزر ستكون النتيجة التالية:


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

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

أولا نتابع بالشكل الاعتيادي للخطأ

بعد استخدام Try سيصبح الكود كالتالي :

كود :
Try

PictureBox1.Image = System.Drawing.Bitmap.FromFile("D:\File.bmp")

Catch

MsgBox("لقد حصل خطأ الرجاء الاتصال بالاخ سيلفر لايت")

End Try
فالناتج الجديد للخطأ سيكون التالي :


لاحظ الفرق بين الرسالتين



الآن سنجري استثناء غير معالج بالطريقة التالية سنقوم بإضافة Module و بعدها نضيف فيه التصريح التالي

كود :
Public Sub UnhandledExceptionHandler()

'Show an error message to the user.

MsgBox("An error occurred. Error Number: " & Err.Number & _

" Description: " & Err.Description & " Source: " & Err.Source)

End Sub
ونعد للنموزج ونغير catch ليصبح الاتصال بالتصريح عند أي خطأ ويصبح الكود كالتالي:

كود :
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

Try

PictureBox1.Image = System.Drawing.Bitmap.FromFile("D:\File.bmp")

Catch

UnhandledExceptionHandler()

End Try

End Sub
جرب البرنامج وستظهر رسالة الخطأ التالية :

تحوي النافذة على رقم الخطأ و وصف الخطأ ومصدر الخطأ

وهذا يسهل لك معالجة أخطاء برنامجك

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

نقوم بإنشاء مشروع جديد نحتاج فيه لقائمة ListBox و زر أمر Button ونضع الكود التالي لزر الأمر:

كود :
Dim s As Integer

For s = 1 To 1000

ListBox1.Items.Add(ErrorToString(s).ToString + s.ToString)

Next

نقوم بتشغيل البرنامج ونضغط على الزر لنجد أن القائمة امتلأت من الرقم 1 إلى 1000 وبجانب كل رقم شرح الخطأ نذهب للرقم 53 لنتعرف عليه

سنجد أن الشرح هو أن الملف غير موجود



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