أسس البرمجة بلغة VB.NET

Page 1

‫أسس البرمجة بلغة ‪VB.NET‬‬

‫‪Basics of VB.NET‬‬

‫تأليف األستاذ خليل أبو شنب‬ ‫جديدة‪-‬المكر ‪2015‬‬ ‫‪abushanab_khalil@yahoo.com‬‬

‫‪1‬‬


‫الفهرس‬ ‫مقدمة ‪4..................................................................................................................‬‬ ‫البرمجة بتسويق األحداث ‪6..........................................................................................‬‬ ‫األدوات ‪8................................................................................................ Controls‬‬ ‫األداة ‪9...................................................................................................... Form‬‬ ‫األداة ‪17 .............................................................................................. TextBox‬‬ ‫األداة ‪19 ...................................................................................................Label‬‬ ‫األداة ‪20 ................................................................................................. Button‬‬ ‫قواعد لغة البرمجة ‪21 ............................................................................... VB.NET‬‬ ‫تعريف المتغيرات ‪21 .............................................................................................‬‬ ‫العمليات الحسابية ‪23 .............................................................................................‬‬ ‫عمليات المقارنة المنطقية ‪23 ....................................................................................‬‬ ‫عمليات الربط المنطقية ‪24 .......................................................................................‬‬ ‫األمر ‪24 ......................................................................................................... If‬‬ ‫حلقة ‪25 ....................................................................................................... For‬‬ ‫حلقة ‪26 ................................................................................................... While‬‬ ‫المصفوفات األحادية ‪26 ..........................................................................................‬‬ ‫المصفوفات الثنائية ‪28 ............................................................................................‬‬ ‫اإلجراءات ‪29 ......................................................................................................‬‬ ‫الدوال ‪30 ...........................................................................................................‬‬ ‫الفئات‪31 ............................................................................................................‬‬ ‫البواني ‪32 ..........................................................................................................‬‬ ‫الخصائص ‪33 .................................................................................... Properties‬‬ ‫معالجات األحداث ‪34 .................................................................................................‬‬ ‫عمليات التأكد من صحة االدخال أو المعلومات ‪41 .............................................................‬‬ ‫تمارين ‪44 ..............................................................................................................‬‬ ‫األداة ‪51 ............................................................................................. ComboBox‬‬ ‫األداة ‪57 ..................................................................................... DateTimePicker‬‬ ‫تمارين ‪64 ..............................................................................................................‬‬ ‫األداة ‪65 ............................................................................................. PictureBox‬‬ ‫األداة ‪68 .................................................................................................. ListBox‬‬ ‫األدوات ‪ RadioButton‬و ‪76 .................................................................. CheckBox‬‬ ‫العملية ‪85 .............................................................................. MessageBox.Show‬‬ ‫األداة ‪91 ................................................................................................ ListView‬‬ ‫‪97 ......................................................................................... MDI Applications‬‬ ‫األداة ‪97 ...........................................................................................MenuStrip‬‬ ‫تمارين ‪104 ............................................................................................................‬‬ ‫‪2‬‬


‫االستثناءات ‪107 ......................................................................................................‬‬ ‫‪112 ............................................................................................................ SQL‬‬ ‫األمر ‪118 ........................................................................................... SELECT‬‬ ‫تحديد وترتيب النتائج ‪123 .......................................................................................‬‬ ‫ترتيب النتائج ‪130 .................................................................................................‬‬ ‫استخراج معلومات من أكثر من جدول ‪131 ..................................................................‬‬ ‫األمر ‪145 ................................................................................ SELECT INTO‬‬ ‫اإلدخال‪149 ........................................................................................................‬‬ ‫التحديث ‪152 .......................................................................................................‬‬ ‫الحذف ‪154 .........................................................................................................‬‬ ‫الدوال ‪156 .........................................................................................................‬‬ ‫إنشاء مجموعات في جدول النتيجة ‪161 .......................................................................‬‬ ‫‪164 .................................................................................................. ADO.NET‬‬ ‫‪174 ............................................................................... 3-Levels Architecture‬‬ ‫‪179 .............................................................................................. Data Controls‬‬ ‫األداة ‪207 .................................................................................. DataGridView‬‬ ‫تمارين‪228 .........................................................................................................‬‬ ‫األداة ‪239 ......................................................................................... TabControl‬‬ ‫الملفات ‪242 ...........................................................................................................‬‬ ‫األداة ‪252 ...................................................................................... RichTextBox‬‬ ‫تمارين ‪254 ............................................................................................................‬‬

‫‪3‬‬


‫مقدمة‬ ‫‪ VB.NET‬عبارة عن منظومة متقدمة جدا توفرها شركة مايكروسوفت لتطوير تطبيقات النوافذ‬ ‫)‪ .(Windows Applications‬هذه المنظومة تستند إلى البرمجة موجهة الكائنات ‪(Object‬‬ ‫)‪ Oriented Programming‬والبرمجة بتسويق األحداث )‪.(Events Driven Programming‬‬ ‫وتدعم ‪ VB.NET‬التواصل مع قواعد البيانات بأساليب مختلفة من خالل توفير إطار‬ ‫)‪ (Framework‬كامل من الفئات التي تُسهل عملية التواصل مع قواعد البيانات‪ .‬الكتاب يبدأ‬ ‫بالتعرف على األدوات األساسية وكيفية استعمالها‪ .‬ثم يشرح مبدأ البرمجة بتسويق األحداث من خالل‬ ‫أمثلة بسيطة تُعتبر مكونات أساسية في معظم التطبيقات‪ .‬بعدها نتعرف على كيفية انشاء تطبيقات‬ ‫متعددة النماذج )‪ (MDI Applications‬ونستعمل القوائم لتوفير امكانية للتنقل بين النماذج ال ُمتعددة‪.‬‬ ‫ثم نتعلم لغة ‪ SQL‬للتواصل مع قواعد البيانات العالئقية‪ .‬ثم نشرح تقنية ‪ ADO.NET‬التي توفر لنا‬ ‫مجموعة فئات للتعامل مع قواعد البيانات العالئقية من داخل تطبيق الـ ‪ VB.NET‬وفق المعمارية‬ ‫ثالثية الطبقات ‪ .(3 Levels Architecture‬ثم نتعرف على أهم األدوات التي تتخصص بعرض‬ ‫البيانات وتوفير إمكانيات سهلة لتحريرها وهي األداة ‪ .DataGridView‬وأخيرا نشرح بشكل ُمبسط‬ ‫كيفية التعامل مع الملفات النصيّة‪ .‬كل موضوع يم شرحه من خالل أمثلة عملية ومناسبة‪.‬‬ ‫يفترض الكتاب أن لدى القارئ معرفة تفصيلية ُمسبقة في المواضيع التالية‪:‬‬ ‫• أسس علم الحاسوب بلغة برمجة موجهة كائنات مثل لغة ‪ :C#‬أي أنه يفترض معرفة‬ ‫المواضيع التالية‬ ‫‪ o‬المبنى العام للبرنامج‬ ‫‪ o‬المتغيرات وأنماطها المختلفة مثل ‪int, float, double, char, string, bool‬‬ ‫‪ o‬أوامر الطباعة واالستقبال‬ ‫‪ o‬أمر ‪ if‬البسيط والمركب‬ ‫‪ o‬الحلقات ‪ while‬و ‪for‬‬ ‫‪ o‬العمليات الستاتية·‬ ‫‪ o‬المصفوفات أحادية وثنائية األبعاد·‬ ‫‪ o‬النصوص أي الفئة ‪ string‬وواجهتها‬ ‫• أسس البرمجة موجهة الكائنات‪ .‬أي أنه يفترض معرفة المواضيع التالية‬ ‫‪4‬‬


‫‪ o‬الفئات ‪Classes -‬‬ ‫‪ o‬الكائنات – ‪Objects‬‬ ‫‪ o‬المؤشرات ‪References -‬‬ ‫‪static o‬‬ ‫‪ o‬الوراثة ‪ Inheritance -‬وتعدد األشكال ‪Polymorphism -‬‬ ‫‪ o‬الواجهات ‪Interfaces -‬‬ ‫• أسس قواعد البيانات العالئقية – ‪ Relational Data Bases‬مثل ‪MS Access‬‬ ‫كلي أمل بأن يخدم هذا الكتاب كل من أراد معرفة أسس هذا المنهج المتميز من مناهج برمجة‬ ‫تطبيقات النوافذ‪.‬‬

‫‪5‬‬


‫البرمجة بتسويق األحداث‬ ‫‪Events-Driven Programming‬‬ ‫البرمجة بتسويق األحداث هي إحدى مناهج البرمجة )‪ (Programming Paradigms‬التي يكون‬ ‫فيها مجرى تنفيذ األوامر )‪ (Flow of the program‬خاضعا للترتيب الذي تحصل فيه أحداث‬ ‫معينة‪ .‬فالبرنامج الذي يكون مكتوبا وفق هذا المنهج يبقى بعد تشغيله في وضع االنتظار حيث ينتظر‬ ‫حصول أحداث معينة‪ .‬فإذا حصلت األحداث التي يتوقعها (أي التي ُكتبت دوال وإجراءات لمعالجتها)‬ ‫يقوم حينها بتنفيذ هذه الدوال واإلجراءات‪ .‬وال يمكن للبرنامج أن يتوقع ما الذي سيحدث في الخطوة‬ ‫التالية‪ ،‬لذا فإن البرنامج يقسم إلى عدة وظائف ينفذ كل منها عندما يحدث ما يسمى بالحدث‪.‬‬ ‫والمقصود باألحداث )‪ (Events‬عمليات الفارة المختلفة التي ينفذها المستخدم ‪(Mouse User's‬‬ ‫)‪ .Actions‬مثل‪ :‬الضغط مرة واحدة على الزر األيسر للفارة وهو ما يسمى ‪(Left Click‬‬ ‫)‪ Event‬أو الضغط مرتين متتاليتين على الزر األيسر للفارة وهو ما يسمى ‪.(Left Double‬‬ ‫)‪ .Click Event‬أو الضغط على الزر األيمن للفارة وهو ما يسمى )‪(Right Click Event‬‬ ‫وغيرها‪.‬‬ ‫الضغط على أي زر من أزرار لوحة المفاتيح يُعتبر حدثا‪ .‬مثل‪ KeyDown Event :‬و ‪KeyUp‬‬ ‫‪ Event‬وغيرها‬ ‫المجسات )‪ (Sensors‬المختلفة التي تكون متصلة مع الحاسوب‪ .‬هذه المجسات تبلغ الحاسوب ( أي‬ ‫البرنامج المسئول عن معالجة المعلومات الواصلة من المجسات) من خالل إحداث حدث معين متفق‬ ‫عليه‪ .‬هذه العملية تسمى )‪(Firing an Event‬‬ ‫الرسائل )‪ (Messages‬التي ترسلها البرامج المختلفة للتواصل فيما بينها بهدف تبادل المعلومات‪.‬‬ ‫مثال‪ :‬البرامج التي تشغل األفالم ترسل عند نهاية عرض فلم ما رسالة أو حدثا يبلغ المعنيين باألمر‬ ‫أن عرض الفلم قد انتهى‪ .‬في هذه الحالة تقوم البرامج المعنية بمعالجة هذا الحدث ‪(Event‬‬ ‫)‪ Handling‬ومثال تشغيل فلم آخر أو مقطع دعاية وما إلى ذلك‪.‬‬ ‫يُعتبر هذا المنهج البرمجي مرتبطا ارتباطا حتميا مع البرمجة المرئية )‪.(Visual Programming‬‬ ‫في البرمجة المرئية تكون البرامج أو ما يسمى بالتطبيقات )‪ (Applications‬عبارة عن نافذة‬

‫‪6‬‬


‫رئيسية تظهر فيها عادة القائمة الرئيسية التي تحتوي على العمليات الرئيسة التي يوفرها البرنامج‪.‬‬ ‫وعادة ما تظهر أيضا نوافذ الحوار المختلفة التي تحتوي على ما يسمى باألدوات ‪(Tools,‬‬ ‫)‪ Controls‬مثل األزرار وصناديق النصوص والقوائم المنسدلة وما شابهها‪ .‬مثال على هذا النوع‬ ‫من التطبيقات جميع برامج أوفس )‪ (MS Office Applications‬مثل ‪MS Word, MS‬‬ ‫‪ .Excel, MS PowerPoint‬أيضا مواقع االنترنت الديناميكية أي التي تحتوي على نماذج‬ ‫)‪ (Forms‬وأدوات تعتبر أمثلة على برامج مرئية )‪ .(Visual Programs‬تُسمى هذه النوافذ أيضا‬ ‫واجهة المستخدم الرسومية )‪ .(GUI = Graphical User Interface‬ولذلك يُستعمل أحيانا‬ ‫المصطلح ‪ GUI Programming‬بدال من المصطلح ‪.Visual Programming‬‬

‫مراحل برمجة تطبيقات النوافذ‬ ‫• مرحلة التصميم )‪ (Design Phase‬حيث يتم تصميم النماذج المكونة للتطبيق‪.‬‬ ‫• مرحلة كتابة معالجات األحداث )‪ (Events Handler Programming Phase‬وتسمى‬ ‫أيضا ‪ Coding Phase‬أي مرحلة البرمجة‪.‬‬ ‫مهمة مرحلة التصميم تصميم النماذج المختلفة واألدوات التابعة لها‪ .‬لذلك سنبدأ شرحنا بالحديث عن‬ ‫هذه األدوات‪.‬‬

‫‪7‬‬


‫األدوات ‪Controls‬‬ ‫تُعتبر األدوات المكونات األساسية للنماذج‪ .‬فاذا ألقينا نظرة على أي نموذج‪ ،‬نجده مكونا من عدة‬ ‫أنواع من األدوات‪ .‬تُقسم ‪ VB.NET‬األدوات من الناحية الوظيفية الى عدة أقسام نجدها في الـ‬ ‫‪ Toolbox‬وهي‪:‬‬

‫نذكر هنا بعضها‪:‬‬ ‫المجموعة‬ ‫‪Common‬‬

‫أمثلة‬

‫الشرح‬

‫… ‪TextBox, Label, Button,‬‬

‫األدوات األساسية‬

‫‪Controls‬‬ ‫‪Containers‬‬

‫أدوات لتجميع أو احتواء أدوات أخرى‬

‫& ‪Menus‬‬

‫القوائم الرئيسية وأشرطة األدوات‬

‫… ‪GroupBox, Panel, TabControl,‬‬

‫… ‪MenuStrip, ToolStrip,‬‬

‫‪Toolbars‬‬ ‫‪Data‬‬

‫… ‪DataGridView,‬‬

‫األدوات المتخصصة بعرض‬ ‫المعلومات على شكل جداول‬

‫‪Dialogs‬‬

‫نوافذ حوار مختلفة‪ :‬لفتح الملفات‬

‫‪ColorDialog, OpenFileDialog,‬‬ ‫… ‪SaveFileDialog,‬‬

‫والختيار ألوان ‪...‬‬

‫‪8‬‬


‫‪Reporting‬‬

‫أدوات تدعم انتاج تقارير عن البيانات‬

‫‪ReportViewer‬‬

‫المختلفة‪.‬‬ ‫في هذا الفصل سوف نشرح بعضا من هذه األدوات وهي األكثر شيوعًا واستعماال في النماذج‪ .‬لكن‬ ‫قبل أن نبدأ بالتفاصيل ال بد من التنويه الى أن األدوات عبارة عن كائنات أي ‪ Objects‬المعروفة لنا‬ ‫من البرمجة موجهة الكائنات )‪ .(Object Oriented Programming‬هناك كانت للكائنات‬ ‫مجموعة من الخصائص والبواني والعمليات‪ .‬هنا تُضاف إليهم مجموعة من األحداث (أي ‪)Events‬‬ ‫تضيف الى الكائن جانبا تفاعليًا مع ال ُمستخدم وتمكنهم من معرفة ما يطلبه المستخدم وتلبية هذه‬ ‫الطلبات‪ .‬أسهل طريقة إلضافة األداة الى النموذج تكون عن طريق سحبها من الـ ‪Toolbox‬‬ ‫ووضعها في المكان المناسب في النموذج‪ .‬بعد ذلك بإمكاننا اعطاء القيم المناسبة للخصائص التي‬ ‫نريد وكتابة معالجات لألحداث التي تهمنا‪ .‬تظهر نافذة الخصائص التابعة لألداة من خالل الضغط‬ ‫على الزر األيمن للفارة وهي موضوعة على األداة واختيار العنصر ‪ Properties‬منها وذلك في‬ ‫عرض الـ ‪ Design‬للنموذج‪ .‬نبين ذلك بالنسبة لألدوات التالية‪:‬‬

‫األداة ‪Form‬‬ ‫تتكون تطبيقات النوافذ على األقل من نموذج واحد‪ .‬أي من أداة من نوع ‪ .Form‬هذه األداة معروفة لنا من خالل‬ ‫تعاملنا شبه اليومي مع تطبيقات النوافذ المختلفة‪ .‬فاذا قمنا بإنشاء مشروع جديد من نوع ‪Windows Forms‬‬ ‫‪ Application‬نحصل على مشروع فيه نموذج واحد يُعتبر النموذج الرئيسي‪ .‬أي الذي يظهر مباشرة عند تشغيل‬ ‫التطبيق‪:‬‬

‫‪9‬‬


‫كما قلنا فان لكل أداة مجموعة من الخصائص واألحداث الخاصة بها‪ .‬تظهر نافذة الخصائص التابعة‬ ‫لألداة من خالل الضغط على الزر األيمن للفارة وهي موضوعة على األداة واختيار العنصر‬ ‫‪ Properties‬منها وذلك في عرض الـ ‪ Design‬للنموذج‬

‫بعد اختيار العنصر ‪ Properties‬تظهر نافذة الخصائص التالية‪:‬‬

‫نجد في هذه النافذة عددا كبيرا من الخصائص سنتعرف خالل أمثلة الكتاب على معظمها‪ .‬لكن يهمنا‬ ‫هنا اثنتان‪ Name :‬و ‪ .Text‬أما ‪ Name‬فهو اسم النموذج أي اسم الكائن‪ .‬وهو عبارة عن نص يميز‬ ‫األداة ويجب أن تتوفر فيه الشروط التي يجب أن تتوفر في كل ال ُمعرّفات )‪ (Identifiers‬وهي‪:‬‬ ‫‪10‬‬


‫• ال يجوز أن يبدأ برقم‬ ‫• ال يجوز أن يحتوي على فراغات‬ ‫• ال يجوز أن يحتوي على رموز محجوزة مثل … ‪+,-, /, %, ;,‬‬ ‫• ال يجوز أن يكون اس ًما محجو ًزا مثل … ‪class, for, while,‬‬ ‫من ال ُمفضل اعطاء الكائن اس ًما معبرًا عن وظيفتة وجعل االسم يبدأ بنوع الكائن‪ .‬مثل ‪FormMain‬‬ ‫‪:Text‬‬ ‫وظيفة هذه الخا ّ‬ ‫صة‪ ،‬اعطاء عنوان للنموذج يظهر في أعلى النموذج‪ .‬مسموح للعنوان أن يكون بأي لغة نريد‪ .‬هنا‬ ‫أعطيت النموذج العنوان ‪My First Windows Form‬‬

‫‪:BackColor‬‬ ‫وظيفة هذه الخاصّ ة‪ ،‬تحديد لون خلفية النموذج‪ .‬يتم اختيار اللون من القائمة التي تظهر عند النقر على القائمة ال ُمنسدلة‬ ‫التي تظهر الى يمين اسم الخاصية في نافذة الخصائص‪:‬‬

‫‪11‬‬


‫الصورة التالية تظهر النموذج بعد تغيير لون الخلفية‪:‬‬

‫‪12‬‬


‫منظومة الملفات‬ ‫يُحفظ كل نموذج من النماذج المكونة للتطبيق في ‪ 3‬ملفات‪:‬‬ ‫• ملف للتنسيق أي لمبنى النموذج ‪FormName.Designer.vb‬‬ ‫• وملف للبرمجة ‪FormName.vb‬‬ ‫• وملف للمصادر‪. FormName.res‬‬ ‫‪ FormName‬هنا هو اسم النموذج كما تم تحديده من قبل المبرمج‪.‬‬ ‫يمكننا رؤية اسم الملف في النافذة ‪ Solution Explorer‬التي نفتحها من خالل النقر على األمر‬ ‫‪ Solution Explorer‬في القائمة ‪ View‬التي تظهر ضمن القائمة الرئيسية‪:‬‬

‫‪13‬‬


14


‫أما الملفات نفسها فيمكننا رؤيتها في المجلد الذي يحوي المشروع‪.‬‬ ‫تم تخزين المشروع كالتالي‬

‫داخل هذا المجلد يوجد مجلد آخر وملف الحل وهو يحمل اسم المشروع هنا‬ ‫‪ VB.NET_Book_Samples‬والملحق ‪ sln‬ليصبح االسم الكامل‬

‫‪15‬‬


‫‪ .VB.NET_Book_Samples.sln‬النقر على هذا الملف نقرة ‪ Double Click‬بواسطة الزر‬ ‫األيسر للفارة يؤدي الى فتح المشروع بواسطة ‪Visual Studio‬‬

‫إذا فتحنا المجلد ‪ VB.NET_Book_Samples‬نرى المحتويات التالية‬

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

‫‪16‬‬


‫اسم المجلد أو الملف‬ ‫‪bin‬‬ ‫‪My Project‬‬ ‫‪obj‬‬

‫‪App.config‬‬ ‫‪FormMain.Designer.vb‬‬ ‫‪FormMain.res‬‬

‫‪FormMain.vb‬‬ ‫‪VB.NET_Book_Samples.vbproj‬‬

‫الشرح‬ ‫في هذا المجلد يتم حفظ ملفات التشغيل أي الـ ‪Exe Files‬‬ ‫في هذا المجلد يتم حفظ ملفات متعلقة بالتنسيقات العامة للمشروع أي‬ ‫‪Configuration information about the project‬‬ ‫في هذا المجلد يتم حفظ ملفات متعلقة بنسخة المشروع‪ 32 :‬أو ‪64‬‬ ‫‪bit‬‬ ‫في هذا المجلد يتم حفظ معلومات متعلقة بالتنسيقات العامة للمشروع‬ ‫هذا هو ملف التنسيق التابع للنموذج ‪FormMain‬‬ ‫هذا هو ملف المصادر التابعة للنموذج ‪ .FormMain‬والمقصود‬ ‫بالمصادر‪ :‬الصور واأليقونات والنصوص وكذلك ملفات الصوت‬ ‫والفيديو أو أي نوع آخر من الملفات‪.‬‬ ‫في هذا المجلد يتم حفظ الكود مثل معالجات األحداث والفئات وما الى‬ ‫ذلك‪.‬‬ ‫في هذا المجلد يتم أيضا حفظ معلومات متعلقة بالتنسيقات العامة‬ ‫للمشروع‬

‫األداة ‪TextBox‬‬ ‫وتُسمى أيضا "صندوق نص" تُمكن المستخدم من ادخال األنواع األساسية من المعلومات مثل‬ ‫األعداد والنصوص‪.‬‬ ‫بعد اختيار العنصر ‪ Properties‬تظهر نافذة الخصائص التالية‪:‬‬

‫‪17‬‬


‫ال بد من مالحظة أن محتوى نافذة الخصائص تتغير بتغير األداة التي تم اختيارها وتحديدها‬ ‫ضا بأن معظم الخصائص ُمشتركة لمعظم األدوات أي أنها متوفرة بنفس األسماء عند‬ ‫بالنموذج‪ .‬وأي ً‬ ‫معظم األدوات‪ .‬بالنسبة لألداة ‪ TextBox‬فان أهم خاصيتين حاليًا هما‪:‬‬ ‫‪Name‬‬ ‫اسم األداة‪ .‬وهي عبارة عن نص يميز األداة يجب أن تتوفر فيه الشروط التي يجب أن تتوفر في كل‬ ‫ال ُمعرّفات )‪ (Identifiers‬التي ُذكرت أعاله‪ .‬هنا أعطيت األداة االسم ‪TextBoxXValue‬‬ ‫‪Text‬‬ ‫وظيفة هذه الخاصّة‪ ،‬حفظ القيمة الموجودة في األداة‪ .‬وهي قابلة للقراءة والكتابة‪.‬‬ ‫• القراءة تعني أننا نستطيع الحصول على القيمة الموجودة في األداة‪.‬‬ ‫مثال‬ ‫‪XValue = TextBoxXValue.Text‬‬ ‫• والمقصود بالكتابة أي أننا نستطيع وضع قيمة في األداة‪.‬‬ ‫مثال‬ ‫"‪TextBoxXValue.Text = "100‬‬ ‫الجدول التالي يُلخص بعض الخصائص االضافية لألداة ‪:TextBox‬‬ ‫الخاصيّة‬ ‫‪Visible‬‬

‫الشرح‬ ‫‪ :true‬إلظهار األداة‬ ‫‪ :false‬إلخفائها‬

‫‪Enabled‬‬

‫‪ :true‬يمكن للمستخدم أن يغير محتوى األداة‬ ‫‪ :false‬ال يمكن للمستخدم أن يغير محتوى األداة‬ ‫يمكن الحصول على نفس النتيجة من خالل الخاصيّة ‪ReadOnly‬‬

‫‪Width‬‬

‫عرض األداة‬

‫‪Height‬‬

‫ارتفاع األداة‬

‫‪ MaxLength‬العدد األكبر للرموز التي يُمكن ادخالها‬ ‫‪ForeColor‬‬ ‫‪Font‬‬

‫لون النص أي المحتوى‬ ‫اسم الخط‬

‫‪18‬‬


‫الحظ أن معظم هذه الخصائص متوفرة عند معظم األدوات‪ .‬سيتم شرح باقي الخصائص الحقًا ألنها‬ ‫تتطلب معرفة اضافية‪.‬‬

‫األداة ‪Label‬‬ ‫تُمكننا هذه األداة من اظهار معلومات للمستخدم للقراءة فقط وتُستخدم إلظهار عناوين ألدوات أخرى‬ ‫أو إلظهار رسائل معينة لل ُمستخدم‪ .‬مثال بإمكاننا وضع النص ‪ Please enter Value of X‬الذي‬ ‫يظهر في المثال السابق الى يسار صندوق النص ‪:TextBoxXValue‬‬ ‫الصورة التالية تُظهر مجموعة الخصائص التابعة لألداة ‪ Label‬ويمكننا مالحظة ما قيل سابقًا من أن‬ ‫معظم الخصائص التي تم شرحها سابقًا متوفرة عند هذه األداة‪:‬‬

‫‪19‬‬


‫األداة ‪Button‬‬ ‫وتُسمى أيضًا ‪ Command Button‬بمعنى زر أمر أي أنها تُستعمل لتوفير امكانية لل ُمستخدم‬ ‫لطلب تنفيذ أوامر مثل‪ .Login, Open, Close, Cancel, Add, Calculate,… :‬الحظ أن‬ ‫جميع هذه الكلمات مكتوبة بصيغة األمر‪.‬‬ ‫نضيف هذه األداة الى مثالنا ليصبح كالتالي‪:‬‬

‫واآلن سننتقل الى الجزء الثاني مما تملكه هذه األدوات وهي مجموعة األحداث‪ .‬لكن قبلها سنتحدث‬ ‫عن قواعد لغة البرمجة ‪ VB.NET‬ومن ثم البرمجة بتسويق األحداث‪.‬‬

‫‪20‬‬


VB.NET ‫قواعد لغة البرمجة‬ :VB.NET ‫الجدول التالي يلخص األنواع األساسية التي توفرها لغة‬ ‫المجال‬ Min

‫النوع‬

Max

True, False 0

Boolean 255

Byte

UTF-16 character codes from 0 to 65,535

Char

1/1/0001, 12:00:00 A.M.

31/12/9999, 11:59:59 P.M.

Date

-7.9228 x 10^28

7.9228 x 10^28

Decimal

-1.80 x 10^308

1.80 x 10^308

Double

–2,147,483,648

2,147,483,647

Integer

-9,223,372,036,854,775,808 9,223,372,036,854,775,807

Long

–128

127

SByte

–32,768

32,767

Short

–3.402823538

3.402823538

Single

Unicode characters 0 ≥ Len ≥ 2 31 ‫قادر على تخزين نص بطول‬

String

0

4,294,967,295

UInteger

0

18,446,744,073,709,551,615

ULong

0

65,535

UShort

‫تعريف المتغيرات‬ ‫القاعدة العامة لتعريف المتغيرات‬ Dim VariableName As DataType = InitialValue

21


‫• ‪ :Dim‬كلمة محجوزة يجب أن يبدأ فيها أمر التعريف‪ .‬وظيفة هذا األمر تعريف وحجز‬ ‫ذاكرة لمتغير واحد أو لمجموعة من المتغيرات من نوع واحد معين‪.‬‬ ‫• ‪ :VariableName‬اسم المتغير – يجب أن يحقق الشروط التي ُذكرت آنفا‬ ‫• ‪ :As‬كلمة محجوزة تأتي قبل النوع مباشرة‬ ‫• ‪ :DataType‬النوع‬ ‫• ‪ :InitialValue‬قيمة أولية للمتغير‬ ‫اعطاء القيمة األولية ليس ملزما وانما هو اختياري‪.‬‬

‫أمثلة‬ ‫األمر‬

‫الشرح‬ ‫تم تعريف متغير باسم ‪ X‬من نوع عدد صحيح أي ‪Integer‬‬ ‫تم تعريف متغير باسم ‪ f‬من نوع عدد حقيقي أي ‪float‬‬

‫‪Dim X As Integer‬‬ ‫‪Dim f As Single‬‬

‫تم تعريف متغير باسم ‪ Counter‬من نوع عدد صحيح واعطاؤه القيمة األولية‬

‫‪Dim Counter As Integer = 0‬‬

‫‪0‬‬ ‫يمكننا تعريف أكثر من متغير من نفس النوع في أمر واحد‬

‫‪Dim x, y, z As Integer‬‬

‫مالحظة‪ :‬لغة ‪ VB.NET‬ليست حساسة لحالة الحرف‪ .‬فال فرق عندها بين متغير اسمه ‪ X‬وآخر‬ ‫اسمه ‪.x‬‬

‫‪22‬‬


‫العمليات الحسابية‬ ‫العملية‬

‫الشرح‬ ‫الجمع‬

‫‪+‬‬

‫الطرح‬

‫‪-‬‬

‫الضرب‬

‫*‬

‫قسمة مع باق‬

‫‪/‬‬

‫قسمة بدون باق أي ‪ .Div‬العملية تعمل فقط مع األنواع الرقمية‪:‬‬

‫\‬

‫‪Byte, Short, Integer, Long‬‬ ‫باقي القسمة‪ .‬العملية تعمل فقط مع األنواع الرقمية‪:‬‬

‫‪Mod‬‬

‫‪Byte, Short, Integer, Long‬‬ ‫القوة‪.‬‬ ‫أمثلة‬

‫^‬ ‫‪Dim a As Integer = 2‬‬ ‫‪Dim n As Integer = 3‬‬ ‫‪Dim Res As Double‬‬ ‫‪Res = a^n‬‬

‫النتيجة تكون دائما من نوع ‪ .Double‬هنا قيمة ‪ Res‬تكون ‪8.0‬‬

‫عمليات المقارنة المنطقية‬ ‫العملية‬

‫الشرح‬ ‫هل أكبر؟‬

‫>‬

‫هل أكبر أو يساوي؟‬ ‫هل أصغر؟‬

‫=>‬ ‫<‬

‫هل أصغر أو يساوي؟‬ ‫هل يساوي؟‬

‫=<‬ ‫=‬

‫هل ال يساوي؟‬

‫><‬

‫الحظ أن عملية حفظ قيمة ما في متغير هي أيضا العملية =‬

‫‪23‬‬


‫عمليات الربط المنطقية‬ ‫العملية‬

‫الشرح‬ ‫وأيضا‬

And Or

True ‫ يكفي أن يكون أحد الطرفين‬:‫أو‬

Not

‫النفي‬

Xor

True ‫ فقط إذا كان أحد الطرفين‬:‫أو‬

If ‫األمر‬ ‫المبنى العام‬ If Expression Then Statements End If .False ‫ واما‬True ‫ تعبير منطقي قيمته النهائية اما‬:Espression True ‫ مجموعة أوامر يجب أن تُنفذ اذا كانت قيمة التعبير‬:Statements Else ‫ مع‬If ‫أمر‬ If Expression Then Statements Else Statements End If ElseIf ‫ مع‬If ‫أمر‬ If Expression Then Statements ElseIf Expression Then Statements ElseIf Expression Then Statements Else Statements End If

24


‫الحلقات‬ ‫حلقة ‪For‬‬ ‫المبنى العام‬ ‫‪For VariableName = Expression To Expression‬‬ ‫‪Statements‬‬ ‫‪Next‬‬ ‫الحظ أن ‪ To‬تشمل القيمة التي تأتي بعدها‪.‬‬ ‫هكذا يتم رفع عداد الحلقة بعد كل دورة فقط بواحد‬ ‫أما إذا أردنا رفع عداد الحلقة بعد كل دورة بأية قيمة نريد نكتب القيمة بعد الكلمة ‪:Step‬‬ ‫‪For VariableName = Expression To Expression Step Expression‬‬ ‫‪Statements‬‬ ‫‪Next‬‬ ‫مثال‬ ‫المقطع التالي يجمع األعداد الزوجية من ‪ 0‬ولغاية ‪:100‬‬ ‫‪Dim i As Integer‬‬ ‫‪Dim Sum As Integer = 0‬‬ ‫‪For i = 0 To 100 Step 2‬‬ ‫‪Sum += i‬‬ ‫‪Next‬‬ ‫ممكن الخروج من الحلقة مبكرا عن طريق األمر ‪.Exit For‬‬ ‫طبعا لدينا أيضا امكانية لكتابة حلقات متداخلة‪:‬‬ ‫‪Dim i, j, k As Integer = 0‬‬ ‫‪For i = 1 To 10‬‬ ‫‪For j = 1 To 10‬‬ ‫‪For k = 1 To 10‬‬ ‫‪' ...‬‬ ‫‪Next‬‬ ‫‪Next‬‬ ‫‪Next‬‬

‫‪25‬‬


‫حلقة ‪While‬‬ ‫المبنى العام‬ ‫‪While Expression‬‬ ‫‪Statements‬‬ ‫‪End While‬‬ ‫‪ :Expression‬تعبير منطقي يمثل شرط الحلقة‪.‬‬ ‫مثال‬ ‫المقطع التالي يجمع منازل العدد الصحيح ‪Num‬‬ ‫‪Dim Num As Integer = 36259‬‬ ‫‪Dim Sum As Integer = 0‬‬ ‫‪While Num <> 0‬‬ ‫‪Sum += Num Mod 10‬‬ ‫‪Num = Num \ 10‬‬ ‫‪End While‬‬ ‫ممكن الخروج من الحلقة مبكرا عن طريق األمر ‪.Exit While‬‬ ‫طبعا لدينا أيضا امكانية لكتابة حلقات ‪ While‬متداخلة كما سيأتي الحقا في األمثلة‪.‬‬

‫المصفوفات األحادية‬ ‫تعرف مصفوفة أحادية‬ ‫‪Dim ArrayName(ArrayLength-1) As Type‬‬ ‫مثال‬ ‫األمر التالي يُعرف مصفوفة أحادية ألعداد صحيحة باسم ‪ A‬وبطول ‪5‬‬ ‫‪Dim A(4) As Integer‬‬ ‫أي أن ‪ 4‬هي رقم الخلية األخيرة في المصفوفة‪ .‬أرقام الخاليا هي‪:‬‬ ‫‪0, 1, 2, 3, 4‬‬ ‫يمكننا ادخال قيم أولية الى المصفوفة وقت تعريفها‪:‬‬ ‫مثال‬ ‫}"‪Dim A( ) As String = {"First", "Second", "Third", "Fourth", "Fifth‬‬

‫‪26‬‬


‫الوصول الى الخاليا يكون وفق القاعدة التالية‪:‬‬ ‫)‪ArrayName(CellIndex‬‬ ‫مثال‬ ‫المقطع التالي يحفظ قيمة الخلية رقم ‪ 2‬التابعة لمصفوفة النصوص ‪ A‬في المتغير ‪Str‬‬ ‫‪Dim Str As String‬‬ ‫)‪Str = A(2‬‬ ‫المقطع التالي يجد أكبر قيمة في المصفوفة ‪:Arr‬‬

‫}‪Dim Arr() As Integer = {2, -1, 0, 10, 1, 8‬‬ ‫‪Dim i As Integer‬‬ ‫)‪Dim MaxValue As Integer = Arr(0‬‬ ‫‪For i = 1 To Arr.Length - 1‬‬ ‫‪If MaxValue < Arr(i) Then‬‬ ‫)‪MaxValue = Arr(i‬‬ ‫‪End If‬‬ ‫‪Next‬‬ ‫الحظ أن طول المصفوفة موجود في الخاصية ‪.Length‬‬ ‫بإمكاننا أيضا انشاء مصفوفات حجمها يُعرف خالل زمن التشغيل‪ .‬االنشاء يتم بواسطة األمر ‪.New‬‬ ‫المقطع التالي مثال يقوم بإنشاء مصفوفة أحادية بحجم ‪ 5‬وادخال قيم اليها‪:‬‬ ‫‪Dim Size As Integer = 5‬‬ ‫‪Dim B() As Integer‬‬ ‫}{ )‪B = New Integer(Size-1‬‬ ‫‪B(0) = 2‬‬ ‫‪B(1) = 4‬‬ ‫‪B(2) = 6‬‬ ‫‪B(4) = 8‬‬

‫‪27‬‬


‫المصفوفات الثنائية‬ ‫تعريف مصفوفة ثنائية‬ ‫‪Dim ArrayName(NumRows-1,NumCols-1) As Type‬‬ ‫مثال‬ ‫األمر التالي يُعرف مصفوفة ثنائية ألعداد صحيحة باسم ‪ M‬وبطول ‪5X5‬‬ ‫‪Dim M(4,4) As Integer‬‬ ‫يمكننا ادخال قيم أولية الى المصفوفة وقت تعريفها‪ .‬المقطع التالي يُعرف ويعبئ مصفوفة ثنائية بحجم‬ ‫‪3X2‬‬ ‫}}‪Dim Matrix(,) As Integer = {{1, 2}, {3, 4}, {5, 6‬‬ ‫امكانية أخرى‬ ‫‪Dim Matrix(2,1) As Integer‬‬ ‫‪Matrix(0, 0) = 1‬‬ ‫‪Matrix(0, 1) = 2‬‬ ‫‪Matrix(1, 0) = 3‬‬ ‫‪Matrix(1, 1) = 4‬‬ ‫‪Matrix(2, 0) = 5‬‬ ‫‪Matrix(2, 1) = 6‬‬ ‫المقطع التالي يجمع قيم المصفوفة الثنائية ‪:Matrix‬‬

‫}}‪Dim Matrix(,) As Integer = {{1, 2}, {3, 4}, {5, 6‬‬ ‫‪Dim i, j As Integer‬‬ ‫‪Dim Sum As Integer = 0‬‬ ‫)‪For i = 0 To Matrix.GetUpperBound(0‬‬ ‫)‪For j = 0 To Matrix.GetUpperBound(1‬‬ ‫)‪Sum += Matrix(i, j‬‬ ‫‪Next‬‬ ‫‪Next‬‬ ‫العملية ‪ GetUpperBound‬تتلقى البعد (‪ 0‬للبعد األول أي لألسطر و ‪ 1‬للبعد الثاني أي لألعمدة)‪.‬‬

‫‪28‬‬


‫اإلجراءات‬ ‫المبنى العام لإلجراءات‪:‬‬ ‫) ‪Accessibility Sub RoutineName ( ParamatersList‬‬ ‫‪Statements‬‬ ‫‪End Sub‬‬ ‫• ‪ :Accessibility‬مستوى الحماية كما هو معروف من البرمجة موجهة الكائنات‪ .‬ممكن أن‬ ‫تكون واحدة من األنواع التالية‪Public, Private, Protected,… :‬‬ ‫• ‪ :Sub‬كلمة محجوزة تفيد أننا نكتب اجراء‪ .‬وهي مأخوذة من الكلمة ‪Subroutine‬‬ ‫• ‪ :RoutineName‬اسم اإلجراء‬ ‫• ‪ :ParamatersList‬قائمة البارمترات‪.‬‬ ‫• ‪ :End Sub‬نهاية اإلجراء‪.‬‬ ‫مبنى قائمة البارمترات‬ ‫القائمة عبارة عن سلسلة من األجزاء التي تفصل بينها الفاصلة‪ .‬لكل بارامتر يوجد جزء مبني‬ ‫كالتالي‪:‬‬ ‫‪PassingWay ParameterName As ParameterType‬‬ ‫• ‪ :PassingWay‬نوع تمرير البارمترات وهي اما‬ ‫‪ :ByVal o‬بحسبها يتم تمرير ‪ Values‬أي قيم فقط‪ .‬هذا النوع من البارمترات يحمل‬ ‫قيما من المستدعي الى اإلجراء فقط‪ .‬القيم تبقى عند المستدعي بعد انتهاء االستدعاء‬ ‫كما كانت قبله أي ال تتغير‪.‬‬ ‫‪ :ByRef o‬بحسبها يتم تمرير ‪ References‬أي مؤشرات‪ .‬هذا النوع من البارمترات‬ ‫يحمل قيما من المستدعي الى اإلجراء والعكس‪ .‬أي أن القيم قد تتغير عند المستدعي‬ ‫بعد انتهاء االستدعاء‪.‬‬ ‫• ‪ :ParameterName‬اسم البارمتر‪.‬‬ ‫• ‪ :ParameterType‬نوع البارمتر‪.‬‬

‫‪29‬‬


‫الخروج من االجراء مبكرا يكون بواسطة األمر ‪.Exit Sub‬‬ ‫مثال‬ ‫االجراء التالي يعرض العملية المشهورة في علم الحاسوب وهو يتلقى عددين صحيحين ‪ a‬و ‪ b‬ثم‬ ‫يقوم بتبديل قيمهم‪:‬‬ ‫)‪Public Sub Swap(ByRef a As Integer, ByRef b As Integer‬‬ ‫‪Dim Temp As Integer‬‬ ‫‪Temp = a‬‬ ‫‪a=b‬‬ ‫‪b = Temp‬‬ ‫‪End Sub‬‬

‫الدوال‬ ‫المبنى العام للدوال‪:‬‬ ‫‪Accessibility Function FunctionName ( ParamatersList ) As RetType‬‬ ‫‪Statements‬‬ ‫‪End Function‬‬ ‫• ‪ :Accessibility‬مستوى الحماية كما هو مشروح عند اإلجراءات‬ ‫• ‪ :Function‬كلمة محجوزة تفيد أننا نكتب دالة‪.‬‬ ‫• ‪ :FunctionName‬اسم الدالة‬ ‫• ‪ :ParamatersList‬قائمة البارمترات كما هي مشروحة عند اإلجراءات‬ ‫• ‪ :RetType‬نوع القيمة ال ُمرجعة من قبل الدالة‪ .‬الدالة تعيد القيمة بمساعدة األمرة ‪.Return‬‬ ‫• ‪ :End Function‬نهاية الدالة‪.‬‬ ‫الخروج من الدالة مبكرا يكون بواسطة األمر ‪.Exit Sub‬‬ ‫مثال‬ ‫الدالة التالية تتلقى عددا طبيعيا ‪ Num‬وتعيد مجموع منازله‪:‬‬ ‫‪Public Function GetSumOfDigits(ByVal Num As Integer) As Integer‬‬ ‫‪Dim Sum As Integer = 0‬‬ ‫‪While Num <> 0‬‬ ‫‪Sum += Num Mod 10‬‬ ‫‪Num = Num \ 10‬‬ ‫‪End While‬‬ ‫‪Return Sum‬‬ ‫‪End Function‬‬

‫‪30‬‬


‫مثال‬ :False ‫ خالف ذلك تعيد‬.‫ إذا كان أوليا‬True ‫ وتعيد‬Num ‫الدالة التالية تتلقى عددا طبيعيا‬ Public Function IsPrime(ByVal Num As Integer) As Boolean Dim i As Integer For i = 2 To (Num - 1) If Num Mod i = 0 Then Return False End If Next Return True End Function

‫الفئات‬ ‫سأشرح هنا الفئات بشكل عام ومن خالل أمثلة فقط ألنها ال تختلف كثيرا عن التفاصيل الموجودة في‬ C# ‫كتاب اسس البرمجة موجهة الكائنات بلغة‬ :‫المبنى العام للفئات‬ public Class ClassName { // ‫تعريف مجموعة من الخصائص أو الصفات‬ // ‫برمجة مجموعة من العمليات‬ }

‫مثال‬ Public Class Employee Public EmployeeNumber As Integer Public FamilyName As String Public GivenName As String Public DateOfBirth As Date Public Salary As Decimal Public Function Format( ) As String Return GivenName & " " & FamilyName End Function End Class

31


Employee ‫المقطع التالي يستعمل الفئة‬ Dim emp As New Employee( ) emp.EmployeeNumber = 10 emp.FamilyName = "Abu Sami" emp.GivenName = "Sami" emp.DateOfBirth = #1/28/1965# emp.Salary = 11000

emp ‫امكانية أخرى إلنشاء الكائن‬ Dim emp As Employee = New Employee() ‫ وهنا تم استعمال الباني االفتراضي الذي وفره‬.New ‫الحظ أن انشاء الكائنات يكون بواسطة األمر‬ .‫لنا المترجم كما هو معروف من اسس البرمجة موجهة الكائنات‬

‫البواني‬ ‫ األمثلة‬.New ‫ ال تأخذ نفس اسم الفئة وانما اسمها يكون الكلمة المحجوزة‬VB.NET ‫البواني بلغة‬ :‫التالية تبين ذلك‬ Public Sub New() 'Default Constructor End Sub Public Sub New(ByVal EmployeeNumber As Integer) Me.EmployeeNumber = EmployeeNumber End Sub Public Sub New(ByVal EmployeeNumber As Integer, ByVal FamilyName As String, ByVal GivenName As String) Me.EmployeeNumber = EmployeeNumber Me.FamilyName = FamilyName Me.GivenName = GivenName End Sub

32


‫ في لغات‬this ‫ التي تقابل الكلمة المحجوزة‬Me ‫الحظ أننا نرمز الى الكائن الحالي بالكلمة المحجوزة‬ .C# ‫أخرى مثل‬

Properties ‫الخصائص‬ ‫تعريف الخصائص يكون على النحو التالي‬ Public Property EmployeeNumber() As String Get Return m_EmployeeNumber End Get Set(ByVal value As String) m_EmployeeNumber = value End Set End Property

33


‫معالجات األحداث‬ ‫سنبدأ اآلن بشرح جانب البرمجة من خالل األمثلة‪.‬‬ ‫مثال‬ ‫المطلوب تصميم وبرمجة آلة حاسبة بسيطة قادرة على جمع وضرب وطرح عددين حقيقيين‪.‬‬ ‫التصميم المقترح هو التالي‪:‬‬

‫يظهر النموذج بأن لدينا ‪ 9‬أدوات أو ‪ .Controls‬هذه األدوات هي‪:‬‬ ‫األداة‬

‫االسم أو الـ ‪ID‬‬

‫‪Label‬‬

‫‪LabelResult‬‬

‫‪Label‬‬

‫‪LabelXValue‬‬

‫‪Label‬‬

‫‪LabelYValue‬‬

‫الشرح‬ ‫تستعمل هذه األداة إلظهار نصوص‬ ‫ثابتة كعناوين ألدوات أخرى‪ .‬هنا‬ ‫سنستعملها إلظهار نتيجة الحساب‪.‬‬ ‫هنا استعملناها لتوجيه المستخدم بأن‬ ‫يدخل في صندوق النص الذي إلى‬ ‫يمين األداة القيمة األولى ال ُمراد‬ ‫جمعها‪.‬‬ ‫توجه المستخدم بأن يدخل في‬ ‫صندوق النص الذي إلى يمين األداة‬ ‫القيمة الثانية ال ُمراد جمعها‪.‬‬

‫‪34‬‬


‫‪TextBox‬‬

‫‪TextBoxValue1‬‬

‫‪TextBox‬‬

‫‪TextBoxValue2‬‬

‫‪Button‬‬

‫‪ButtonAdd‬‬

‫‪Button‬‬

‫‪ButtonSub‬‬

‫‪Button‬‬

‫‪ButtonMul‬‬

‫‪Button‬‬

‫‪ButtonClose‬‬

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

‫البرمجة‬ ‫إذا شغلنا هذا النموذج فسوف يظهر بالضبط كما نريده وبإمكاننا أن نستعمل صناديق النصوص لكتابة‬ ‫األعداد لكن إذا نقرنا بالزر األيسر للفارة على احد األزرار )… ‪ (ADD, SUB,‬فان شيئًا لن‬ ‫يحدث‪ .‬لماذا؟ اإلجابة بسيطة ألننا لم نكتب معالجًا لهذه األحداث‪ .‬أي لم نكتب االجراء الذي سيأخذ‬ ‫القيم من صناديق النصوص ثم يُنفذ العملية المطلوبة ويضع النتيجة في األداة ‪.LabelResult‬‬

‫‪35‬‬


‫كتابة معالجات األحداث‬ ‫يوجد لكل أداة من األدوات المتوفرة في القائمة التي يعرضها الـ ‪ Toolbox‬مجموعة من األحداث‬ ‫التي تدعمها هذه األدوات‪ .‬عند التعرف على أية أداة سيكون التعرف على األحداث التي تدعمها األداة‬ ‫جزءا من عملية دراسة األداة ودراسة إمكانياتها وخصائصها‪ .‬لمعرفة مجموعة األحداث ألية أداة‬ ‫نختار األداة في عرض الـ ‪ Design‬ومن ثم نحضر نافذة الخصائص كما بينا سابقا من خالل النقر‬ ‫على الزر األيمن للفارة واختيار ‪ Properties‬من القائمة التي تظهر (احرص على وضع الفارة‬ ‫على األداة حين النقر على الزر األيمن للفارة) ‪.‬‬ ‫حينها ستظهر(عادة) في الجهة اليمنى من الـ ‪ Visual Studio‬نافذة الخصائص التي تحتوي على‬ ‫جميع خصائص األداة بما في ذلك أيضا األحداث‪ .‬الوصول إلى قائمة األحداث يكون من خالل النقر‬ ‫على الزر‬

‫الموجود أعلى نافذة الخصائص‬

‫النقر على زر األحداث يظهر قائمة األحداث التالية‬

‫‪36‬‬


37


‫انتبه إلى أن محتوى القائمة سيكون مختلفا حسب األداة التي نختارها في عرض الـ ‪ !Design‬الحظ‬ ‫أيضا المالحظة الموجودة في نهاية نافذة األحداث التي تشرح متى يحصل الحدث ال ُمختار‪.‬‬ ‫لكتابة معالج لحدث ما أُكتب اسما في الصندوق الذي إلى يمين اسم الحدث ثم أضغط ‪ .Enter‬انتبه‬ ‫إلى أن االسم الذي تكتبه هنا هو اسم إلجراء أي لعملية ولذلك عليه أن يكون محققا لشروط تسمية‬ ‫ال ُمعرفات )‪ .(Identifiers Naming Rules‬مثال ‪ OnClickAdd‬فقد جرت العادة عند مبرمجي‬ ‫الـ ‪ GUIs‬أن يبدأ اسم معالج الحدث بالنص ‪ On‬للداللة على أن هذا هو المقطع الذي يستدعى كردة‬ ‫فعل على الحدث )‪ .(Response On an Event‬في االسم يظهر أيضا اسم الحدث ‪ Click‬واسم‬ ‫يدل على الزر‪ .‬طبعا هذه الطريقة للتسمية ليست ملزمة وإنما هي إحدى اإلمكانيات للتسمية‪ .‬بعد‬ ‫إعطاء االسم والضغط على ‪ Enter‬سينقُلُك ‪ Visual Studio‬إلى النافذة التي ستكتب فيها الكود أي‬ ‫برمجة جميع معالجات األحداث وجميع الفئات والعمليات التابعة لنموذج معين‪.‬‬ ‫‪Public Class FormCalc‬‬ ‫‪Private Sub OnClickAdd(sender As System.Object,‬‬ ‫‪e As System.EventArgs) Handles ButtonAdd.Click‬‬ ‫‪End Sub‬‬ ‫‪End Class‬‬

‫انتبه إلى الجزء ‪ Handles ButtonAdd.Click‬الموجود في نهاية رأس اإلجراء والذي يعني حرفيا‪:‬‬ ‫يعالج الحدث ‪ Click‬التابع لألداة ‪.ButtonAdd‬‬ ‫في األمثلة المتقدمة التي ستأتي الحقا سوف نتعرف أكثر على قائمة البارامترات ووظيفة كل‬ ‫بارامتر‪.‬‬ ‫هنالك إمكانية ثانية لكتابة معالج الحدث بدون استعمال نافذة األحداث وذلك من خالل النقر مرتين‬ ‫بالفارة ‪Double Click‬على األداة التي نريد أن نكتب لها معالج حدث وذلك في عرض الـ‬ ‫‪ .Design‬حينها سيكتب ‪ Visual Studio‬معالجا لما يُسمى بالحدث االفتراضي لألداة ‪(Default‬‬ ‫)‪ Event‬وهو يختلف من أداة إلى أُخرى‪ .‬فمثال الحدث االفتراضي لألداة ‪ Button‬هو الحدث‬ ‫‪ Click‬الذي يحصل عندما ينقر المستخدم بالزر األيسر للفارة على األداة‪ .‬بينما الحدث االفتراضي‬ ‫لألداة ‪ TextBox‬هو الحدث ‪ TextChanged‬الذي يحصل عندما يتغير محتوى صندوق النص‪.‬‬

‫‪38‬‬


‫يجب أن تالحظ أيضا أن االسم الذي يعطيه ‪ Visual Studio‬للمعالج عند استعمال هذه اإلمكانية هو‬ ‫كالتالي‪ :‬فقد سار ‪ Visual Studio‬في التسمية حسب القاعدة "اسم الحدث_اسم األداة"‪.‬‬ ‫‪Private Sub ButtonAdd_Click(sender As System.Object,‬‬ ‫‪e As System.EventArgs) Handles ButtonAdd.Click‬‬ ‫‪End Sub‬‬

‫ننتقل اآلن إلى برمجة معالج الحدث ‪ ButtonAdd_Click‬بشكل كامل‪ .‬األلغوريثم التالي يبين‬ ‫ال ُخطُوات الالزمة‪:‬‬ ‫‪ُ .1‬خذ النص الموجود في الصندوق ‪ TextBoxXValue‬وحوله إلى عدد حقيقي وأحفظ العدد في‬ ‫المتغير ‪Val1‬‬ ‫‪ُ .2‬خذ النص الموجود في الصندوق ‪ TextBoxYValue‬وحوله إلى عدد حقيقي وأحفظ العدد في‬ ‫المتغير ‪Val2‬‬ ‫‪ .3‬أحفظ القيمة ‪ Val1 + Val2‬في المتغير ‪Result‬‬ ‫‪ .4‬حول قيمة المتغير ‪ Result‬إلى نص بواسطة الدالة )(‪ ToString‬وأعطه كقيمة إلى الخاصية‬ ‫‪ Text‬التابعة لألداة ‪ LabelResult‬وصلها بجملة توضيح مناسبة مثل ‪The Result is‬‬ ‫في لغة ‪ VB.NET‬تكون البرمجة كالتالي‪:‬‬ ‫‪Private Sub ButtonAdd_Click(sender As System.Object,‬‬ ‫‪e As System.EventArgs) Handles ButtonAdd.Click‬‬ ‫‪Dim Val1, Val2 As Double‬‬ ‫)‪Val1 = Integer.Parse(TextBoxXValue.Text‬‬ ‫)‪Val2 = Integer.Parse(TextBoxYValue.Text‬‬ ‫‪Dim Result As Double‬‬ ‫‪Result = Val1 + Val2‬‬ ‫‪LabelResult.Text = "The Result is:" + Result.ToString‬‬ ‫‪End Sub‬‬

‫الحظ أنه حين استدعاء اجراء ال يتلقى بارامترات مثل ‪ ToString‬فال حاجة لكتابة األقواس‬ ‫الدائرية‪.‬‬ ‫‪39‬‬


‫اآلن إذا شغلنا التطبيق وأدخلنا القيم التي نريد ثم نقرنا الزر ‪ ADD‬ستظهر النتيجة كالتالي‪:‬‬

‫‪40‬‬


‫عمليات التأكد من صحة االدخال أو المعلومات‬ ‫ماذا لو أدخل ال ُمستخدم في المثال السابق قيما ليست أعدادا؟ كيف سيكون بإمكاننا في هذه الحالة‬ ‫التأكد من صحة االدخال؟ أي كيف سنفحص مثال أن ال ُمستخدم حقًا أدخل عددا أو عددا حقيقيًا وما الى‬ ‫ذلك‪.‬‬ ‫توفر ‪ VB.NET‬مجموعة من العمليات العامة لفحص مبنى المعلومات األساسية نلخصها فيما يلي‪:‬‬ ‫العملية ‪IsNumeric‬‬ ‫‪Public Function IsNumeric(ByVal Expression As Object) As Boolean‬‬ ‫ادعاء الدخول‬

‫تتلقى تعبيرا قد يكون نصا أو أي شيء مشتق من الفئة‬ ‫‪Object‬‬

‫ادعاء الخروج‬

‫تعيد ‪ True‬إذا تبين أن التعبير عبارة عن عدد صحيح أو‬ ‫حقيقي‪.‬‬ ‫خالف ذلك تعيد ‪ .False‬العملية تعيد أيضا ‪ False‬اذا‬ ‫كان البارمتر عبارة عن نص فارغ‪.‬‬

‫أمثلة‬ ‫‪Dim obj As Object‬‬ ‫‪Dim CheckResult As Boolean‬‬ ‫"‪obj = "53‬‬ ‫‪' The following call to IsNumeric returns True.‬‬ ‫)‪CheckResult = IsNumeric(obj‬‬ ‫"‪obj = "459.95‬‬ ‫‪' The following call to IsNumeric returns True.‬‬ ‫)‪CheckResult = IsNumeric(obj‬‬ ‫"‪obj = "45 Help‬‬ ‫‪' The following call to IsNumeric returns False.‬‬ ‫)‪CheckResult = IsNumeric(obj‬‬

‫‪41‬‬


‫ في التطبيق السابق ليكون أكثر أمانًا ويقبل فقط‬ADD ‫واآلن بامكاننا اعادة كتابة معالج الحدث للزر‬ :‫أعدادا في صناديق النص‬ Private Sub ButtonAdd_Click(sender As System.Object, e As System.EventArgs) Handles ButtonAdd.Click If Not IsNumeric(TextBoxXValue.Text) Then LabelResult.Text = "Error: Value of X is not a number" Exit Sub End If If Not IsNumeric(TextBoxXValue.Text) Then LabelResult.Text = "Error: Value of Y is not a number" Exit Sub End If Dim Val1, Val2 As Double Val1 = Integer.Parse(TextBoxXValue.Text) Val2 = Integer.Parse(TextBoxYValue.Text) Dim Result As Double Result = Val1 + Val2 LabelResult.Text = "The Result is:" + Result.ToString() End Sub

IsDate ‫العملية‬ Public Function IsDate(ByVal Expression As Object) As Boolean ‫تتلقى تعبيرا قد يكون نصا أو أي شيء مشتق من الفئة‬

‫ادعاء الدخول‬

Object ‫ إذا تبين أن التعبير عبارة عن‬True ‫تعيد‬ ‫تاريخ صالح‬

‫أو وقت صالح‬

‫أو تاريخ ووقت صالحين‬

‫ادعاء الخروج‬

.False ‫خالف ذلك تعيد‬ ‫أمثلة‬ Dim firstDate, secondDate As Date Dim timeOnly, dateAndTime, noDate As String Dim CheckResult As Boolean ' CDate converts the passed parameter to a Date object firstDate = CDate("February 12, 1969") secondDate = #2/12/1969#

42


timeOnly = "3:45 PM" dateAndTime = "March 15, 1981 10:22 AM" noDate = "Hello" ' The following calls to IsDate return True. CheckResult = IsDate(firstDate) CheckResult = IsDate(secondDate) CheckResult = IsDate(timeOnly) CheckResult = IsDate (dateAndTime) ' The following call to IsDate returns False. CheckResult = IsDate (noDate)

IsNothing ‫العملية‬ Public Function IsNothing(ByVal Expression As Object) As Boolean ‫تتلقى تعبيرا قد يكون نصا أو أي شيء مشتق من الفئة‬

‫ادعاء الدخول‬

Object ‫ تُمثل‬.Nothing ‫ إذا تبين أن التعبير عبارة‬True ‫تعيد‬

‫ادعاء الخروج‬

‫ المعروفة في باقي‬null ‫هذه الكلمة المحجوزة القيمة‬ ‫ وهي قيمة المؤشر أو الكائن عندما يكون غير‬.‫اللغات‬ .‫صالح لالستعمال‬ .False ‫خالف ذلك تعيد‬ ‫أمثلة‬ Dim obj As Object ' No instance has been assigned to variable obj yet. Dim CheckResult As Boolean ' The following call returns True. CheckResult = IsNothing(obj) ' Assign a string instance to variable obj. obj = "ABCDEF" ' The following call returns False. CheckResult = IsNothing(obj) ' Disassociate variable obj from any instance. obj = Nothing ' The following call returns True. CheckResult = IsNothing(obj)

43


‫تمارين‬ ‫تمرين رقم ‪1‬‬ ‫أُكتب معالج حدث للحدث ‪ Click‬للزر ‪ Close‬في تطبيق اآللة الحاسبة الموجود أعاله‪ .‬على معالج‬ ‫الحدث أن يغلق النموذج وينهي التطبيق وذلك من خالل األمر‬ ‫)(‪Me.Close‬‬

‫تمرين رقم ‪2‬‬ ‫أُكتب معالج حدث للحدث ‪ Click‬لألزرار ‪ SUB‬و ‪ MUL‬في تطبيق اآللة الحاسبة الموجود أعاله‪.‬‬ ‫المعالجان يعمالن بالضبط مثل معالج الزر ‪ ADD‬لكنهما يقومان بالطرح والضرب بدال من الجمع‪.‬‬ ‫تمرين رقم ‪3‬‬ ‫مؤشر كتلة الجسم (باإلنجليزية‪ )Body mass index :‬هو أفضل مقياس متعارف عليه عالميا لتمييز‬ ‫الوزن الزائد عن السمنة أو البدانة عن النحافة عن الوزن المثالي‪ ،‬وهو يعبر عن العالقة بين وزن الشخص‬ ‫وطوله‪ .‬يُحسب مؤشر كتلة الجسم بتقسيم الوزن بالكيلوجرام على مربع الطول بالمتر كما يلي‪ :‬مؤشر كتلة‬ ‫الجسم = الوزن بالكيلوجرام ‪ /‬مربع الطول بالمتر‬ ‫صمم التطبيق التالي لحساب مؤشر كتلة الجسم‪ .‬الحظ أننا نستعمل هنا األداة ‪ .GroupBox‬الغرض من‬ ‫استخدام هذه األداة هو تنظيم وضع األدوات التي لها نفس الهدف على النموذج (باإلضافة الى أغراض‬ ‫أخرى سنتعرف عليها الحقًا)‪ .‬هذه األداة عبارة عن شكل رباعي ( ُمربع أو مستطيل) له اسم خاص به يُحدد‬ ‫بواسطة الخاصية ‪ Text‬التابعة لها‪ .‬نضع بداخلها األدوات التي لها نفس الهدف أو الوظيفة‪ .‬يُمكننا الحصول‬ ‫على هذه األداة من الـ ‪ Toolbox‬من المجموعة ‪ Containers‬كما تُبين الصورة التالية‪:‬‬

‫‪44‬‬


‫النموذج‪:‬‬

‫يظهر النموذج بأن لدينا مجموعة كبيرة من األدوات أو ‪ .Controls‬هذه األدوات هي‪:‬‬ ‫األداة‬ ‫‪GroupBox‬‬

‫االسم أو الـ ‪ID‬‬ ‫‪GroupBoxData‬‬

‫الشرح‬ ‫تُظهر النص‪:‬‬ ‫‪Data‬‬

‫‪45‬‬


‫تُظهر النص‪:‬‬

‫‪Label‬‬

‫‪LabelHeight‬‬

‫‪TextBox‬‬

‫‪TextBoxHeight‬‬

‫إلدخال طول الشخص بالمتر‬

‫‪Label‬‬

‫‪LabelWeight‬‬

‫تُظهر النص‪:‬‬

‫‪TextBox‬‬

‫‪TextBoxWeight‬‬

‫‪Button‬‬

‫‪ButtonCalcBMI‬‬

‫‪GroupBox‬‬

‫‪GroupBoxResults‬‬

‫‪Label‬‬

‫‪LabelBMI‬‬

‫تُظهر النص‪:‬‬

‫‪TextBox‬‬

‫‪TextBoxBMI‬‬

‫إلظهار قيمة الـ ‪ BMI‬التي تم‬

‫‪Label‬‬

‫‪LabelCategory‬‬

‫‪TextBox‬‬

‫‪TextBoxCategory‬‬

‫(‪Your Height (in m‬‬

‫)‪Your Weight (in Kg‬‬ ‫إلدخال وزن الشخص‬ ‫بالكيلوغرام‬ ‫الزر الذي سيكون على‬ ‫المستخدم أن ينقره نقرة واحدة‬ ‫بالزر األيسر للفارة لحساب الـ‬ ‫‪.BMI‬‬ ‫تُظهر النص‪:‬‬ ‫‪Results‬‬

‫‪Your BMI is‬‬ ‫حسابها‪ .‬أعط الخاصية‬ ‫‪ ReadOnly‬التابعة لهذه‬ ‫األداة القيمة ‪ True‬حتى تكون‬ ‫للقراءة فقط وذلك ألن الذي‬ ‫سيدخل القيمة هو التطبيق‬ ‫وليس ال ُمستخدم‪.‬‬ ‫تُظهر النص‪:‬‬ ‫‪Your BMI Category is‬‬ ‫إلظهار تصنيف قيمة الـ‬ ‫‪ BMI‬التي تم حسابها‪ .‬أعط‬ ‫الخاصية ‪ ReadOnly‬التابعة‬

‫‪46‬‬


‫لهذه األداة القيمة ‪ True‬حتى‬ ‫تكون للقراءة فقط وذلك ألن‬ ‫الذي سيدخل النص هو‬ ‫التطبيق وليس ال ُمستخدم‪.‬‬ ‫ال ُمستخدم يُدخل القيم الالزمة لحساب الـ ‪( BMI‬الطول والوزن) الى صناديق النص ‪ TextBoxHeight‬و‬ ‫‪ .TextBoxWeight‬ثم يضغط على الزر ‪ .Calculate BMI‬بعد ذلك يقوم التطبيق بحساب قيمة الـ‬ ‫‪ BMI‬ويُدخل النتيجة الى صندوق النص ‪ TextBoxBMI‬والتصنيف الى صندوق النص‬ ‫‪ .TextBoxCategory‬يُلخص الجدول التالي تصنيف نتيجة الـ ‪ BMI‬بحسب مجال القيمة التي تم‬ ‫حسابها‪:‬‬ ‫‪Category‬‬

‫‪BMI range – kg/m2‬‬ ‫‪ less than 15‬نقص حاد جدا‬

‫‪Very severely underweight‬‬

‫‪Severely underweight‬‬ ‫‪Underweight‬‬ ‫)‪Normal (healthy weight‬‬

‫بالعربية‬

‫‪ from 15.0 to 16.0‬نقص حاد‬ ‫‪ from 16.0 to 18.5‬نقص في الوزن‬ ‫‪ from 18.5 to 25‬وزن طبيعي‬ ‫‪ from 25 to 30‬زيادة في الوزن‬

‫‪Overweight‬‬ ‫‪Obese Class I (Moderately‬‬ ‫)‪obese‬‬

‫‪ from 30 to 35‬سمنة خفيفة (سمنة من الدرجة األولى)‬

‫‪Obese Class II (Severely‬‬ ‫)‪obese‬‬

‫‪ from 35 to 40‬سمنة متوسطة (سمنة من الدرجة الثانية)‬

‫‪Obese Class III (Very severely‬‬ ‫)‪obese‬‬

‫‪ over 40‬سمنة مفرطة (سمنة من الدرجة الثالثة)‬

‫‪47‬‬


‫يجب فحص ال ُمعطيات ال ُمدخلة الى صناديق النصوص بواسطة العملية ‪ IsNumeric‬قبل البدء‬ ‫بالحسابات‪.‬‬

‫تمرين رقم ‪4‬‬ ‫برمج نموذج حساب الـ ‪ BMI‬بحيث يظهر محتواه باللغة العربية‬

‫توفر األداة ‪ Form‬خاصيتين لدعم اللغة العربية واللغة العبرية‪:‬‬ ‫‪ :RightToLeft‬اما أن تكون ‪ Yes‬أو ‪ .No‬يجب اختيار ‪ Yes‬إلظهار النموذج وجميع األدوات من‬ ‫اليمين الى اليسار‪.‬‬

‫‪48‬‬


‫‪ :RightToLeftLayout‬اما أن تكون ‪ True‬أو ‪ .False‬يجب اختيار ‪ True‬إلظهار أزرار‬ ‫النموذج‬

‫في الجهة اليسرى العليا للنموذج‪.‬‬

‫‪49‬‬


‫تمرين رقم ‪5‬‬ ‫صمم وبرمج النموذج التالي لحل المعادالت التربيعية‬

‫على ال ُمستخدم أن يُدخل معامالت المعادلة التربيعية ‪ a,b,c‬في صناديق النصوص من اليسار الى‬ ‫اليمين‪ .‬واظهار النتيجة بواسطة أداة ‪ Label‬مناسبة التي تظهر في الـ ‪ GroupBox‬أسفل النموذج‬ ‫وذلك بعد أن يضغط ال ُمستخدم على الزر !‪.Solve It‬‬ ‫يجب التأكد من صحة االدخال أي أن ال ُمستخدم أدخل أعدادا حقيقية للمعامالت وذلك بواسطة‬ ‫استعمال العملية ‪ .IsNumeric‬في حال وجود خطأ يجب اظهار ذلك بواسطة األداة ‪ Label‬بحيث‬ ‫يكون لون الخط أحمرا‪.‬‬ ‫الحظ أن المعادلة قد‬ ‫• ال يكون لها حلول حقيقية (مثال‪ b2 – 4ac < 0 :‬أو ‪)a = 0, b = 0, c ≠ 0‬‬ ‫• يكون لها عدد ال نهائي من الحلول )‪.(a = 0, b = 0, c = 0‬‬ ‫• يكون لها حل واحد‬

‫‪50‬‬


‫األداة ‪ComboBox‬‬ ‫تُسمى هذه األداة أيضا بالقائمة ال ُمنسدلة وهي تُشكل امكانية لعرض مجموعة من المعلومات (مثل‬ ‫األعداد أو النصوص) بحيث يكون بإمكان ال ُمستخدم اختيار واحد منها أو أكثر‪ .‬القائمة ال تُظهر‬ ‫محتواها ُدفعة واحدة وانما تُظهر عنصرا واحدا فقط وبإمكان ال ُمستخدم أن يفتح القائمة ليرى كل‬ ‫محتواها مع امكانية المرور على محتوى القائمة بواسطة شريط المرور أي الـ ‪.Scrolling bar‬‬ ‫شكل قائمة األشهر وهي ُمغلقة (أي تظهر شهرا واحدا فقط)‬

‫شكل قائمة األشهر بعد أن فُتحت من خالل النقر على السهم الظاهر في جهتها اليمنى‪:‬‬

‫الجدول التالي يُلخص بعض الخصائص ال ُمميزة لألداة ‪ ComboBox‬والتي سنستعملها في األمثلة‪.‬‬ ‫هناك مجموعة اضافية سنشرحها الحقا عند الحديث عنها‪.‬‬ ‫الخاصيّة‬ ‫‪Items‬‬

‫الشرح‬ ‫عبارة عن سلسلة أي ‪ List‬من العناصر التي تشكل محتوى القائمة‪ .‬وهي بودرها توفر عدة‬ ‫عمليات منها ‪ Add‬إلضافة عنصر الى القائمة والعملية ‪ Clear‬لتفريغ القائمة من محتواها‬ ‫والعملية ‪ Contains‬لمعرفة هل عنصر ما موجود داخل القائمة وهكذا‪.‬‬

‫‪Text‬‬

‫النص ال ُمختار حاليًا‬

‫‪SelectedText‬‬

‫النص ال ُمختار حاليًا‬

‫‪ SelectedIndex‬اندكس أي رقم النص ال ُمختار حاليًا في القائمة‬

‫‪51‬‬


‫مثال‬ ‫المطلوب تصميم وبرمجة إمكانية تمكن المستخدم من اختيار تاريخ ما‪ .‬إحدى المشاكل التي نواجهها‬ ‫عندما نطلب من المستخدم تاريخا ما (مثال تاريخ ميالد المستخدم) هي فحص هل القيمة أو القيم التي‬ ‫أُدخلت تمثل حقًا تاري ًخا صحي ًحا‪ .‬الحل األمثل لمثل هذه المهام إعطاء المستخدم إمكانية االختيار بدال‬ ‫من إمكانية الكتابة‪ .‬هذا الحل يُعتبر أيضا لطيفا مع المستخدم أي ‪ .User-friendly‬فاالختيار أسهل‬ ‫وأسرع من الكتابة ويحول دون حصول أخطاء‪ .‬سوف نستعمل هنا أداة القائمة المنسدلة‬ ‫‪ ComboBox‬ثالث مرات على النحو وبالتنسيق التالي‪:‬‬

‫األداة‬

‫االسم أو الـ ‪ID‬‬

‫الشرح‬

‫‪ComboBox‬‬

‫‪ComboBoxDay‬‬

‫تستعمل هذه األداة إلظهار األيام‬

‫‪ComboBox‬‬

‫‪ComboBoxMonth‬‬

‫الممكنة وذلك وفقا للسنة والشهر‬ ‫المختارين‪ .‬مثال إذا كانت السنة‬ ‫المختارة كبيسة والشهر المختار‬ ‫شباط فسيكون مجال األيام من ‪1‬‬ ‫إلى ‪ .29‬خالف ذلك ستحتوي هذه‬ ‫القائمة بالنسبة لشهر شباط فقط ‪28‬‬ ‫يوما‪ .‬كذلك األمر بالنسبة لألشهر‬ ‫التي فيها ‪ 30‬يوما وتلك التي فيها‬ ‫‪ 31‬يوما‪.‬‬ ‫تستعمل هذه األداة إلظهار األشهر‬ ‫من ‪ 1‬إلى ‪12‬‬

‫‪52‬‬


‫‪ComboBox‬‬

‫‪ComboBoxYear‬‬

‫تستعمل هذه األداة إلظهار السنين‬ ‫من المجال الذي نريده‪.‬‬

‫من الواضح أن أكثر قائمة من بين القوائم الثالث تحتاج إلى حرص ودقة في البرمجة هي قائمة األيام‬ ‫أي ‪ .ComboBoxDay‬محتوى باقي القوائم ثابت بينما محتوى هذه القائمة متعلق بالسنة والشهر‬ ‫المختارين‪ .‬متى سنمأل هذه القائمة بالقيم الممكنة؟ الجواب‬ ‫• عندما يُستدعى النموذج ألول مرة‪ .‬هنا علينا برمجة معالج الحدث ‪ Load‬الخاص بالنموذج‪ .‬هذا‬ ‫الحدث يحصل قبيل ظهور النموذج لل ُمستخدم‪ .‬لذلك بإمكاننا برمجة معالج له لنقوم بإجراء بعض‬ ‫التغييرات المطلوبة على النموذج‪ .‬سنقوم بإدخال السنوات الى القائمة ‪ComboBoxYear‬‬ ‫وأيضا األشهر الى القائمة ‪ ComboBoxMonth‬بعد ذلك سنأخذ التاريخ الحالي ومن ثم نقوم‬ ‫باختيار أجزائه المختلفة (اليوم والشهر والسنة) في القوائم الثالث وادخال األيام الممكنة بعد‬ ‫معرفة السنة والشهر الى القائمة ‪.ComboBoxDay‬‬ ‫• في كل مرة يتم فيها تغيير السنة أو الشهر من قبل المستخدم‪ .‬السؤال هنا هو كيف نعرف (أي‬ ‫كيف يعرف النموذج) أن المستخدم غير اختيار السنة أو الشهر؟ هذا يكون من خالل الحدث‬ ‫‪( SelectedIndexChanged‬أو الحدث ‪ (SelectedTextChanged‬الذي تُحدثه القائمة‬ ‫المنسدلة‪ .‬هذا الحدث هو أيضا الحدث االفتراضي للقائمة المنسدلة‪.‬‬ ‫البرمجة‬ ‫برمجة معالج الحدث ‪ Load‬الخاص بالنموذج ‪FormSelectData‬‬ ‫‪Private Sub FormSelectData_Load(sender As System.Object,‬‬ ‫‪e As System.EventArgs) Handles MyBase.Load‬‬ ‫اجراء مساعد لتعبئة قائمة األشهر' ) (‪FillMonthsCB‬‬ ‫اجراء مساعد لتعبئة قائمة السنين ' ) (‪FillYearsCB‬‬ ‫نُعرف متغيرا من نوع تاريخ ' ‪Dim ToDay As Date‬‬ ‫‪ToDay = Date.Now‬‬ ‫نأخذ تاريخ اليوم '‬ ‫نختار السنة الحالية من قائمة السنين '‬ ‫‪ComboBoxYear.SelectedText = ToDay.Year.ToString‬‬ ‫نختار الشهر الحالي من قائمة األشهر '‬ ‫‪ComboBoxMonth.SelectedText = ToDay.Month.ToString‬‬ ‫اجراء مساعد لتعبئة قائمة األيام ' )(‪FillDaysCB‬‬ ‫نختار اليوم الحالي من قائمة األيام '‬ ‫‪ComboBoxDay.SelectedText = ToDay.Day.ToString‬‬ ‫‪End Sub‬‬

‫‪53‬‬


‫العمليات المساعدة‬ ‫اجراء مساعد لتعبئة قائمة األشهر‬ Private Sub FillMonthsCB() ComboBoxMonth.Items.Clear() ' ‫نقوم بتفريغ القائمة حتى ال تظهر القيم أكثر من مرة‬ Dim i As Integer For i = 1 To 12 ComboBoxMonth.Items.Add(i.ToString()) Next End Sub

‫اجراء مساعد لتعبئة قائمة السنين‬ Private Sub FillYearsCB() ComboBoxYear.Items.Clear() Dim i As Integer Dim ToDay As Date ToDay = Date.Now For i = 1965 To ToDay.Year ComboBoxYear.Items.Add(i.ToString()) Next End Sub

‫اجراء مساعد لتعبئة قائمة األيام‬ Private Sub FillDaysCB() Dim Month As Integer ' ‫نأخذ الشهر ال ُمختار من قائمة األشهر‬ Month = Integer.Parse(ComboBoxMonth.Text.ToString()) Dim Year As Integer ' ‫نأخذ السنة ال ُمختارة من قائمة السنين‬ Year = Integer.Parse(ComboBoxYear.Text.ToString()) Dim Days As Integer ' ‫نحصل على عدد األيام في الشهر بمساعدة دالة مساعدة‬ Days = GetNumOfDays(Month, Year) ComboBoxDay.Items.Clear() Dim i As Integer For i = 1 To Days ComboBoxDay.Items.Add(i.ToString()) Next End Sub

‫دالة مساعدة تتلقى الشهر والسنة وتعيد عدد األيام في الشهر‬ Private Function GetNumOfDays(ByVal month As Integer, ByVal year As Integer) As Integer If month = 1 Or month = 3 Or month = 5 Or month = 7 Or month = 8 Then Return 31 End If If month = 2 Then 54


If IsLeapYear(year) Then Return 29 Else Return 28 End If End If If month = 4 Or month = 6 Or month = 9 Or month = 11 Then Return 30 End If If month = 10 Or month = 12 Then Return 31 End If Return 0 End Function

False ‫ خالف ذلك تعيد‬.‫ إذا كانت سنة كبيسة‬True ‫دالة مساعدة تتلقى سنة وتعيد‬

Private Function IsLeapYear(ByVal year As Integer) As Boolean Return (((year Mod 4 = 0) And (year Mod 100 <> 0)) Or (year Mod 400 = 0)) End Function

‫معالجات األحداث التي تحصل عندما يغير ال ُمستخدم اختياره في احدى القوائم – لكل قائمة معالج‬ :‫خاص بها‬ Private Sub ComboBoxMonth_SelectedIndexChanged( sender As System.Object, e As System.EventArgs) Handles ComboBoxMonth.SelectedIndexChanged FillDaysCB() ShowSelectedDate() End Sub Private Sub ComboBoxYear_SelectedIndexChanged( sender As System.Object, e As System.EventArgs) Handles ComboBoxYear.SelectedIndexChanged FillDaysCB() ShowSelectedDate() End Sub Private Sub ComboBoxDay_SelectedIndexChanged( sender As System.Object, e As System.EventArgs) Handles ComboBoxDay.SelectedIndexChanged ShowSelectedDate() End Sub LabelSelectedDate ‫اجراء مساعد إلظهار التاريخ ال ُمختار بواسطة األداة‬ 55


Private Sub ShowSelectedDate() Dim strDate As String strDate = ComboBoxDay.Text + "/" + ComboBoxMonth.Text + "/" strDate += ComboBoxYear.Text LabelSelectedDate.Text = "The selected date is " + strDate End Sub

56


‫األداة ‪DateTimePicker‬‬ ‫توفر ‪ VB.NET‬أداة متطورة جدا لتمكين ال ُمستخدم من اختيار التواريخ التي يريد‪ .‬هذه األداة تظهر‬ ‫كالتالي‬

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

‫التاريخ الذي اختاره ال ُمستخدم موجود في الخاصية ‪ Value‬وهي من نوع ‪Date‬‬

‫‪57‬‬


‫لدى هذه األداة حدث باسم ‪ ValueChanged‬يحدث كلما غير ال ُمستخدم التاريخ ال ُمختار‬ ‫‪Private Sub DateTimePicker1_ValueChanged(sender As System.Object,‬‬ ‫)‪e As System.EventArgs‬‬ ‫‪Handles DateTimePicker1.ValueChanged‬‬ ‫‪LabelSelectedDate.Text = "You date of birth is " + DateTimePicker1.Value‬‬ ‫‪End Sub‬‬

‫بارمترات معالجات األحداث‬ ‫اآلن نريد التعرف على بارامترات معالجات األحداث‪ .‬يظهر في رأس معالج الحدث بارامتران وهما‬ ‫• ‪ :sender As Object‬هذا البرامتر عبارة عن كائن من نوع ‪ object‬ومعروف أن الفئة‬ ‫‪ object‬هي الفئة التي تُشتق منها كل الفئات التي نكتبها بلغة ‪ .C#‬معنى ذلك أن هذا الكائن قد‬ ‫يكون حين المناداة على معالج الحدث )‪ (At Runtime‬كائنا من نوع فئة ُمستقة (أي ‪Derived‬‬ ‫‪ )Subclass‬وذلك بواسطة منهج تحويل أنماط الكائنات (‪ .)Objetct Type Casting‬التحويل‬ ‫الذي تم في هذه الحالة هو تحويل الى أعلى أي ‪ . Upcasting‬وبالفعل فقد يكون هذا الكائن من‬ ‫نوع ‪ Button‬اذا كان ُمرسل الحدث زرًا من نوع ‪ .Button‬أو قد يكون من نوع ‪ComboBox‬‬ ‫اذا كان ُمرسل الحدث من نوع ‪ ComboBox‬وهكذا ‪ ...‬ا ًذا هذا البرامتر وكما يدل على ذلك‬ ‫اسمه فانه يشير الى األداة التي أرسلت الحدث‪ .‬احدى االمكانيات للقيام بعملية التحول هذه تكمن‬ ‫في استعمال العملية ‪ CType‬التي هي اختصار لـ ‪ .Convert Type‬تتلقى هذه العملية متغيرا‬ ‫أو مؤشرا على كائن ما والنوع الذي نريد الحصول على متغير أو مؤشر من نوعه‬ ‫)‪Expression CType(Expression, Typename‬‬ ‫العملية تعيد متغيرا أو مؤشرا من النمط المطلوب‪.‬‬ ‫المثال األول‪ :‬أنماط أساسية‬ ‫‪Dim testNumber As Long = 1000‬‬ ‫‪' The following line of code sets testNewType to 1000.0.‬‬ ‫)‪Dim testNewType As Single = CType(testNumber, Single‬‬

‫‪58‬‬


‫المثال الثاني‪ :‬تحويل مؤشرات‬ ‫‪Dim btn As Button‬‬ ‫)‪btn = CType(sender, Button‬‬ ‫• ‪ :e As EventArgs‬هذا البرامتر يحتوي على معلومات اضافية عن الحدث وما أرسله ُمرسل‬ ‫الحدث‪ .‬شرح هذا البرامتر سيكون الحقًا من خالل مثال عملي‪.‬‬ ‫مثال‬ ‫المطلوب تصميم وبرمجة آلة حاسبة متطورة نوعا ما‪ .‬التصميم المطلوب هو التالي‪:‬‬

‫الحظ أن معظم األدوات عبارة عن أزرار ألرقام‪ .‬ما الذي يجب أن يحصل عندما ينقر ال ُمستخدم على‬ ‫أحد أزرار األرقام؟ عند النقر على أحد هذه األزرار يجب على معالج الحدث أن يضيف (عن طريق‬ ‫الوصل) الرقم الذي نُقر عليه الى العدد الموجود في صندوق النص‪ .‬العشرة أزرار تشترك في هذه‬ ‫العملية (أي عملية الوصل)‪ .‬عادة علينا أن نكتب عشرة معالجات أحداث بحيث نكتب لكل زر من‬ ‫األزرار معالجا خاصا به‪ .‬لكن وبما أن كود معالجات األحداث سيكون متشابها جدا وللحيلولة دون‬ ‫اضافة نُسخ كود متشابهة وغير ضرورية نقترح كتابة معالج حدث واحد إذا كان بإمكاننا أن نعرف‬ ‫داخل معالج الحدث الرقم الذي يجب أن يضاف الى صندوق النص‪ .‬هنا يأتي دور البارامتر ‪sender‬‬

‫‪59‬‬


‫الذي يحتوي على معلومات عن ال ُمرسل‪ .‬ا ًذا نضيف للعشرة أزرار معالج حدث واحد باسم عام‬ ‫وواحد مثل ‪ .OnDigitClick‬اضافة معالج الحدث تكون بإحدى الطرق التي ناقشناها سابقا‪.‬‬ ‫الصورة التالية تبين وضع البارامتر ‪ sender‬في الـ ‪ Debug Mode‬حين استدعاء معالج الحدث‬ ‫بعد أن نقر المستخدم على الرقم ‪.4‬‬

‫الحظ أن الخاصية ‪ Text‬التابعة للزر والتي تظهر في القائمة التي في الصورة تحمل القيمة ‪ 4‬وهي‬ ‫نفس الرقم ال ُمراد اضافته الى نص الصندوق‪.‬‬ ‫الحظ أيضا أن أسماء األزرار العشرة التي تشترك في معالج الحدث ‪ OnDigitClick‬تظهر في‬ ‫رأس معالج الحدث بعد الكلمة ‪Handles‬‬ ‫‪Private Sub OnDigitClick(sender As System.Object, e As System.EventArgs) Handles ...‬‬ ‫‪Dim btn As Button‬‬ ‫)‪btn = CType(sender, Button‬‬ ‫‪TextBoxResult.Text += btn.Text‬‬ ‫‪End Sub‬‬

‫انتبه الى أنه وجب علينا أن نقوم بعملية تحويل نمط الكائن ‪ sender‬الى أسفل أي ‪DownCast‬‬ ‫لنعيده الى نمطه األصلي وهو ‪ .Button‬بدون القيام بعملية التحويل هذه لن يكون بإمكاننا الوصول‬ ‫الى الخاصية ‪ Text‬المطلوبة‪ .‬هذا المعالج مشترك لجميع أزرار األرقام كما تم شرح ذلك‪.‬‬ ‫واآلن سنكتب معال ًجا للحدث ‪ Click‬للزر الذي يضغط عليه ال ُمستخدم إلضافة نقطة الى العدد إلدخال‬ ‫عدد حقيقي‪ .‬علينا أن نقوم بفحص العدد الموجود في صندوق النص وفق القواعد التالية‬ ‫• ال يجوز للعدد أن يبدأ بنقطة‬ ‫‪60‬‬


‫ هذا الشرط ال يمكن فحصه اال عندما ينهي المستخدم ادخال العدد‬.‫• ال يجوز للعدد أن ينتهي بنقطة‬ ‫ أو عندما ينهي‬+, -, *, … ‫األول وهذا يحصل عندما ينقر احدى العمليات المتوفرة مثل‬ = ‫المستخدم ادخال العدد الثاني وبعدها ينقر الزر‬ ‫• ال يجوز للعدد أن يحتوي على أكثر من نقطة‬ ‫ أي أن معالج الحدث ال يفعل‬.‫في حال عدم تحقق واحد من هذه الشروط فإننا نتجاهل محاولة االدخال‬ .‫شيئا‬ :‫واليكم برمجة المعالج‬ Private Sub ButtonPoint_Click(sender As System.Object, e As System.EventArgs) Handles ButtonPoint.Click ' If the number is empty the request ' the user tries to insert a point at the beginning then ' make the number start with 0. If TextBoxResult.Text.Equals(String.Empty) Then TextBoxResult.Text = "0." Exit Sub End If

' If the user tries to insert more than one point then ' ignore it If TextBoxResult.Text.Contains(".") Then ' Ignore it Exit Sub End If

' Append the point Dim btn As Button btn = CType(sender, Button) TextBoxResult.Text += btn.Text End Sub 61


‫واآلن ماذا يجب أن يحصل عندما يضغط ال ُمستخدم على أحد أزرار العمليات الحسابية )‪(+,*,-,/‬؟‬ ‫علينا‬ ‫• حفظ العدد األول الموجود في صندوق النص ‪ .TextBoxResult‬أما إذا كان الصندوق فارغا‬ ‫فعلينا اهمال هذا االختيار‪ .‬الحظ أن حفظ العدد األول يجب أن يتم بمساعدة متغير يتم تعريفه‬ ‫كخاصيّة تابعة لفئة النموذج ‪ FormMyCalculator‬وذلك حتى تكون معروفة لجميع العمليات‬ ‫ومعالجات األحداث الموجودة في الفئة‪.‬‬ ‫• حفظ العملية الحسابية التي اختارها ال ُمستخدم كخاصيّة تابعة لفئة النموذج‬ ‫‪FormMyCalculator‬‬ ‫• بعدها نقوم بتفريغ صندوق النص ‪TextBoxResult‬‬ ‫• ثم يقوم ال ُمستخدم بإدخال العدد الثاني الى صندوق النص ‪TextBoxResult‬‬ ‫الحظ أن جميع أزرار العمليات الحسابية تقوم بنفس المهام المذكورة أعاله‪ .‬لذلك سنكتب لها جميعا‬ ‫معالجا واحدا باسم ‪.OnOpClick‬‬ ‫أوال نقوم بتعريف المتغيرات على مستوى الفئة ‪:FormMyCalculator‬‬ ‫‪Public Class FormMyCalculator‬‬ ‫‪Private FirstNumber, Operation As String‬‬ ‫‪...‬‬ ‫‪End Class‬‬

‫‪ :FirstNumber‬لحفظ العدد األول‬ ‫‪ :Operation‬لحفظ العملية الحسابية‬ ‫ثم نكتب معالجا ألزرار العمليات الحسابية‪:‬‬ ‫‪Private Sub OnOpClick(sender As System.Object, e As System.EventArgs) Handles‬‬ ‫‪ButtonMult.Click, ButtonMinus.Click, ButtonDiv.Click, ButtonAdd.Click‬‬ ‫‪If TextBoxResult.Text = "" Then‬‬ ‫‪Exit Sub‬‬ ‫‪End If‬‬ ‫‪FirstNumber = TextBoxResult.Text‬‬ ‫‪Dim btn As Button‬‬ ‫)‪btn = CType(sender, Button‬‬ ‫‪Operation = btn.Text‬‬ ‫"" = ‪TextBoxResult.Text‬‬ ‫‪End Sub‬‬ ‫‪62‬‬


:= ‫ثم نكتب معالجا لزر الحصول على النتيجة أي الزر المكتوب عليه الرمز‬ Private Sub ButtonCalc_Click(sender As System.Object, e As System.EventArgs) Handles ButtonCalc.Click If TextBoxResult.Text = "" Then Exit Sub End If If FirstNumber = "" Or Operation = "" Then Exit Sub End If Dim N1, N2, Result As Double N1 = Double.Parse(FirstNumber) N2 = Double.Parse(TextBoxResult.Text) If Operation = "+" Then Result = N1 + N2 ElseIf Operation = "-" Then Result = N1 - N2 ElseIf Operation = "*" Then Result = N1 * N2 ElseIf Operation = "/" Then If N2 = 0 Then Exit Sub End If Result = N1 / N2 End If TextBoxResult.Text = Result.ToString FirstNumber = "" Operation = "" End Sub

63


‫تمارين‬ ‫تمرين رقم ‪1‬‬ ‫أُكتب معالج حدث للحدث ‪ Click‬للزر ‪ .BackSpace‬على معالج الحدث أن يحذف من العدد‬ ‫ال ُمدخل آخر رقم تم ادخاله‪ .‬بإمكانك االستعانة بالعملية ‪ Substring‬التابعة للفئة ‪String‬‬ ‫تمرين رقم ‪2‬‬ ‫أُكتب معالج حدث للحدث ‪ Click‬للزر ‪ Sqrt‬أي حساب الجذر التربيعي لعدد ما‪ .‬بإمكانك االستعانة‬ ‫بالعملية ‪ Sqrt‬التابعة لفئة الخدمة ‪.Math‬‬ ‫تمرين رقم ‪3‬‬ ‫أضف أزرارا الى اآللة الحاسبة لحساب الدوال الهندسية )‪ (Sin, Cos, Tan‬عليك كتابة معالج حدث‬ ‫واحد فقط لهذه الدوال باسم ‪ ..OnGeometricClick‬بإمكانك االستعانة بالعمليات الهندسية التابعة‬ ‫لفئة الخدمة ‪ .Math‬انتبه الى أن هذه الدوال تطلب أن تكون الزوايا ال ُممرة لها كبارامترات بالرادين‬ ‫)‪ (Radians‬وليس بالدرجات )‪ .(Degrees‬لتحويل الدرجات الى رادين عليك ضرب القيمة بـ‬ ‫‪.Math.PI/180‬‬ ‫لمزيد من المعلومات‪:‬‬ ‫‪http://msdn.microsoft.com/en-us/library/system.math.cos.aspx‬‬ ‫تمرين رقم ‪4‬‬ ‫أكمل اآللة الحاسبة بحيث تعمل جميع األزرار كما يجب‪.‬‬ ‫الحظ أنه بإمكان المستخدم استعمال لوحة المفاتيح إلدخال األعداد‪ .‬األداة تدعم االدخال عبر لوحة‬ ‫المفاتيح بدون الحاجة الى أية برمجة اضافية‪.‬‬

‫‪64‬‬


‫األداة ‪PictureBox‬‬ ‫ال تخلو التطبيقات التي نستعملها يوميا من الصور‪ .‬لذلك توفر ‪ VB.NET‬عدة امكانيات الدراج‬ ‫وعرض الصور في النماذج‪ .‬من هذه االمكانيات األداة ‪ PictureBox‬التي يوحي اسمها بأنها عبارة‬ ‫عن صندوق صورة أي عبارة عن إطار قادر على احتواء صورة وعرضها لل ُمستخدم‪ .‬لتوضيح‬ ‫كيفية استعمال هذه األداة سنقوم بتطوير نموذج يعرض صورا لكلمات باللغة االنجليزية يختارها‬ ‫ال ُمستخدم بحيث تُعرض الصورة المناسبة كلما اختار ال ُمستخدم كلمة معينة‪.‬‬ ‫توضح الصورة التالية تصميم النموذج المطلوب‪:‬‬ ‫كلما ضغط ال ُمستخدم على أحد األزرار األربعة تظهر الصورة المناسبة‪.‬‬

‫‪65‬‬


‫توفر ‪ VB.NET‬امكانية خاصة لحفظ الصور ضمن المشروع بحيث تصبح جزءا من التطبيق وذلك‬ ‫من خالل اضافة الصور التي سنستعملها في التطبيق الى ملف مصادر خصوصي ويُسمى‬ ‫‪ .Resources File‬للقيام بذلك علينا تنفيذ الخطوات التالية‪:‬‬ ‫افتح نافذة الـ ‪ Solution Explorer‬ثم اختر اسم المشروع في هذه النافذة‬ ‫اختر من القائمة الرئيسية ‪ Project‬في الـ ‪ Visual Studio‬األمر ‪ .Properties‬الحظ أن اسم‬ ‫المشروع جزء من اسم األمر ‪ .Properties‬مثال مشروعي اسمه ‪ .PictureBox_App‬لذلك اسم‬ ‫األمر هو ‪:PictureBox_App Properties‬‬

‫ثم اختر من النافذة التي تظهر األمر ‪ Resources‬في الجهة اليسرى كم هو ُمبين في الصورة‬

‫‪66‬‬


‫ثم قم بواسطة الـ ‪ Windows Explorer‬باختيار ملفات الصور التي تريد اضافتها ثم سحبها‬ ‫ورميها على نافذة الـ ‪ .Resources‬بعدها سترى أن الصور اضيفت الى المصادر كما تُبين الصورة‬ ‫التالية‪:‬‬

‫‪67‬‬


‫ لألربعة أزرار الموجودة في النموذج‬Click ‫اآلن بامكاننا برمجة معالج الحدث‬ Private Sub ShowPicture(sender As System.Object, e As System.EventArgs) Handles ButtonOrange.Click, ButtonKiwi.Click, ButtonBanana.Click, ButtonApple.Click Dim btn As Button btn = CType(sender, Button) If btn.Text = "Apple" Then PictureBox1.Image = My.Resources.Apple ElseIf btn.Text = "Orange" Then PictureBox1.Image = My.Resources.Orange ElseIf btn.Text = "Banana" Then PictureBox1.Image = My.Resources.Banana ElseIf btn.Text = "Kiwi" Then PictureBox1.Image = My.Resources.Kiwi End If End Sub

‫شرح البرمجة‬ ‫ لنعرف النص المكتوب عليه‬Button ‫ الى‬sender ‫أوال نقوم بتحويل البارامتر‬ Dim btn As Button btn = CType(sender, Button)

‫ الكلمة‬.‫ والموجودة في المصادر‬Apple ‫ نقوم باظهار الصورة المسماة‬Apple ‫إذا كان النص الكلمة‬ ‫ تابعة‬Resources ‫ توصلنا الى المصادر وهي أي المصادرعبارة عن خاصيّة باسم‬My ‫المحجوزة‬ ‫ لديها‬PictureBox ‫ الحظ أيضا أن األداة‬.Apple ‫ وهي تحوي بداخلها صورة باسم‬My ‫للكائن‬ :‫ قادرة على أخذ الصورة ال ُمراد عرضها‬Image ‫خاصيّة باسم‬ If btn.Text = "Apple" Then PictureBox1.Image = My.Resources.Apple

.‫ثم نقوم بنفس األمر لكل زر من األزرار‬

ListBox ‫األداة‬ ‫ التي ُشرحت سابقًا باستثناء أنها تكون دائما مفتوحة‬ComboBox ‫هذه األداة شبيهة جدا باألداة‬ ‫ الظهار باقي المحتوى أو للتنقل‬.‫وتُظهر كل المحتوى الذي يُمكن اظهاره بحسب ارتفاع األداة‬ ‫ هنالك شريط‬.‫ خاص لهذا الغرض‬Scrolling ‫ومعاينة محتوى األداة بامكان األداة اظهار شريط‬ .Vertical Scrolling Bar ‫ وآخر عامودي‬Horizontal Scrolling Bar ‫أفقي‬ ‫مثال‬ 68


‫‪Stack Simulator‬‬ ‫نُريد استعمال هذه األداة الظهار كيفية عمل مبنى المعلومات "ال ّراصة"‪ .‬يوفر هذا المبنى كما هو‬ ‫معلوم مجموعة من العمليات التي تضمن أن يكون اخراج وادخال المعلومات من والى رأس‬ ‫الرّاصة‪ .‬وعليه فان آخر قيمة أُدخلت تكون أول قيمة تُخرج أي ‪.LIFO – Last In First Out‬‬ ‫بعض عمليات المبنى "ال ّراصة"‬ ‫العملية‬

‫الشرح‬ ‫تُدخل المعلومة ‪ X‬الى رأس الرّاصة‬

‫)‪Public Sub Push(X As Object‬‬

‫تُخرج المعلومة الموجودة في رأس ال ّراصة‬

‫‪Public Function Pop() As Object‬‬

‫تُعيد المعلومة الموجودة في رأس ال ّراصة بدون اخراجها‬

‫‪Public Function Top() As Object‬‬

‫تُعيد حجم ال ّراصة‬

‫‪Public Function Size() As Integer‬‬

‫نقترح التصميم التالي‬

‫‪ListBox Control‬‬

‫• الحظ أننا جعلنا صندوق النص‪ ،‬الذي سيعرض نتيجة تنفيذ عملية من عمليات الرّاصة‪،‬‬ ‫للقراءة فقط من خالل اعطاء الخاصية ‪ ReadOnly‬التابعة لـ ‪ TextBox‬القيمة ‪.True‬‬

‫‪69‬‬


‫• إذا كان صندوق االدخال ‪ TextBoxInput‬فارغا حينها سيكون الزر ‪ Push‬غير قابل‬ ‫للضغط عليه أي سنعطي الخاصية ‪ Enabled‬القيمة ‪ .False‬سنغير هذه الخاصية إذا تغير‬ ‫محتوى الصندوق ولم يعد فارغا وذلك من خالل معالجة الحدث ‪ TextChanged‬التابع لـ‬ ‫‪ .TextBox‬يحصل هذا الحدث كلما تغير محتوى الصندوق‪.‬‬ ‫• إذا كانت الرّاصة فارغة حينها سيكون الزران ‪ Pop‬و‪ Top‬غير قابلين للضغط عليهما أي‬ ‫سنعطي الخاصية ‪ Enabled‬القيمة ‪ .False‬سنغير هذه الخاصية إذا تغير محتوى الرّاصة‬ ‫ولم تعد فارغة‪ .‬يحصل هذا في معالج الحدث ‪ Click‬التابع للزر ‪.Push‬‬ ‫سنتحكم بعملية االدخال بحيث تكون الى رأس الرّاصة من خالل استعمال العملية ‪ Insert‬التابعة‬ ‫للخصية ‪ Items‬التابعة لـ ‪:ListBox‬‬ ‫) ‪Public Sub Insert ( index As Integer, item As Object‬‬ ‫العملية تُضيف المعلومة ‪ item‬الى المكان رقم ‪ index‬في الـ ‪ .ListBox‬من أجل اضافة ‪ item‬الى‬ ‫رأس الرّاصة نستدعي ‪ Insert‬للمكان رقم ‪:0‬‬ ‫)‪ListBoxStack.Items.Insert(0, TextBoxInput.Text‬‬ ‫أما عملية االخراج من رأس الرّاصة فستكون من خالل استعمال العملية ‪ RemoveAt‬التابعة‬ ‫للخصية ‪ Items‬التابعة لـ ‪:ListBox‬‬ ‫)‪Public Sub RemoveAt ( index As Integer‬‬ ‫العملية تحذف المعلومة الموجودة في المكان رقم ‪ index‬من الـ ‪ .ListBox‬من أجل حذف المعلومة‬ ‫الموجودة في رأس الرّاصة نستدعي ‪ RemoveAt‬للمكان رقم ‪:0‬‬ ‫)(‪TextBoxOutput.Text = ListBoxStack.Items(0).ToString‬‬ ‫)‪ListBoxStack.Items.RemoveAt(0‬‬ ‫أي أننا نضيف فقط الى المكان رقم ‪ 0‬ونحذف أيضا فقط من المكان رقم ‪.0‬‬ ‫الحظ أن العملية ‪ RemoveAt‬عبارة عن اجراء وليس دالة أي أنها ال تُعيد القيمة التي تم حذفها‪.‬‬ ‫لذلك أخذنا أوال القيمة الموجودة في )‪ Items(0‬وحفظناها في الصندوق ‪ TextBoxOutput‬ثم‬ ‫حذفناها‪.‬‬ ‫‪70‬‬


:‫واليكم معالجات األحداث التي تشكل الحل‬ Private Sub TextBoxInput_TextChanged(sender As System.Object, e As System.EventArgs) Handles TextBoxInput.TextChanged ButtonPush.Enabled = TextBoxInput.Text <> "" End Sub Private Sub ButtonPush_Click(sender As System.Object, e As System.EventArgs) Handles ButtonPush.Click ListBoxStack.Items.Insert(0, TextBoxInput.Text) ButtonPop.Enabled = True ButtonTop.Enabled = True End Sub Private Sub ButtonPop_Click(sender As System.Object, e As System.EventArgs) Handles ButtonPop.Click TextBoxOutput.Text = ListBoxStack.Items(0).ToString() ListBoxStack.Items.RemoveAt(0) ButtonPop.Enabled = ListBoxStack.Items.Count > 0 ButtonTop.Enabled = ListBoxStack.Items.Count > 0 End Sub Private Sub ButtonTop_Click(sender As System.Object, e As System.EventArgs) Handles ButtonTop.Click TextBoxOutput.Text = ListBoxStack.Items(0).ToString() End Sub Private Sub ButtonSize_Click(sender As System.Object, e As System.EventArgs) Handles ButtonSize.Click TextBoxOutput.Text = ListBoxStack.Items.Count.ToString + " item(s)" End Sub Private Sub ButtonClose_Click(sender As System.Object, e As System.EventArgs) Handles ButtonClose.Click Me.Close() End Sub

71


‫تمرين رقم ‪5‬‬ ‫‪Queue Simulator‬‬ ‫المطلوب استعمال هذه األداة الظهار كيفية عمل مبنى المعلومات "قائمة االنتظار" أو ما يُسمى أيضا‬ ‫"الطابور"‪ .‬يوفر هذا المبنى كما هو معلوم مجموعة من العمليات التي تضمن أن يكون ادخال‬ ‫المعلومات الى نهاية الطابور‪ .‬أما اخراج المعلومات فيجب أن يتم من رأس الطابور‪ .‬وعليه فان أول‬ ‫قيمة أُدخلت تكون أول قيمة تُخرج أي ‪.FIFO – First In First Out‬‬ ‫بعض عمليات المبنى "قائمة االنتظار"‬ ‫العملية‬

‫الشرح‬ ‫تُدخل المعلومة ‪ X‬الى نهاية الطابور‬

‫)‪Public Sub Insert(X As Object‬‬

‫تُخرج المعلومة الموجودة في رأس الطابور‬

‫‪Public Function Remove() As Object‬‬

‫تُعيد المعلومة الموجودة في رأس الطابور بدون اخراجها‬

‫‪Public Function Head() As Object‬‬

‫تُعيد حجم الطابور‬

‫‪Public Function Size() As Integer‬‬

‫بامكان التصميم أن يكون مشابها لتصميم نموذج الرّاصة‪.‬‬ ‫الحظ أن االدخال سيكون الى المكان رقم ‪ .Items.Count‬أما االخراج فسيكون من المكان رقم ‪.0‬‬ ‫• يجب جعل صندوق النص‪ ،‬الذي سيعرض نتيجة تنفيذ عملية من عمليات الطابور‪ ،‬للقراءة فقط‬ ‫من خالل اعطاء الخاصية ‪ ReadOnly‬التابعة لـ ‪ TextBox‬القيمة ‪.True‬‬ ‫• إذا كان صندوق االدخال ‪ TextBoxInput‬فارغا حينها سيكون الزر ‪ Insert‬غير قابل للضغط‬ ‫عليه أي سنعطي الخاصية ‪ Enabled‬القيمة ‪ .False‬يجب تغيير هذه الخاصية إذا تغير محتوى‬ ‫الصندوق ولم يعد فارغا وذلك من خالل معالجة الحدث ‪ TextChanged‬التابع لـ ‪.TextBox‬‬ ‫• إذا كان الطابور فارغا حينها سيكون الزران ‪ Remove‬و‪ Head‬غير قابلين للضغط عليهما أي‬ ‫سنعطي الخاصية ‪ Enabled‬القيمة ‪ .False‬سنغير هذه الخاصية إذا تغير محتوى الطابور ولم‬ ‫يعد ا يحصل هذا في معالج الحدث ‪ Click‬التابع للزر ‪.Insert‬‬

‫‪72‬‬


‫تمرين رقم ‪6‬‬ ‫‪Evens And Odds‬‬ ‫نريد أن نبرمج نموذجًا يُمكن ال ُمستخدم من فرز األعداد الفردية واألعداد الزوجية‪ .‬على ال ُمستخدم أن‬ ‫يبقي في احدى القوائم )‪ (ListBox‬األعداد الفردية وفي األخرى الزوجية‪ .‬النموذج يُوفر زرين‪،‬‬ ‫واحدا لنقل أسطر من قائمة األعداد الفردية الى قائمة األعداد الزوجية وزرا للعملية العكسية‪.‬‬ ‫التصميم ال ُمقترح‬

‫• عنما يظهر النموذج تكون القائمة ‪ Evens‬محتوية على ‪ 10‬أعداد طبيعية (زوجية وفردية)‬ ‫عشوائية من المجال ]‪[1,100‬‬ ‫• على ال ُمستخدم اختيار األعداد الفردية الموجودة في القائمة ‪ Evens‬ونقلها بواسطة الضغط‬ ‫على الزر >== الى القائمة ‪Odds‬‬ ‫• إذا أخطأ ال ُمستخدم بنقل بعض األعداد الزوجية الى القائمة ‪ Odds‬بامكانه اختيارهم‬ ‫واعادتهم الى القائمة ‪Evens‬‬ ‫• الضغط على الزر ‪ New Numbers‬يؤدي الى تعبئة القائمة ‪ Evens‬بعشرة أعداد جديدة‬ ‫طبيعية (زوجية وفردية) عشوائية من المجال ]‪[1,100‬‬

‫‪73‬‬


Label ‫ يفحص محتوى القائمتين ويكتب رسالة مناسبة في الـ‬Check ‫• الضغط على الزر‬ ‫ خالف ذلك تُكتب رسالة خطأ باللون األحمر‬.‫ باللون األزرق‬Result ‫ال ُمسمى‬ .New Numbers ‫• يجب محو رسالة النتيجة كلما ضغط ال ُمستخدم على الزر‬ ‫ علينا أن نعطي الخاصيّة‬ListBox ‫لتمكين ال ُمستخدم من اختيار أكثر من سطر في الـ‬ ‫ حينها على ال ُمستخدم الضغط على ال ُمفتاح‬.MultiSimple ‫ التابعة له القيمة‬SelectionMode .‫ بشكل ُمستمر خالل اختيار األسطر‬Ctrl ‫البرمجة‬ Public Class FormMain Private Sub ButtonNew_Click(sender As System.Object, e As System.EventArgs) Handles ButtonNew.Click ‫تغيير لون خط النتيجة الى األسود‬ LabelResult.ForeColor = Color.Black ‫وحذف النتيجة السابقة‬ LabelResult.Text = "Result: " ListBoxEvens ‫ومن ثم تعبئة القائمة‬ Fill() End Sub Private Sub Fill() ListBoxOdds.Items.Clear() ‫تفريغ القائمتين‬ ListBoxEvens.Items.Clear() ListBoxEvens ‫ومن ثم تعبئة القائمة‬ Dim Rnd As New Random .‫بالقيم العشوائية‬ Dim i As Integer For i = 1 To 10 ListBoxEvens.Items.Add(Rnd.Next(1, 101)) Next End Sub Private Sub ButtonToOdds_Click(sender As System.Object, e As System.EventArgs) Handles ButtonToOdds.Click While ListBoxEvens.SelectedItems.Count > 0 SelectedItems ‫الخاصيّة‬ ListBoxOdds.Items.Add(ListBoxEvens.SelectedItems(0).ToString) .‫تحوي جميع العناصر ال ُمختارة‬ ListBoxEvens.Items.Remove(ListBoxEvens.SelectedItems(0)) ‫الحظ أننا ننقل دائما العنصر‬ End While ‫ ثم نحذفه فيؤدي‬0 ‫ال ُمختار رقم‬ End Sub ‫ذلك الى خروجه من القائمة‬ ‫وأيضا من الخاصيّة‬ Private Sub ButtonToEvens_Click(sender As System.Object, ‫ نُكرر ذلك‬.SelectedItems e As System.EventArgs) ‫حتى ال تبقى أية عناصر ُمختارة‬ Handles ButtonToEvens.Click .0 ‫أي يصبح عددهم‬ While ListBoxOdds.SelectedItems.Count > 0 ListBoxEvens.Items.Add(ListBoxOdds.SelectedItems(0).ToString) ListBoxOdds.Items.Remove(ListBoxOdds.SelectedItems(0)) End While End Sub

74


Private Sub ButtonCheck_Click(sender As System.Object, e As System.EventArgs) Handles ButtonCheck.Click If ListBoxEvens.Items.Count = 0 And ListBoxOdds.Items.Count = 0 Then Exit Sub End If Dim i, Num As Integer ' All items in ListBoxEvens MUST be even For i = 0 To ListBoxEvens.Items.Count - 1 Num = Integer.Parse(ListBoxEvens.Items(i).ToString()) If Num Mod 2 <> 0 Then LabelResult.ForeColor = Color.Red LabelResult.Text = "Error. Try Again!" Exit Sub End If Next ' All items in ListBoxOdds MUST be odd For i = 0 To ListBoxOdds.Items.Count - 1 Num = Integer.Parse(ListBoxOdds.Items(i).ToString()) If Num Mod 2 <> 1 Then LabelResult.ForeColor = Color.Red LabelResult.Text = "Error. Try Again!" Exit Sub End If Next LabelResult.ForeColor = Color.Blue LabelResult.Text = "Wow. Perfect!" End Sub End Class

75


‫األدوات ‪ RadioButton‬و ‪CheckBox‬‬ ‫توفر ‪ VB.NET‬هاتين األداتين لتمكين ال ُمستخدم من اختيار امكانية واحدة فقط من عدة امكانيات من‬ ‫خالل استعمال األداة ‪ .RadioButton‬أو اختيار عدة امكانيات من عدة امكانيات بمساعدة األداة‬ ‫‪ .CheckBox‬هذه األدوات لديها وضعان‪ :‬اما أن تكون ُمختارة (أي ‪ )Checked‬أو غير ُمختارة‪.‬‬ ‫لذلك فهي توفر خاصيّة بوليانية باسم ‪ Checked‬لمعرفة ذلك‪ .‬تكون قيمة هذه الخاصيّة ‪ True‬إذا‬ ‫كانت األداة ُمختارة‪ .‬خالف ذلك تكون قيمتها ‪.False‬‬ ‫صورة األداة ‪ CheckBox‬وهي غير ُمختارة‬

‫وصورتها وهي ُمختارة‬

‫أما األداة ‪ RadioButton‬فهي تظهر كالتالي‪:‬‬

‫تستعمل التطبيقات ال ُمختلفة عادة أكثر من أداة ‪ RadioButton‬واحدة كمجموعة اختيارات يتم‬ ‫وضعها ضمن ‪ GroupBox‬مما يُكسبها صفة المجموعة التي يُمكن اختيار واحدة منها فقط‪ .‬أي أن‬ ‫النقطة التي تكون في الدائرة تظهر عند أداة واحدة من المجموعة وإذا ضغط ال ُمستخدم على اداة‬ ‫أخرى من نفس المجموعة تنتقل النقطة اليها أي يتم اختيارها هي والغاء االختيار السابق‪.‬‬ ‫الحظ أنه بامكاننا تصميم النموذج األخير لمعرفة جنس ال ُمستخدم كالتالي‪:‬‬

‫‪76‬‬


‫فاألداة ‪ CheckBoxFemale‬اما أن تكون ُمختارة فيعني ذلك ‪ Female‬أو أن تكون غير ُمختارة‬ ‫فيعني ذلك ‪.Male‬‬ ‫مثال‬ ‫نريد تصميم نموذج يُمكننا من معرفة لُغات البرمجة المختلفة التي يتقنها ال ُمستخدم‪.‬‬ ‫التصميم ال ُمقترح‬

‫بامكان النموذج حساب عدد النقاط الكلي التي يحصل عليها ال ُمستخدم بحيث يُعطى لكل لغة يتقنها ‪25‬‬ ‫نقطة‪.‬‬ ‫مثال ال ُمستخدم التالي حصل على ‪ 75‬نقطة ألنه يعرف ‪ 3‬لغات فقط‪:‬‬

‫‪77‬‬


Calculate Points ‫ للزر‬Click ‫برمجة معالج الحدث‬ Private Sub ButtonCalc_Click(sender As System.Object, e As System.EventArgs) Handles ButtonCalc.Click Dim Points As Integer = 0 ‫ نقطة إذا تم‬25 ‫أضف‬ If CheckBoxVB_NET.Checked Then VB.NET ‫اختيار‬ Points += 25 ‫وهكذا بالنسبة لباقي‬ End If ‫االختيارات‬ If CheckBoxCSharp.Checked Then Points += 25 End If If CheckBoxJava.Checked Then Points += 25 End If If CheckBoxCPP.Checked Then Points += 25 End If LabelPoints.Text = "Number Of Points: " + Points.ToString End Sub

‫مثال‬

78


‫نريد تصميم نموذج يُمكن طالبا ما من التدرب على حل مسائل جمع أعداد صحيحة‪ .‬البرنامج ينشئ‬ ‫مسائل حسابية بشكل عشوائي من المجال ]‪ [10,100‬ويقترح ‪ 4‬حلول على شكل األسئلة األمريكية‪.‬‬ ‫بامكان ال ُمستخدم الضغط على زر ‪ Check My Answer‬لفحص االجابة‪ .‬البرنامج يُظهر صورة‬ ‫مناسبة تبين هل كانت االجابة صحيحة أم ال ويظهر لكل سؤال رقمه التسلسلي‪ .‬ال ُمستخدم يطلب من‬ ‫البرنامج أن ينشئ سؤاال جديدا من خالل الضغط على زر ‪.Generate A New Question‬‬ ‫السؤال األول يتم انشاؤه عند تشغيل التطبيق‪ .‬األجوبة الثالثة الخطأ سيتم انشاؤها عشوائيا من المجال‬ ‫]‪ .[CorrectAnswer+1, CorrectAnswer+10‬ترتيب األجوبة سيكون أيضا عشوائيا قدر‬ ‫االمكان بحيث ال تظهر االجابة الصحيحة دائما في نفس األداة (أي االجابة األولى مثال أو الثانية‬ ‫وهكذا)‪ .‬البرنامج يقوم أيضا بترقيم األسئلة بشكل تسلسلي‪.‬‬ ‫التصميم ال ُمقترح‬ ‫هنا االجابة صحيحة‪ .‬لذلك تظهرعند فحص السؤال من خالل الضغط على الزر ‪Check‬‬ ‫‪ MyAnswer‬الصورة التي تدل على أن االجابة صحيحة‪.‬‬

‫‪79‬‬


‫بينما هنا االجابة غيرصحيحة‪ .‬لذلك تظهرعند فحص السؤال من خالل الضغط على الزر ‪Check‬‬ ‫‪ MyAnswer‬الصورة التي تدل على أن االجابة غير صحيحة‪.‬‬

‫يصف الجدول التالي بعض األدوات ال ُمستعملة في هذا النموذج‬ ‫األداة‬

‫االسم أو الـ ‪ID‬‬

‫الشرح‬

‫‪Button‬‬

‫‪ButtonNewQuestion‬‬

‫لطلب انشاء سؤال جديد‬

‫‪GroupBox‬‬

‫‪GroupBoxQuestionNr‬‬

‫‪PictureBox‬‬

‫‪PictureBoxAnswer‬‬

‫‪Label‬‬

‫‪LabelQuestion‬‬

‫الظهار السؤال الحالي‬

‫‪RadioButton‬‬

‫‪RadioButtonA‬‬

‫االجابة األولى‬

‫‪RadioButton‬‬

‫‪RadioButtonB‬‬

‫االجابة الثانية‬

‫‪RadioButton‬‬

‫‪RadioButtonC‬‬

‫االجابة الثالثة‬

‫‪RadioButton‬‬

‫‪RadioButtonD‬‬

‫االجابة الرابعة‬

‫‪Button‬‬

‫‪ButtonCheckAnswer‬‬

‫الظهار رقم السؤال الحالي‬ ‫الظهار صورة معبرة عن‪ :‬هل‬ ‫كانت االجابة صحيحة أم ال‪.‬‬

‫‪80‬‬

‫لطلب فحص االجابة‬


‫شرح لبعض العمليات ال ُمساعدة‬ ‫()‪Private Sub GenerateNewQuestion‬‬ ‫ادعاء الدخول‪:‬‬ ‫ادعاء الخروج‪ :‬تقوم بانشاء سؤال عشوائي جديد من المجال ]‪ [1,100‬وتشكيل األجوبة الخاطئة الى جانب االجابة‬ ‫الصحيحة‪ .‬ثم تقوم بتوزيع األجوبة بشكل عشوائي على أدوات الـ ‪ RadioButton‬ال ُمعدة لالجابات‪.‬‬

‫)(‪Private Sub ResetControls‬‬ ‫ادعاء الدخول‪:‬‬ ‫ادعاء الخروج‪ :‬تقوم بازالة أي اختيار من أدوات الـ ‪ RadioButton‬ال ُمعدة لالجابات‪ .‬أي أنها تحذف اجابة السؤال‬ ‫السابق‪.‬‬

‫)‪Private Sub FillArray(ByVal A() As Integer‬‬ ‫ادعاء الدخول‪ :‬تتلقى مصفوفة األجوبة‪ .‬هذه المصفوفة فيها فقط في الخلية األولى االجابة الصحيحة‪ .‬باقي القيم سالبة‪.‬‬ ‫ادعاء الخروج‪ :‬تقوم بتعبئة باقي خاليا المصفوفة بقيم عشوائية من المجال‬ ‫[‪ . ]A(0)+1, A(0)+10‬هذه القيم تمثل االجابات الخاطئة‪ .‬العملية تمنع تكرار نفس االجابة‪ .‬أي أن األجوبة ال‬ ‫تتكرر لتفس السؤال‪.‬‬

‫)‪Private Sub Randomize(ByVal A() As Integer‬‬ ‫ادعاء الدخول‪ :‬تتلقى مصفوفة األجوبة‪.‬‬ ‫ادعاء الخروج‪ :‬تقوم بتغيير أماكن األجوبة بشكل عشوائي‪.‬‬

‫)(‪Private Sub CheckAnswer‬‬ ‫ادعاء الدخول‪:‬‬ ‫ادعاء الخروج‪ :‬تقوم بفحص االجابة التي اختارها ال ُمستخدم وتقارنها مع االجابة الصحيحة وتظهر صورة معبرة عن‬ ‫نتيجة الفحص‪.‬‬

‫احرص على اضافة صورتين من اختيارك الى ‪ My.Resources‬كما ُشرح سابقا عند األداة‬ ‫‪ .PictureBox‬واحدة تُعبر عن اجابة صحيحة مثال مكتوب عليها ‪ Correct‬أو صحيح أو أي كلمة‬ ‫أو رمز آخر‪ .‬واألخرى مكتوب عليها ‪ Wrong‬أو خطأ أو أي كلمة أو رمز آخر‪.‬‬ ‫البرمجة‬ ‫في البداية نقوم بتعريف ع ّداد لرقم السؤال ونصفره‪ .‬التعريف يكون على مستوى فئة النموذج‪.‬‬ ‫‪Public Class FormSimpleMathTrainer‬‬ ‫‪Private QuestionNr As Integer = 0‬‬ ‫‪End Class‬‬

‫‪81‬‬


‫ بانشاء السؤال األول قبل ظهور النموذج‬GenerateNewQuestion() ‫ثم نقوم بمساعدة العملية‬ ‫ التابع للنموذج‬Load ‫لل ُمستخدم في معالج الحدث‬ Private Sub FormSimpleMathTrainer_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load GenerateNewQuestion() End Sub

‫واليكم البرمجة الكاملة للتطبيق‬ Public Class FormSimpleMathTrainer Private QuestionNr As Integer = 0 Private Sub ButtonNewQuestion_Click(sender As System.Object, e As System.EventArgs) Handles ButtonNewQuestion.Click GenerateNewQuestion() End Sub Private Sub GenerateNewQuestion() QuestionNr += 1 GroupBoxQuestionNr.Text = "Question Nr " + QuestionNr.ToString PictureBoxAnswer.Visible = False Dim R As New Random Dim X, Y, CorrectAnswer As Integer X = R.Next(10, 101) Y = R.Next(10, 101) CorrectAnswer = X + Y LabelQuestion.Text = X.ToString + " + " + Y.ToString() Dim Answers(3) As Integer Answers ‫هنا نستعمل المصفوفة األحادية‬ Answers(0) = CorrectAnswer ‫ استعمال المصفوفة يُمكننا من‬.‫لتخزين األجوبة‬ FillArray(Answers) ‫خلط أماكن األجوبة بشكل عشوائي بحيث ال‬ Randomize(Answers) .‫تظهر االجابة الصحيحة دائما في نفس المكان‬ RadioButtonA.Text = Answers(0) ‫بعد الخلط نوزع األجوبة على أدوات االجابة أي‬ RadioButtonB.Text = Answers(1) ‫ وأخيرا نقوم بازالة‬.RadioButtons ‫على الـ‬ RadioButtonC.Text = Answers(2) .‫االجابة األخيرة‬ RadioButtonD.Text = Answers(3) ResetControls() End Sub

Private Sub ResetControls() ‫هذه العملية تقوم بازالة أي اختيار من أدوات الـ‬ .‫ ال ُمعدة لالجابات‬RadioButton

RadioButtonA.Checked = False RadioButtonB.Checked = False RadioButtonC.Checked = False RadioButtonD.Checked = False End Sub

82


Private Sub Randomize(ByVal A() As Integer) Dim R As New Random Dim i, j As Integer For i = A.Length - 1 To 1 Step -1 j = R.Next(0, i) Swap(A, i, j) Next

‫هذه العملية تقوم بتغيير أماكن األجوبة بشكل‬ j ‫ الحظ أننا نقوم بانشاء رقم الخلية‬.‫عشوائي‬ .Swap ‫بشكل عشوائي وتمريره للعملية‬

End Sub Private Function Exists(ByVal A() As Integer, ByVal x As Integer) As Boolean For i = 0 To A.Length - 1 If A(i) = x Then Return True End If Next Return False End Function Private Sub FillArray(ByVal A() As Integer) Dim Rnd As New Random Dim x As Integer For i = 1 To A.Length - 1 x = Rnd.Next(A(0) + 1, A(0) + 11) While Exists(A, x) And i < A.Length x = Rnd.Next(A(0) + 1, A(0) + 11) End While A(i) = x Next

‫ أي‬0 ‫االجابة الصحيحة موجودة في الخلية رقم‬ .A(0) ‫العملية تقوم بتعبئة باقي خاليا المصفوفة بقيم‬ ‫عشوائية من المجال‬ ‫ هذه القيم تمثل‬. ]A(0)+1, A(0)+10[ ‫ العملية تمنع تكرار نفس‬.‫االجابات الخاطئة‬ .‫ أي أن األجوبة ال تتكرر لتفس السؤال‬.‫االجابة‬

End Sub

Private Sub Swap(ByVal A() As Integer, ByVal i As Integer, ByVal j As Integer) Dim Temp As Integer Temp = A(i) A(i) = A(j) A(j) = Temp End Sub

83


Private Sub ButtonCheckAnswer_Click(sender As System.Object, e As System.EventArgs) Handles ButtonCheckAnswer.Click CheckAnswer() End Sub Private Sub CheckAnswer() Dim X, Y, CorrectAnswer, UsersAnswer As Integer Dim Q As String = LabelQuestion.Text X = Integer.Parse(Q.Substring(0, Q.IndexOf(" "))) Y = Integer.Parse(Q.Substring(Q.IndexOf("+") + 1)) CorrectAnswer = X + Y If RadioButtonA.Checked Then UsersAnswer = Integer.Parse(RadioButtonA.Text) ElseIf RadioButtonB.Checked Then UsersAnswer = Integer.Parse(RadioButtonB.Text) ElseIf RadioButtonC.Checked Then UsersAnswer = Integer.Parse(RadioButtonC.Text) ElseIf RadioButtonD.Checked Then UsersAnswer = Integer.Parse(RadioButtonD.Text) End If PictureBoxAnswer.Visible = True If UsersAnswer = CorrectAnswer Then PictureBoxAnswer.Image = My.Resources.Correct Else PictureBoxAnswer.Image = My.Resources.Wrong End If

‫ من‬Y ‫ وقيمة‬X ‫هنا نستخلص قيمة‬ ‫نص السؤال‬ LabelQuestion.Text

‫هنا نجد االجابة التي اختارها‬ .‫ال ُمستخدم‬

‫إذا كانت االجابة صحيحة نُظهر‬ ‫ خالف ذلك‬.Correct ‫الصورة‬ .Wrong ‫نُظهر الصورة‬

End Sub Private Sub FormSimpleMathTrainer_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load GenerateNewQuestion() End Sub Private Sub ButtonClose_Click(sender As System.Object, e As System.EventArgs) Handles ButtonClose.Click Me.Close() End Sub End Class

84


‫تمرين رقم ‪7‬‬ ‫أضف الى نموذج المثال السابق للتدرب على عملية الجمع االمكانيات التالية‪:‬‬ ‫اختيار مجال األعداد‬ ‫اختيار العملية التي يريد ال ُمستخدم التدرب عليها من بين العمليات ‪+, -, *, /‬‬

‫العملية ‪MessageBox.Show‬‬ ‫توفر هذه العملية امكانية الظهار نافذة حوار من التطبيق لل ُمستخدم البالغة رسالة معينة (أي‬ ‫‪ )Message‬أو سؤاله عن أمر ما بحيث أن االجابة على السؤال تتحكم في مجرى تنفيذ التطبيق‪.‬‬ ‫تتلقى هذه العملية عدة بارامترات تحدد مبنى ومحتوى نافذة الحوار‪.‬‬ ‫أمثلة‬ ‫االستدعاء التالي يتلقى فقط نص الرسالة "!‪"Hi, I am a simple MessageBox‬‬ ‫)"!‪MessageBox.Show("Hi, I am a simple MessageBox‬‬

‫ويظهر النافذة التالية‬

‫االستدعاء التالي يتلقى الى جانب نص الرسالة "!‪ "Hi, I am a simple MessageBox‬العنوان‬ ‫"‪"Sample 2‬‬ ‫)"‪MessageBox.Show("Hi, I am a simple MessageBox!", "Sample 2‬‬

‫ويظهر النافذة التالية‬

‫‪85‬‬


"Confirmation" ‫ العنوان‬Are You Sure?" ‫االستدعاء التالي يتلقى الى جانب نص الرسالة‬ No ‫ والزر‬Yes ‫ هنا نريد الزر‬.‫ويحدد األزرار التي يريدها في نافذة الحوار‬ MessageBox.Show("Are You Sure?", "Confirmation", MessageBoxButtons.YesNo)

‫ويظهر النافذة التالية‬

:‫األزرار التي يُمكننا اضافتها الى نافذة الحوار هي التالية‬ ‫األزرار‬

‫القيمة‬

Ignore ‫ وزر‬Retry ‫ وزر‬Abort ‫ زر‬MessageBoxButtons.AbortRetryIgnore ‫ فقط‬OK ‫ زر‬MessageBoxButtons.OK Cancel ‫ وزر‬OK ‫ زر‬MessageBoxButtons.OKCancel Cancel ‫ وزر‬Retry ‫ زر‬MessageBoxButtons.RetryCancel No ‫ وزر‬Yes ‫ زر‬MessageBoxButtons.YesNo Cancel ‫ وزر‬No ‫ وزر‬Yes ‫ زر‬MessageBoxButtons.YesNoCancel

‫كيف يُمكننا معرفة االجابة التي اختارها ال ُمستخدم؟‬ 86


‫ وهي واحدة من احدى القيم التالية بحسب األزرار‬DialogResult ‫تعيد هذه العملية قيمة من نوع‬ ‫التي تظهر في نافذة الحوار‬ • Windows.Forms.DialogResult.No • Windows.Forms.DialogResult.Abort • Windows.Forms.DialogResult.Retry • Windows.Forms.DialogResult.Ignore • Windows.Forms.DialogResult.OK • Windows.Forms.DialogResult.Cancel ‫مثال‬ Dim Res As DialogResult Res = MessageBox.Show("Are You Sure?", "Confirmation",MessageBoxButtons.YesNo) If Res = Windows.Forms.DialogResult.No Then ‫ يتم‬No ‫إذا أجاب ال ُمستخدم بـ‬ Exit Sub .‫مثال الخروج من االجراء‬ End If

"Confirmation" ‫" العنوان‬Are You Sure?" ‫االستدعاء التالي يتلقى الى جانب نص الرسالة‬ ‫ ويضيف صورة تُعبر‬No ‫ والزر‬Yes ‫ هنا نريد الزر‬.‫ويحدد األزرار التي يريدها في نافذة الحوار‬ ‫عن سؤال تظهر الى يسار نص الرسالة‬ MessageBox.Show("Are You Sure?", "Confirmation", MessageBoxButtons.YesNo, MessageBoxIcon.Question)

‫ويظهر النافذة التالية‬

87


:‫الصور التي يُمكننا اضافتها الى نافذة الحوار هي التالية‬ • MessageBoxIcon.Asterisk • MessageBoxIcon.Error • MessageBoxIcon.Exclamation • MessageBoxIcon.Hand • MessageBoxIcon.Information • MessageBoxIcon.Question • MessageBoxIcon.Stop • MessageBoxIcon.Warning .‫ التي تدل على طلب عدم اضافة صورة‬MessageBoxIcon.None ‫القيمة االفتراضية هي‬

88


‫تمرين رقم ‪8‬‬ ‫صمم تطبيقًا لجمع المعلومات عن مرشحين لوظائف معينة فيه األدوات التالية‪:‬‬

‫يُقبل المرشح إذا حصل على األقل على ‪ 30‬نقطة‪.‬‬ ‫كيفية توزيع النقاط‪:‬‬ ‫• المرشح المتزوج يحصل على ‪ 12‬نقطة‪ .‬خالف ذلك يحصل على ‪ 10‬نقاط‪.‬‬ ‫• المرشح الذي سنه أقل من ‪ 25‬سنة يحصل على ‪ 15‬نقطة‪.‬‬ ‫• المرشح الذي سنه بين ‪ 25‬و ‪ 45‬سنة يحصل على ‪ 20‬نقطة‪.‬‬ ‫• المرشح الذي تجاوز ‪ 45‬سنة يحصل على ‪ 13‬نقطة‪.‬‬ ‫• المرشح الذي له خبرة خارج البالد يحصل على ‪ 15‬نقطة‪ .‬مقابل خبرة داخل البالد يحصل‬ ‫على ‪ 10‬نقاط‪.‬‬ ‫عند النقر على الزر " افحص المعطيات" على النموذج أن يفحص أنه بالفعل تم اختيار الحالة‬ ‫الشخصية والجيل ومن ثم حساب عدد النقاط وكتابة النتيجة في صندوق النتيجة‪ .‬يجب كتابة النص‬ ‫"قُبل" أو " لم يُقبل" بنا ًء على عدد النقاط‪ .‬اذا لم يتم اختيار المعلومات الالزمة‪ ،‬على الصفحة أن‬ ‫تظهر نص خطأ من خالل استعمال ‪.MessageBox‬‬

‫‪89‬‬


‫عند النقر على الزر " المرشح التالي" على النموذج أن يزيل جميع األختيارات استعداداً ألستيعاب‬ ‫المعلومات عن المرشح التالي‪.‬‬ ‫أما عند النقر على الزر "النتائج النهائية" على الصفحة أن تظهر عدد المرشحين الكلي وعدد الذين تم‬ ‫قبولهم‪.‬‬

‫‪90‬‬


‫األداة ‪ListView‬‬ ‫تُمكننا هذه األداة من عرض المعلومات على هيئة جدول مكون من أعمدة بحيث يكون لكل عامود‬ ‫اسم خاص به‪.‬‬ ‫بعد اضافة األداة ‪ ListView‬الى النموذج نقوم بالضغط على السهم الذي يظهر في الزاوية اليمنى‬ ‫العليا من األداة لنفتح قائمة تمكننا من تحديد بعض خصائص األداة واضافة األعمدة اليها‪:‬‬

‫نختار من القائمة التي تظهر ‪ View‬من نوع ‪Details‬‬

‫‪91‬‬


‫ثم نضيف أعمدة من خالل الضغط على الرابط ‪ Edit Columns‬الموجود في القائمة والزر ‪Add‬‬

‫بعد الضغط على ‪ Add‬تظهر النافذة التالية‬

‫ثم نقوم بتغيير قيمة الحقل ‪ Name‬الى اسم مناسب مثال ‪( FullName‬الحظ أن هذا اسم متغير‬ ‫للعامود) والحقل ‪ Text‬نعطيه القيمة ‪ Full Name‬وهي القيمة التي ستظهر كعنوان للعامود‪ .‬الحظ‬ ‫أن العامود الجديد ظهر في القائمة ‪ Members‬التي في يسار النافذة‪ .‬ثم نضيف بهذه الطريقة جميع‬ ‫األعمدة التي نريد‪:‬‬

‫‪92‬‬


‫تُظهر النافذة أننا أضفنا ‪ 4‬أعمدة وهي ‪.FullName, Address, Age, EmailAddress‬‬ ‫الحظ أيضا أننا حددنا بأن يظهر عنوان كل عامود في الوسط من خالل الخاصية أو الحقل‬ ‫‪ TextAlign‬واعطائه القيمة ‪.Center‬‬ ‫إذا شغلنا النموذج ستظهر األداة كالتالي‬

‫أي تظهر كجدول مكون من ‪ 4‬أعمدة‪.‬‬ ‫اآلن نضيف الى النموذج ‪ 4‬صناديق نص الدخال القيم وزرا باسم ‪ Add‬الضافة سطر جديد الى الـ‬ ‫‪ ListView‬فيه القيم التي أُدخلت الى الصناديق‬

‫‪93‬‬


‫برمجة معالج الحدث ‪ Click‬للزر ‪Add‬‬ ‫هنالك عدة امكانيات الضافة أسطر الى األداة ‪ .ListView‬نناقش هنا امكانيتين‪ .‬الحقا سنعود لألداة‬ ‫لنستعملها لعرض معلومات من قاعدة بيانات‪.‬‬ ‫)‪Private Sub ButtonAdd_Click(sender As System.Object, e As System.EventArgs‬‬ ‫‪Handles ButtonAdd.Click‬‬ ‫ُن َعرّ ف مصفوفة أحادية من نوع ‪String‬‬ ‫‪Dim A(3) As String‬‬ ‫ثم ُن َخ ّزن فيها القيم الموجودة في صناديق‬ ‫‪A(0) = TextBoxFullName.Text‬‬ ‫النص‪.‬‬ ‫‪A(1) = TextBoxAddress.Text‬‬ ‫ثم ُن َع ّرف وننشئ كائنا من نوع‬ ‫‪A(2) = TextBoxAge.Text‬‬ ‫‪ .ListViewItem‬العملية البنائية تتلقى‬ ‫‪A(3) = TextBoxEmailAddress.Text‬‬ ‫المصفوفة كبارامتروتنقل قيم خالياها الى‬ ‫السطر الحالي بحيث ُتعطى قيمة الخلية‬ ‫‪Dim itm As ListViewItem‬‬ ‫األولى الى العامود األول والثانية الى الثاني‬ ‫)‪itm = New ListViewItem(A‬‬ ‫وهكذا‪.‬‬ ‫)‪ListViewStudentsDetails.Items.Add(itm‬‬ ‫‪End Sub‬‬

‫‪94‬‬


‫امكانية أخرى الضافة أسطر جديدة الى األداة‬ ‫)‪Private Sub ButtonAdd_Click(sender As System.Object, e As System.EventArgs‬‬ ‫‪Handles ButtonAdd.Click‬‬ ‫‪Dim itm As ListViewItem‬‬ ‫)(‪ListViewStudentsDetails.BeginUpdate‬‬

‫أوال ُنخبر األداة ببدء عملية تغيير محتواها‬ ‫نضيف قيم العامود األول‪ .‬هذه‬ ‫العملية تنشئ وتجهز الكائن‬ ‫بحيث يصبح صالحا لالستعمال‬

‫)‪itm = ListViewStudentsDetails.Items.Add(TextBoxFullName.Text‬‬

‫)‪itm.SubItems.Add(TextBoxAddress.Text‬‬ ‫نضيف باقي القيم بمساعدة الكائن ‪itm‬‬ ‫)‪itm.SubItems.Add(TextBoxAge.Text‬‬ ‫)‪itm.SubItems.Add(TextBoxEmailAddress.Text‬‬ ‫نطلب من األداة القيام بتغيير محتواها‬ ‫ثم ُنخبر األداة بانتهاءعملية تغيير محتواها‬

‫)(‪ListViewStudentsDetails.Update‬‬ ‫)(‪ListViewStudentsDetails.EndUpdate‬‬ ‫‪End Sub‬‬

‫عملية اخبار األداة ببداية ونهاية عملية تغيير المحتوى هي فقط لرفع نجاعة عملية االضافة ومنع‬ ‫رسم األداة خالل عملية االضافة‪.‬‬ ‫بعد اضافة بعض المعلومات تظهر األداة كالتالي‬

‫‪95‬‬


‫تمرين رقم ‪9‬‬ ‫صمم نموذجا لتسجيل طالب لدروس وفق التصميم التالي‪:‬‬

‫تعبئة األيام واألشهر والسنوات الى قوائم تاريخ الميالد يجب أن تتم عند ظهور النموذج للمرة األولى‬ ‫ويجب اظهار قيم تصلح لتكوين التاريخ مع مراعاة سنة كبيسة وما الى ذلك‪ .‬أما ادخال أسماء‬ ‫الدروس فيجب أن يتم في ملف التنسيق‪ .‬أي أن ادخال أسماء الدروس يتم بشكل يدوي‪.‬‬ ‫عند النقر على الزر " أضف الطالب الى القائمة" على النموذج أن يفحص أنه بالفعل تمت تعبئة‬ ‫جميع المعلومات الالزمة‪ .‬اذا لم يتم ادخال أو اختيار المعلومات الالزمة‪ ،‬على النموذج أن يظهر نص‬ ‫خطأ في مكان ما في النموذج من خالل استعمال األداة ‪ Label‬أو اظهار رسالة بواسطة‬ ‫‪ .MessageBox‬بعدها يتم إضافة المعلومات كسطر جديد في قائمة الطالب بالنسق الظاهر في‬ ‫المثال أعاله ويتم تفريغ جميع صناديق النصوص من محتواها‪.‬‬

‫‪96‬‬


‫‪MDI Applications‬‬ ‫تطبيقات متعددة المستندات أو النماذج‬ ‫تتكون معظم التطبيقات من عدة نماذج أو ما يُسمى أيضا بال ُمستندات (‪ .)Documents‬من هنا أطلق‬ ‫على هذه التطبيقات االسم "واجهات متعددة المستندات" أي ‪.Multiple-Document Interface‬‬ ‫الذي يُميز هذه التطبيقات وجود نموذج رئيسي )‪ (Main Form or Parent Form‬يحتوي على‬ ‫قائمة رئيسية )‪ .(Main Menu‬هذه القائمة تحتوي على عناصر متعددة وقد تكون متداخلة (أي قائمة‬ ‫داخل قائمة وهكذا)‪ .‬الضغط على واحد من هذه العناصر يُظهر عادة نموذجًا فرعيّا )‪(Child Form‬‬ ‫ما من نماذج التطبيق‪ .‬وقد تكون عدة نماذج فرعيّة ُمشغلة أو ظاهرة في نفس الوقت‪.‬‬ ‫مثال‬

‫األداة ‪MenuStrip‬‬ ‫تعتبر اداة القائمة من اهم االدوات التي تمكن المستخدم من التنقل بين نماذج التطبيق والوصول الى‬ ‫العمليات المختلفة التي يوفرها التطبيق‪ .‬تتبع هذه االداة في الـ ‪ Toolbox‬لمجموعة ادوات القوائم‬ ‫وأشرطة األدوات او ما يسمى بـ ‪.Menus And Toolbars‬‬ ‫مبنى هذه االداة تراجعي ‪ Recursive Structure‬بمعنى ان كل عنصر من عناصرها ‪(Menu‬‬ ‫)‪ Item‬قد يكون بحد ذاته قائمة وهكذا نحصل على قائمة مكونة من قوائم‪.‬‬ ‫المشترك بين هذه العناصر ان المستخدم ينقر على عناصرها نقرة واحدة ‪Single Click Event‬‬ ‫ليفتح القائمة الفرعية او لينفذ االمر (أي فتح نموذج جديد وما الى ذلك) ولذلك تشترك جميع عناصر‬ ‫القائمة بنفس معالج الحدث أي اننا نكتب معالج حدث واحد لجميع هذه العناصر والحدث هو‬ ‫‪. MenuItemClick‬‬ ‫من أجل الحصول على النموذج الرئيسي الذي يصلح النشاء تطبيق ‪ ،MDI‬علينا أن ننشئ مشروعًا‬ ‫جديدًا ثم نعطي الخاصيّة ‪ IsMdiContainer‬التابعة للنموذج القيمة ‪:True‬‬

‫‪97‬‬


98


‫الحظ كيف تغير مظهر النموذج‪.‬‬ ‫واآلن نضيف القائمة الرئيسية الى النموذج من خالل سحبها من الـ ‪ Toolbox‬ورميها على النموذج‪:‬‬

‫الضافة عناصر الى القائمة نضغط على الصندوق الذي يظهر أعلى النموذج ومكتوب عليه ‪“Type‬‬ ‫”‪ .Here‬نريد تصميم تطبيق نجمع فيه جميع النماذج التي تمت برمجتها حتى اآلن كوظائف‪.‬‬ ‫بعد اضافة العنصر الجديد ‪ Homeworks‬تصبح القائمة كالتالي‬

‫‪99‬‬


‫وبعد اضافة عدة عناصر اضافية تصبح كالتالي‬

‫واآلن نضيف قائمة فرعية تظهر عند الضغط على العنصر ‪ Simulators‬من خالل الكتابة في‬ ‫الصندوق الذي يظهر الى يمين العنصر ‪ Simulators‬ومكتوب عليه ”‪ “Type Here‬لتصبح‬ ‫القائمة كالتالي‪:‬‬

‫‪100‬‬


‫وعند تشغيل التطبيق يظهر كالتالي‬

‫كتابة معالجات األحداث لعناصرالقائمة‬ ‫الحدث االفتراضي لعناصر القائمة هو الحدث ‪ .Click‬اضافة معالج لهذا الحدث تتم بنفس الطريقة التي سبق شرحها‬ ‫في األمثلة السابقة‪.‬‬ ‫في المثال التالي نريد تطوير تطبيق نجمع فيه كل التمارين والوظائف السابقة بحيث نتمكن من استدعاء أي نموذج من‬ ‫نماذج هذه التمارين من خالل اختيار عنصر القائمة الذي يُظهر هذا النموذج‪ .‬أي أننا سنقوم باضافة جميع النماذج التي‬ ‫تمت برمجتها حتى اآلن الى هذا المشروع وتوفير عنصر قائمة لكل نموذج اسمه يساوي اسم النموذج ووظيفته اظهار‬ ‫النموذج لل ُمستخدم‪.‬‬ ‫الضافة نماذج جاهزة (مثل التمارين أو الوظائف السابقة) نضغط في الـ ‪ Solution Explorer‬على الزر األيمن‬ ‫للفارة ثم نختار األمر ‪ Add Existing Item‬الذي يظهر عند الضغط على األمر ‪ Add‬كما هو ُمبين في الصورة‬ ‫التالية‬

‫‪101‬‬


‫ثم نختار في النافذة التي تظهر جميع الملفات ال ُمتعلقة بالنموذج (يجب مراعاة أنه ال يوجد في‬ ‫المشروع نموذج نفس االسم وإذا ُوجد بامكاننا تغيير االسم من خالل الضغط على اسم النموذج بالزر‬ ‫األيمن للفارة في الـ ‪ Solution Explorer‬للمشروع الذي نريد أخذ النموذج منه ثم نختار األمر‬ ‫‪ Rename‬ثم نكتب االسم الجديد) وفي النهاية نضغط على الزر ‪ Add‬كما هو ُمبين في الصورة‬ ‫التالية‬

‫الحظ أنه يجب اضافة جميع الصور التابعة للنموذج (ان ُو ِجدت) الى الـ ‪ Resources‬كما ُش ِرح‬ ‫سابقًا‪.‬‬ ‫بعد ذلك نقوم بانشاء معالج للحدث ‪ Click‬التابع لعنصر القائمة ‪ Math Trainer‬لنحصل على‬ ‫المعالج التالي‬ ‫‪Private Sub MenuItemMathTrainer_Click(sender As System.Object,‬‬ ‫)‪e As System.EventArgs‬‬ ‫‪Handles MenuItemMathTrainer.Click‬‬ ‫‪End Sub‬‬

‫الظهار النموذج عندما يختار ال ُمستخدم هذا العنصر نقوم بالخطوات التالية‬ ‫• نبني كائنا جديدا من النموذج ‪FormSimpleMathTrainer‬‬ ‫‪Dim f As New FormSimpleMathTrainer‬‬

‫• نُبلغ النموذج بأنه تابع للنموذج الرئيسي (‪ )FormMain‬من خالل استعمال الخاصية‬ ‫‪MdiParent‬‬ ‫‪102‬‬


‫‪f.MdiParent = Me‬‬

‫• وأخيرا نظهر النموذج بمساعدة العملية ‪Show‬‬ ‫()‪f.Show‬‬

‫وبهذا يصبح المعالج كامال‬ ‫‪Private Sub MenuItemMathTrainer_Click(sender As System.Object,‬‬ ‫)‪e As System.EventArgs‬‬ ‫‪Handles MenuItemMathTrainer.Click‬‬ ‫‪Dim f As New FormSimpleMathTrainer‬‬ ‫‪f.MdiParent = Me‬‬ ‫)(‪f.Show‬‬ ‫‪End Sub‬‬

‫اختيار هذا العنصر يُظ ِهر النموذج كما يلي‬

‫الحظ أن‬ ‫• النموذج يبقى محصو ًرا داخل إطار النموذج الرئيسي وال يمكنه الظهور خارجه‪ .‬ولو حاول‬ ‫ال ُمستخدم سحبه الى خارج اإلطار لما تمكن من ذلك‪.‬‬ ‫• وإذا تم اغالق النموذج الرئيسي يُغلق أيضًا النموذج التابع له‪.‬‬ ‫• وإذا تم تصغير النموذج الرئيسي يُصغرأيضًا النموذج التابع له‪.‬‬ ‫هذا هو بالضبط معنى كون النموذج الفرعي ‪ Child‬بالنسبة للنموذج الرئيسي أو أن النموذج الرئيسي‬ ‫هو ‪ Parent‬النموذج الفرعي‪ .‬وهو ما فعلناه من خالل األمر ‪ f.MdiParent = Me‬المشروح‬ ‫أعاله‪.‬‬

‫‪103‬‬


‫تمارين‬ ‫تمرين رقم ‪1‬‬ ‫المطلوب اكمال المثال بحيث تُضاف اليه نماذج جميع التمارين السابقة‬

‫تمرين رقم ‪2‬‬ ‫أضف نموذ ًجا جديدا يعرض معلومات عنك (االسم‪ ،‬العنوان‪ ،‬التخصص وما الى ذلك) وبتصميم من اختيارك يظهر‬ ‫عندما يختار ال ُمستخدم العنصر ‪.About‬‬

‫تمرين رقم ‪3‬‬ ‫المطلوب تنفيذ الخطوات التالية على المثال من تمرين ‪ 1‬وتمرين ‪.2‬‬ ‫نريد اضافة حماية للتطبيق بحيث تظهر جميع عناصر القائمة غير قابلة لالختيار )‪ (Disabled‬وعلى ال ُمستخدم أن‬ ‫يقوم بعملية ‪ Login‬ناجحة للدخول للتطبيق‪ .‬لدينا عنصرقائمة لعملية ‪ .Login‬نص العنصر (أي الخاصيّة ‪)Text‬‬ ‫تتغير بعد دخول ال ُمستخدم بنجاح لتصبح ‪ .Logout‬وإذا خرج من خالل اختيار ‪ Logout‬تُصبح ‪.Login‬‬ ‫الحظ أن عناصرالنموذج الرئيسي ‪ File‬و ‪ Help‬غير قابلة لالختيار‬

‫‪104‬‬


Login ‫تصميم نموذج‬

‫ التابعة لصندوق كلمة‬PasswordChar ‫من أجل اخفاء كلمة المرورعند كتابتها قم باعطاء الخاصيّة‬ .‫ال ُمرور القيمة * أو أي رمز آخر تختاره‬ Login ‫اظهار نافذة الحوار‬ Private Sub MenuItemLogin_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MenuItemLogin.Click If MenuItemLogin.Text = "Logout" Then MenuItemLogin.Text = "Login" DisableMenuItems() Return End If

Login ‫ يُغير الى‬Logout ‫إذا كان النص‬ ‫ومن ثم تُستدعى العملية‬ ‫ لجعل جميع‬DisableMenuItems ‫عناصر القائمة الرئيسية غير قابلة لالختيار‬ ‫هنا نظهر النموذج كنافذة حوار وليس‬ ‫ تمنع‬ShowDialog ‫ العملية‬.‫كنموذج‬ ‫ال ُمستخدم من اختيار أي شيء في التطبيق‬ .‫اال بعد اغالق هذه النافذة بنجاح‬

Dim dlg As New FormLogIn Dim Res As DialogResult Res = dlg.ShowDialog()

If Res = Windows.Forms.DialogResult.Yes Then For Each item As ToolStripMenuItem In MenuStrip1.Items item.Enabled = True ‫ القيمة‬ShowDialog ‫إذا أرجعت العملية‬ If item.Name.ToString = "MenuItemLogin" Then ‫ معنى ذلك أنه مسموح لل ُمستخدم‬Yes item.Text = "Logout" ‫ حينها تُجعل جميع العناصر قابلة‬.‫الدخول‬ End If ‫لالختيار ويصبح اسم عنصر الدخول‬ Next Logout End If End Sub

105


DisableMenuItems ‫العملية‬ ‫ غير قابلة لالختيار أي‬Login ‫هذه العملية تجعل جميع عناصر القائمة الرئيسية باستثناء العنصر‬ Disabled Private Sub DisableMenuItems() For Each item As ToolStripMenuItem In MenuStrip1.Items If item.Name.ToString <> "MenuItemLogin" Then item.Enabled = False End If Next End Sub FormLogIn ‫ في النموذج‬Login ‫ التابع للزر‬Click ‫برمجة معالج الحدث‬

‫ الحقًا سنحصل على‬.123 ‫ و‬Me ‫في هذه المرحلة ستكون كلمة ال ُمرور واسم ال ُمستخدم القيم الثابتة‬ ‫هذه القيم من قاعدة البيانات‬ Private Sub ButtonLogIn_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonLogIn.Click If TextBoxUserName.Text = "Me" And TextBoxPassword.Text = "123" Then Me.DialogResult = DialogResult.Yes Else Me.DialogResult = DialogResult.No End If Me.Close() End Sub

‫ التابعة‬DialogResult ‫اعادة القيمة من قبل نافذة الحوار تكون من خالل استعمال الخاصيّة‬ ‫ خالف ذلك تُعاد القيمة‬.DialogResult.Yes ‫ في حال كان ال ُمستخد ُم معروفًا تُعاد القيمة‬.‫للنموذج‬ ‫ الحظ أننا نفحص القيمة ال ُمرجعة من قبل هذه النافذة الحوار في معالج الحدث‬.DialogResult.No .‫ الذي تم شرحه أعاله‬MenuItemLogin_Click FormLogIn ‫ في النموذج‬Cancel ‫ التابع للزر‬Click ‫برمجة معالج الحدث‬ Private Sub ButtonCancel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonCancel.Click Me.DialogResult = DialogResult.No Me.Close() End Sub

.‫ ويتم اغالق النافذة‬DialogResult.No ‫ تُعاد القيمة‬Cancel ‫إذا ضغط ال ُمستخدم على الزر‬

106


‫االستثناءات‬ ‫هنالك عدة أنواع من األخطاء المتعلقة بالبرامج‪:‬‬ ‫أخطاء قواعد – ‪ :Syntax Errors‬وهي عبارة عن أخطاء سببها عدم االلتزام بقواعد اللغة‪ .‬تظهر‬ ‫هذه األخطاء خالل عملية ترجمة البرنامج أي خالل عملية الـ ‪ Compilation‬ولذلك فان الـ‬ ‫‪ Compiler‬هو المسؤول عنها‪ .‬تُسمى هذه األخطاء أيضا ‪Compile Time Error‬‬ ‫أمثلة‪:‬‬ ‫األمر‬

‫الخطأ‬ ‫النوع ‪ Integers‬غير معروف‬

‫‪Dim x As Integers‬‬

‫الكلمة ‪ Then‬ناقصة‬

‫‪If x Mod 2 = 0‬‬ ‫‪x=x+1‬‬ ‫‪End If‬‬

‫العملية ‪ Pars‬غير معروفة‪ .‬األمر يجب أن يكون‬

‫‪Dim N, Result As Double‬‬ ‫=‪N‬‬

‫)‪Double.Parse(TextBoxResult.Text‬‬

‫)‪Double.Pars(TextBoxResult.Text‬‬

‫استثناءات – ‪ :Exceptions‬وهي عبارة عن أخطاء تظهر خالل عملية تنفيذ البرنامج ولذلك تُسمى‬ ‫أيضا ‪ .Run Time Error‬يُعتبر هذا النوع من األخطاء من أشد األخطاء خطورة ألنه يحصل زمن‬ ‫تشغيل البرنامج أي عندما يكون البرنامج عند الزبون الذي اشتراه‪ .‬واألشد من ذلك أن االستثناء إذا‬ ‫حصل ولم يكن المبرمج قد عالجه فان البرنامج يتوقف عن العمل بشكل غير طبيعي –‬ ‫‪ .Unhandled Exceptions‬أمثلة لهذه األخطاء‪:‬‬ ‫• محاولة التقسيم على ‪ Attempted to divide by zero - 0‬وبشكل أدق تُسمى‬ ‫‪ .OverflowException‬مثال‪:‬‬ ‫‪Dim x As Integer = 0‬‬ ‫‪Dim y As Integer‬‬ ‫‪y=5/x‬‬ ‫عند التنفيذ تظهر نافذة الخطأ التالية‪:‬‬

‫‪107‬‬


‫• االدخال غير صالح ‪ Input string was not in a correct format‬وبشكل أدق تُسمى‬ ‫‪ .FormatException‬معنى ذلك أن البرنامج توقع مثال أن يكون االدخال عددا ولكنه كان‬ ‫مثال نصا غير قابل للتحويل الى عدد‪ .‬مثال‪:‬‬ ‫‪Dim X As Integer‬‬ ‫)"‪X = Integer.Parse("Me‬‬

‫‪ Me‬ليست عددا‪ .‬عند التنفيذ تظهر نافذة الخطأ التالية‪:‬‬

‫• محاولة للوصول الى خلية من خاليا مصفوفة برقم غير صالح أي برقم ليس من المجال‬ ‫المسموح به ‪ Index was outside the bounds of the array‬وبشكل أدق تُسمى‬ ‫‪ .IndexOutOfRangeException‬مثال‪:‬‬ ‫‪108‬‬


‫‪Dim A(4) As Integer‬‬ ‫‪A(5) = 2‬‬ ‫عند التنفيذ تظهر نافذة الخطأ التالية‪:‬‬

‫• محاولة فتح قاعدة بيانات غير موجودة أو ال يمكن الوصول اليها‬ ‫‪FileNotFoundException‬‬ ‫• أخطاء قواعد باستعالمات ‪ SQL‬كما سيُبين ذلك الحقا‬ ‫كيف يُمكننا معالجة هذه األخطاء؟‬ ‫علينا احاطة المقطع الذي نتوقع أن تحدث معه أخطاء خالل تنفيذ البرنامج باألوامر ‪ try‬و‪catch‬‬ ‫على النحو التالي‪:‬‬ ‫‪Try‬‬ ‫العمليات التي قد ال ينجح تنفيذها خالل التشغيل‬ ‫‪Catch ex As Exception‬‬ ‫اظهار الخطأ للمستخدم بشكل مفهوم أو انهاء عمل العملية أو ‪...‬‬ ‫أي بشكل عام معالجة االستثناء أو الخطأ‬ ‫‪End Try‬‬

‫‪109‬‬


‫مثال‬ ‫‪Try‬‬ ‫‪Dim X As Integer‬‬ ‫)"‪X = Integer.Parse("Me‬‬ ‫‪Catch ex As Exception‬‬ ‫"!‪LabelMessage.Text = "Error: Me is not a number‬‬ ‫‪End Try‬‬

‫‪ :try‬أي حاول تنفيذ األوامر التالية‬ ‫‪ :catch‬أي التقط األخطاء التي أُرسلت أو رُميت من قبل العمليات على شكل كائن من نوع‬ ‫‪ Exception‬باسم ‪ .ex‬الحظ أن األمر ‪ Catch ex As Exception‬يتضمن تعريفا لمتغير من نوع‬ ‫‪ Exception‬باسم ‪ .ex‬والحقيقة أن هذا الكائن يتم انشاؤه وتجهيزه من قبل العملية التي حصل معها‬ ‫الخطأ‪ .‬يوفر هذا الكائن الخاصية النصية ‪ Message‬التي تحتوي على شرح مفصل عن الخطأ الذي‬ ‫حصل وهو يكون عادة النص الذي يظهر في السطر الثاني في نوافذ األخطاء آنفة الذكر‪ .‬الحظ أن‬ ‫الفئة ‪ Exception‬هي الـ ‪ Base Class‬لجميع فئات االستثناءات الموجودة في ‪ VB.NET‬أي أن‬ ‫الكائن يمر بعملية ‪ UpCasting‬من فئته الخاصة الى الفئة ‪ .Exception‬لكن بإمكاننا أن نكتب أكثر‬ ‫من أمر ‪ catch‬في نفس السلسلة بحسب األخطاء التي نتوقها (الحقيقة أن كل عملية أو أمر يحدث أو‬ ‫يرمي استثناء ‪ - Throws an Exception -‬خالل زمن التشغيل‪ ،‬توثق ذلك بشكل واضح)‪:‬‬

‫‪try‬‬ ‫العمليات التي قد ال ينجح تنفيذها خالل التشغيل‬ ‫‪catch ex As System.IO.FileNotFoundException‬‬ ‫اظهار أو معالجة الخطأ بأن الملف غير موجود‬ ‫‪catch ex As IndexOutOfRangeException‬‬ ‫اظهار أو معالجة الخطأ بأن أرقام الخاليا غير صالحة‬ ‫‪catch ex As DivideByZeroException‬‬ ‫اظهار أو معالجة الخطأ بأن التقسيم على ‪ 0‬غير ممكن‬ ‫‪Finally‬‬ ‫اظهار أو معالجة الخطأ بشكل عام‬ ‫‪End Try‬‬

‫‪110‬‬


‫هذه الطريقة تُسهل علينا اظهار نصوص واضحة للمستخدم النهائي (‪ )End User‬بلغة بعيدة عن لغة‬ ‫المبرمجين‪.‬‬ ‫يجب التنويه الى أنه بإمكان العمليات التي يكتبها المبرمج بنفسه أيضا رمي استثناءات بواسطة األمر‬ ‫‪ Throw‬لكننا سنترك دراسة هذا األمر للقارئ لعدم أهميته هنا‪ .‬الموقع التالي يوفر مادة ال بأس فيها‬ ‫عن الموضوع‪:‬‬

‫)‪Creating and Throwing Exceptions (VB.NET Programming Guide‬‬ ‫‪https://msdn.microsoft.com/en-us/library/ty79csek.aspx‬‬

‫‪111‬‬


‫‪SQL‬‬ ‫‪Structured Query Language‬‬ ‫لغة االستعالم الهيكلية‬ ‫لغة ‪ SQL‬هي لغة ُمستخدمة على نطاق واسع جدًا للوصول للمعلومات (البيانات) ال ُمخزنة في قواعد‬ ‫البيانات االرتباطية أو العالئقية )‪ (Relational Databases‬أي التي تُخزن المعلومات في جداول‬ ‫تربط بينها عالقات معينة‪ .‬والمقصود بالوصول للمعلومات أي استخراجُها وتحديثُها وحذفُها‪ .‬هذه‬ ‫األمثلة من العمليات هي على سبيل المثال ال الحصر‪ .‬وهي تُعطي تفسيرًا لسبب تسمية هذه اللغة بهذا‬ ‫االسم‪ .‬إال أن هذه التسمية مغلوطة نوعًا ما ألن اللغة قادرة على أكثر من ذلك فهي قادرة على إنشاء‬ ‫وحذف مكونات كائنات قاعدة البيانات من جداول وحقول داخل هذه الجداول وخصائص هذه الحقول‬ ‫كالفهارس أو المفاتيح (‪ )Indexes, Keys‬والعالقات )‪ . (Relations‬إضافة إلى ذلك هي قادرة‬ ‫على تنفيذ مهام إدارية مختلفة لدعم العمليات اليومية التي تتم على قاعدة البيانات‪ .‬تم تطوير هذه اللغة‬ ‫من قبل المهندسين ‪ Donal D. Chamberlin‬و ‪ Raymond F. Boyce‬من شركة ‪ IBM‬وذلك‬ ‫في عام ‪ .1970‬وكانت آنذاك تسمى بلغة ‪.SEQUEL‬‬ ‫مالحظة‪:‬‬ ‫من أجل القيام بتجربة وتنفيذ األمثلة التالية عليك القيام بالخطوات التالية التي من شأنها فتح محرر‬ ‫أوامر ‪ SQL‬التابع لبرنامج أكسس‪:‬‬ ‫•‬

‫أفتح برنامج أكسس‬

‫•‬

‫أنشئ الجداول الالزمة والعالقات التي تربطها‬

‫•‬

‫أمأل الجداول بقيم من اختيارك أو بتلك المبينة في األمثلة‬

‫•‬

‫اختر بعد ذلك كله الكائن استعالمات (שאילתות) (انظر في الشكل التالي إلى الرقم ‪)1‬‬

‫•‬

‫أنقر الزر جديد חדש (انظر في الشكل التالي إلى الرقم ‪)2‬‬

‫•‬

‫اختر (יצירת שאילתה בתצוגת עיצוב) (انظر في الشكل التالي إلى الرقم ‪)3‬‬

‫•‬

‫اختر في نافذة الحوار التي تظهر(תצוגת עיצוב) ثم انقر الزر אישור (انظر في الشكل‬ ‫التالي إلى الرقم ‪)5 + 4‬‬

‫‪112‬‬


‫•‬

‫أغلق نافذة الحوار التي تظهر(הצגת טבלה) من خالل النقر على الزر סגור (انظر في‬ ‫الشكل التالي إلى الرقم ‪)6‬‬

‫•‬

‫أنقر على الزر األيمن للفارة في المنطقة العليا من النافذة التي تظهر (انظر في الشكل التالي‬ ‫إلى الرقم ‪ )7‬ثم أختر من القائمة التي تظهر األمر תצוגת ‪( SQL‬انظر في الشكل التالي إلى‬ ‫الرقم ‪)8‬‬

‫•‬ ‫•‬

‫ابدأ بكتابة استعالمك في النافذة التي تظهر (انظر في الشكل التالي إلى الرقم ‪)9‬‬ ‫لتنفيذ االستعالم أنقر على الزر‬

‫في شريط األدوات (انظر في الشكل التالي إلى الرقم‬

‫‪)10‬‬ ‫•‬

‫عند االنتهاء من تنفيذ وفحص االستعالم بإمكانك حفظه من النقر على الزر‬ ‫األدوات‪.‬‬

‫‪113‬‬

‫في شريط‬


114


115


‫تتكون لغة ‪ SQL‬كأية لغة من‬ ‫•‬

‫مجموعة من الرموز والكلمات المحجوزة والتي لكل واحد وواحدة منها معنى معين‪.‬‬

‫•‬

‫مجموعة من القواعد التي تبين كيفية استعمال الرموز والكلمات المحجوزة لبناء جمل أو‬ ‫أوامر مركبة‪.‬‬

‫تنقسم أوامر لغة ‪ SQL‬بشكل أساسي إلى عدة أقسام منها‪:‬‬ ‫•‬

‫االستعالمات )‪ :)Queries‬األمر ‪SELECT‬‬

‫•‬

‫لغة معالجة البيانات (‪ :)DML = Data Manipulation Language‬وهي عبارة عن‬ ‫مجموعة من األوامر لتغيير محتوى الجداول في قاعدة البيانات مثل‬

‫•‬

‫‪o‬‬

‫إضافة سجالت جديدة بواسطة األمر ‪INSERT INTO‬‬

‫‪o‬‬

‫حذف سجالت موجودة في الجداول بواسطة األمر ‪DELETE‬‬

‫‪o‬‬

‫تحديث سجالت موجودة بواسطة األمر ‪UPDATE‬‬

‫لغة تعريف البيانات (‪ :)DDL = Data Definition Language‬وهي عبارة عن‬ ‫مجموعة من األوامر لتغيير مبنى قاعدة البيانات من خالل إنشاء وتغيير الكائنات المكونة لقاعدة‬ ‫البيانات مثل الجداول والحقول داخل هذه الجداول وخصائص هذه الحقول كالفهارس‬

‫‪116‬‬


‫(‪ )Indexes‬والعالقات وما إلى ذلك‪ .‬بل توفر ‪ DML‬أيضًا أوامر إلنشاء قاعدة البيانات نفسها‪.‬‬ ‫أمثلة على هذه األوامر‪:‬‬

‫•‬

‫‪o‬‬

‫إضافة جدول جديد بواسطة األمر ‪CREATE TABLE‬‬

‫‪o‬‬

‫حذف جدول موجود بواسطة األمر ‪DROP TABLE‬‬

‫‪o‬‬

‫تحديث مبنى جدول موجود بواسطة األمر ‪ALTER TABLE‬‬

‫‪o‬‬

‫إنشاء قاعدة بيانات جديدة بواسطة األمر ‪CREATE DATABASE‬‬

‫لغة التحكم بالبيانات (‪ :)DCL = Data Control Language‬وهي عبارة عن مجموعة‬ ‫من األوامر للتحكم بامتيازات المستخدمين للوصول إلى البيانات‪ .‬مثل‬ ‫‪o‬‬

‫منح امتيازات معيّنة لمجموعة مستخدمين أو مستخدم موجود بواسطة األمر‬ ‫‪GRANT‬‬

‫‪o‬‬

‫إبطال امتيازات معيّنة لمجموعة مستخدمين أو مستخدم موجود بواسطة األمر‬ ‫‪REVOKE‬‬

‫•‬

‫لغة التحكم بالمعامالت(‪ :)TCL = Transaction Control Language‬وهي عبارة عن‬ ‫مجموعة من األوامر للتحكم ببداية ونهاية تنفيذ المعامالت‪ .‬والمقصود بالمعامالت سلسلة من‬ ‫التغيرات التي يُطلب تنفيذها على البيانات أو مبنى القاعدة والتي يجب أن تعامل كوحدة واحدة أي‬ ‫إما أن تنفذ جميعها بنجاح أو أن ال تنفذ مطلقًا)‪ .‬أمثلة على هذا النوع من األوامر‬ ‫‪o‬‬

‫البدء بتنفيذ معاملة جديدة بواسطة األمر ‪BEGIN TRANSACTION‬‬

‫‪o‬‬

‫إنهاء معاملة من خالل تنفيذ كافة األعمال التي يتم إجراؤها أثناء المعاملة بواسطة‬ ‫األمر ‪COMMIT TRANSACTION‬‬

‫‪o‬‬

‫إنهاء معاملة بواسطة التراجع عن كافة األعمال التي يتم إجراؤها أثناء المعاملة‬ ‫بواسطة األمر ‪ROLLBACK TRANSACTION‬‬

‫‪117‬‬


‫االستعالمات )‪)Queries‬‬ ‫األمر ‪SELECT‬‬ ‫األمر ‪ SELECT‬بأبسط صوره‬ ‫عند االنتهاء من هذا الدرس عليك أن تكون قادراً على‬ ‫•‬

‫شرح قدرات األمر ‪SELECT‬‬

‫•‬

‫تنفيذ أمر ‪ SELECT‬بسيط‬

‫الستخراج معلومات من قاعدة البيانات علينا أن نستعمل األمر ‪ SELECT‬التابع للغة ‪ .SQL‬ربما‬ ‫تحتاج أيضا ً إلى تحديد النتائج بناءاً على شروط معينة‪ .‬هذا الدرس يشرح جميع صيغ األمر ‪SQL‬‬ ‫الالزمة لهذا الغرض‪.‬‬ ‫قدرات األمر ‪:SELECT‬‬ ‫األمر ‪ SELECT‬يسترجع معلومات من قاعدة البيانات ‪ .‬وهو قادر على‪:‬‬ ‫•‬

‫استخراج اسطر من جدول تحقق شروطا ً معينة وهو ما يسمى باختيار ‪Selection‬‬

‫•‬

‫استخراج أعمدة من جدول تحقق شروطا ً معينة وهو ما يسمى باختيار ‪Projection‬‬

‫•‬

‫استخراج معلومات مخزنة في أكثر من جدول تربط بينها عالقات أي يشتركون بيتهم بحقل‬ ‫واحد أو أكثر وهو ما يسمى باالتحاد أو الدمج ‪.Join‬‬

‫المبنى العام لألمر ‪: SELECT‬‬ ‫يكون األمر ‪ SELECT‬في ابسط صوره مكونا من القسمين )‪:(Clauses‬‬ ‫•‬

‫‪ : SELECT‬الذي يحدد الحقول التي نريد إظهار معلوماتها‬

‫•‬

‫‪ :From‬الذي يحدد الجدول (الجداول) التي تحتوي على الحقول التي حُددت في قسم ألـ‬ ‫‪SELECT‬‬

‫‪118‬‬


‫}…]‪SELECT * | {Column1 [as OtherName1], Column2 [as OtherName2‬‬ ‫;‪FROM table‬‬ ‫األقواس ] [ تعني أن الكلمة أي االستعمال غير ملزم‬ ‫الرمز | يعني أو‬ ‫األقواس } { تعني سلسلة أو قائمة‬ ‫شرح‪ :‬األمر ‪ SELECT‬يبدأ بالكلمة ‪ SELECT‬ثم إما أن يأتي الرمز * إلعادة جميع الحقول أو أن‬ ‫تأتي بعد هذه الكلمة سلسلة من أسماء الحقول طولها على األقل حقل واحد‪ .‬تفصل بين أسماء الحقول‬ ‫فواصل‪ .‬بإمكاننا أن نحدد اسما خاصا لكل حقل يعطى له في جدول النتيجة‪ .‬يجب أن ينتهي هذا األمر‬ ‫بالقسم ‪ FROM‬الذي نحدد فيه اسم الجدول (الجداول) الذي يحوي الحقول‬ ‫مالحظات‪:‬‬ ‫•‬

‫أوامر ‪ SQL‬ليست حساسة لحالة الحرف‪.‬‬

‫•‬

‫ليس بالضرورة أن ينتهي األمر في نفس السطر بل يجوز أن يكون مكتوبا ً في أكثر من سطر‬ ‫وذلك لتسهيل قراءة وفهم األمر‪.‬‬

‫•‬

‫ال يجوز قطع أو فصل الكلمات المحجوزة مثل‪.FROM, SELECT :‬‬

‫•‬

‫من المفضل كتابة الكلمات المحجوزة بأحرف كبيرة لتفريقها عن غيرها من الكلمات‬

‫أمثلة‪:‬‬ ‫اختيار جميع أعمدة الجدول ‪:Friends‬‬ ‫;‪SELECT * FROM Friends‬‬ ‫هذا األمر يعيد لنا الجدول التالي الذي يحوي جميع أعمدة الجدول ‪ .Friends‬فالنتيجة تكون متطابقة‬ ‫مع األمر التالي الذي يحدد أسماء جميع الحقول‬ ‫‪SELECT IDFriend, FName, LName, BirthDay, Address, Mobile‬‬ ‫‪;FROM Friends‬‬

‫‪119‬‬


‫الحظ انه يجب الفصل بين أسماء الحقول بالفاصلة‪ .‬ترتيب الحقول هنا يحدد ترتيبهم في جدول‬ ‫النتيجة‪.‬‬

‫اختيار أعمدة جدول محددة‪:‬‬ ‫;‪SELECT FName, LName from Friends‬‬ ‫هذا األمر يعيد لنا الجدول التالي والذي يحوي على الحقلين المطلوبين فقط‪.‬‬

‫اختيار أعمدة محددة من الجدول وإعطاؤها أسماء جديدة في جدول النتيجة‪:‬‬ ‫;‪SELECT FName AS [First Name], LName AS [Last Name] from Friends‬‬

‫‪120‬‬


‫هذا األمر يعيد لنا الجدول التالي والذي يحوي على الحقلين المطلوبين فقط‪ .‬في جدول النتيجة يظهر‬ ‫االسم ‪ First Name‬بدال من االسم ‪ FName‬واالسم ‪ Last Name‬بدال من االسم ‪.LName‬‬ ‫الحظ أن‬ ‫•‬

‫األسماء الجديدة ُوضعت بين القوسين ][ ألنها تحتوي على فراغات‬

‫•‬

‫الكلمة ‪ AS‬يجب أن تأتي مباشرة بعد اسم الحقل الذي نريد تغيير اسمه في جدول النتيجة‪.‬‬

‫•‬

‫بإمكاننا إعطاء فقط جزء من الحقول أسماء جديدة‬

‫حذف المعلومات المتكررة‬ ‫حذف المعلومات المتكررة من جدول النتيجة يتم بمساعدة الكلمة ‪( DISTINCT‬أي مختلف) التي‬ ‫تأتي قبل اسم الحقل‪.‬‬ ‫مثال‪ :‬األمر التالي يعيد لنا جميع األسطر التي تحتوي على عناوين مختلفة‪:‬‬

‫‪SELECT DISTINCT Address‬‬ ‫;‪FROM Friends‬‬

‫‪121‬‬


‫الحظ أن العنوان سخنين أُعيد مرة واحدة مع أنه موجود مرتين‪.‬‬

‫‪122‬‬


‫تحديد وترتيب النتائج‬ ‫عند االنتهاء من هذا الدرس عليك أن تكون قادراً على‬ ‫•‬

‫تحديد األسطر بناء ً على شروط معينة‬

‫•‬

‫ترتيب األسطر وفق حقول معينة‬

‫عند استخراج معلومات من قاعدة البيانات علينا أحيانا أن نحدد النتائج بناء ً على شروط معينة‪ .‬هذا‬ ‫ما ينجزه بالضبط القسم ‪ WHERE‬في األمر ‪:SQL‬‬ ‫}…]‪SELECT * | {Column1 [as OtherName1], Column2 [as OtherName2‬‬ ‫;‪FROM table WHERE Condition‬‬ ‫بحيث أن ‪ Condition‬يمثل شرطا ً‪ .‬الشرط عبارة عن أي تعبير قيمته النهائية إما صدق )‪(True‬‬ ‫أو كذب )‪ .(False‬التعبير يقارن عادة قيمتين أو أكثر بواسطة عمليات المقارنة‪ .‬هذه المقارنات قد‬ ‫تكون مرتبطة مع بعضها بواسطة عمليات الربط المنطقي‪ .‬القيم قد تكون قيم حقول أو قيم ثابتة أو‬ ‫سلسلة من القيم (انظر إلى استعمال الكلمة ‪ IN‬الحقا ً)‪.‬‬ ‫عمليات المقارنة‪:‬‬ ‫عملية المقارنة‬

‫المعنى‬

‫=‬

‫يساوي‬

‫>‬

‫أكبر من‬

‫=>‬

‫أكبر من أو يساوي‬

‫<‬

‫أصغر من‬

‫=<‬

‫أصغر من أو يساوي‬

‫><‬

‫ال يساوي‬

‫‪123‬‬


‫‪BETWEEN‬‬

‫أكبر أو يساوي ‪ x‬و‬

‫‪x AND y‬‬

‫أصغر أو يساوي ‪y‬‬

‫)‪IN (list‬‬

‫يساوي أية قيمة من‬ ‫القائمة‬

‫‪LIKE‬‬

‫يشبه بناء ً على تعبير‬ ‫رسمي‬ ‫يساوي ‪NULL‬‬

‫‪IS NULL‬‬ ‫المعامل ‪LIKE‬‬

‫يُمكننا المعامل ‪ LIKE‬من استعمال رموز خاصة (مثل * و ‪ #‬و؟) في الجزء الخاص بالشرط (أي‬ ‫جزء الـ ‪ )WHERE‬ضمن أي أمر ‪ .SQL‬استعمال هذه الرموز للبحث يُسمى أيضًا بـ ‪Pattern‬‬ ‫‪ Matching‬أو مطابقة النصوص‪ .‬بامكان هذه الرموز أن تظهر أكثر من مرة في النص المبحوث‬ ‫عنه الذي هو عبارة عن قالب أو ‪.Pattern‬‬ ‫الجدول التالي يُلخص أهم هذه الرموز‬ ‫المعنى‬

‫الرمز‬ ‫?‬

‫يعني أي رمز‬

‫*‬

‫سلسلة رموز بطول ‪ 0‬أو أكثر‬

‫‪#‬‬

‫رقم واحد فقط من األرقام ‪ 0‬ولغاية ‪9‬‬

‫الرمز ‪ #‬يعني رق ًما واحدًا فقط‪ .‬فحيث ما ُو ِجد في التعبير يعني أننا نأخذ القيمة فقط اذا احتوت في‬ ‫األماكن التي فيها الرمز ‪ #‬على رقم‬ ‫أمثلة‬ ‫• األمر التالي يعيد لنا جيمع السجالت الموجودة في الجدول ‪ Contacts‬التي قيم الحقل‬ ‫‪ MyName‬فيها بطول رمزين فقط وتبدأ بالحرف ‪ T‬وتنتهي برقم (أي مثال ‪T0, T1, T2,‬‬ ‫‪)…, T9‬‬

‫‪124‬‬


‫* ‪SELECT‬‬ ‫‪FROM Contacts‬‬ ‫'‪WHERE Contacts.MyName Like 'T#‬‬ ‫• األمر التالي يعيد لنا جيمع السجالت الموجودة في الجدول ‪ Contacts‬التي قيم الحقل‬ ‫‪ MyName‬فيها بطول ‪ 3‬رموز فقط وتبدأ وتنتهي برقم وتنتهي وبين الرقمين الحرف ‪T‬‬ ‫(أي مثال ‪)2T0, 0T1, 1T2, …, 8T9‬‬ ‫* ‪SELECT‬‬ ‫‪FROM Contacts‬‬ ‫'‪WHERE Contacts.MyName Like '#T#‬‬ ‫الرمز ? يعني رم ًزا واحدًا فقط‪ .‬فحيث ما ُو ِجد في التعبير يعني أننا نأخذ القيمة فقط إذا احتوت في‬ ‫األماكن التي فيها الرمز ? على رمز‬ ‫مثال‬ ‫• األمر التالي يعيد لنا جيمع السجالت الموجودة في الجدول ‪ Contacts‬التي قيم الحقل‬ ‫‪ MyName‬فيها يبدأ بالعدد ‪ 2015‬وينتهي بأي رمز‬ ‫* ‪SELECT‬‬ ‫‪FROM Contacts‬‬ ‫'?‪WHERE Contacts.MyName Like '2015‬‬ ‫الرمز * يعني سلسلة رموز وقد تكون فارغة‬ ‫مثال‬ ‫• األمر التالي يعيد لنا جيمع السجالت الموجودة في الجدول ‪ Contacts‬التي قيم الحقل‬ ‫‪ MyName‬فيها يبدأ بأي نص ويتنهي بالنص ‪Tester‬‬ ‫* ‪SELECT‬‬ ‫‪FROM Contacts‬‬ ‫'‪WHERE Contacts.MyName Like '*Tester‬‬ ‫• األمر التالي يعيد لنا جيمع السجالت الموجودة في الجدول ‪ Contacts‬التي قيم الحقل‬ ‫‪ MyName‬فيها يبدأ ويتنهي بأي نص ويحتوي على النص ‪Tester‬‬ ‫‪125‬‬


‫* ‪SELECT‬‬ ‫‪FROM Contacts‬‬ ‫'*‪WHERE Contacts.MyName Like '*Tester‬‬ ‫عمليات الربط‬ ‫عملية الربط‬

‫المعنى‬

‫‪X AND Y‬‬

‫تعيد ‪ True‬إذا كانت قيمة ‪ X‬و قيمة ‪True Y‬‬

‫‪X OR Y‬‬

‫تعيد ‪ True‬إذا كانت قيمة ‪ X‬أو قيمة ‪True Y‬‬

‫‪NOT X‬‬

‫تعيد ‪ True‬إذا كانت قيمة ‪False X‬‬

‫مثال‪:‬‬ ‫األمر التالي يعيد لنا تفاصيل جميع األصدقاء من سخنين (أي بشرط أن يكونوا من سخنين)‪:‬‬ ‫* ‪SELECT‬‬ ‫‪FROM Friends‬‬ ‫;'‪WHERE Address='Sakhnin‬‬

‫الحظ أن‬ ‫الكلمة ‪ Sakhnin‬أحيطت بشطائر فردية ألن الحقل من نوع نص‪ .‬أما بالنسبة للقيم العددية فال تحاط‬ ‫القيم العددية بأية شطائر‪.‬‬ ‫عملية المقارنة غير حساسة لحالة الحرف‪ .‬فلو كتبنا ‪ Sakhnin‬أو ‪ sakhnin‬نحصل على نفس‬ ‫النتيجة (صحيح بالنسبة لـ ‪.)MS Access‬‬ ‫األمر التالي يعيد لنا تفاصيل الصديق الذي رقمه ‪:2‬‬ ‫‪126‬‬


‫* ‪SELECT‬‬ ‫‪FROM Friends‬‬ ‫;‪WHERE IDFriend=2‬‬

‫األمر التالي يعيد لنا تفاصيل األصدقاء الذين أرقامهم أكبر أو تساوي ‪ 4‬و أصغر أو يساوي ‪:5‬‬

‫* ‪SELECT‬‬ ‫‪FROM Friends‬‬ ‫;‪WHERE IDFriend BETWEEN 4 AND 5‬‬ ‫نفس النتيجة يعيدها األمر‬ ‫* ‪SELECT‬‬ ‫‪FROM Friends‬‬ ‫;)‪WHERE IDFriend IN (4, 5‬‬

‫انتبه إلى أن نوع القيم يجب أن يكون من نوع الحقل! فمثال األمر التالي يستعمل حقال من نوع نص‬ ‫ولذلك نصوص كقيم وأحيطت بشطائر فردية‪:‬‬

‫‪127‬‬


SELECT * FROM Friends WHERE Address IN ('Haifa', 'Sakhnin');

‫ أي يعيد لنا تفاصيل األصدقاء الذين‬OR ‫نفس النتيجة يعيدها األمر التالي من خالل استعمال الرابط‬ :Haifa ‫ أو في‬Sakhnin ‫يسكنون في‬

SELECT * FROM Friends WHERE Address='Sakhnin' OR Address='Haifa'; :Samra ‫ واسم العائلة‬Sami ‫األمر التالي يعيد لنا تفاصيل األصدقاء الذين اسمهم األول‬ SELECT * FROM Friends WHERE FName='Sami' AND LName='Samra';

128


‫األمر التالي يعيد من خالل استعمال الرابط ‪ NOT‬تفاصيل األصدقاء الذين ال يسكنون في ‪Sakhnin‬‬ ‫وأيضا ليس في ‪:Haifa‬‬

‫* ‪SELECT‬‬ ‫‪FROM Friends‬‬ ‫;)'‪WHERE Address NOT IN ('Sakhnin','Haifa‬‬

‫الحقا ً سنرى أن عناصر القائمة قد تكون نتيجة استعالم ‪ SELECT‬داخلي‪.‬‬

‫‪129‬‬


‫ترتيب النتائج‬ ‫ترتيب األسطر في جدول النتيجة يكون غير معروف مسبقا ً‪ .‬القسم ‪ ORDER BY‬التابع لألمر‬ ‫‪ SELECT‬يمكننا من ترتيب األسطر في جدول النتيجة‪ .‬هذا القسم يجب أن يكون القسم األخير في‬ ‫أمر الـ ‪ .SELECT‬األمر يوفر لنا إمكانيتين للترتيب‪ (Ascending) ASC .‬للترتيب التصاعدي و‬ ‫‪ (Descending) DESC‬للترتيب التنازلي‪ .‬الترتيب التصاعدي هو الترتيب االفتراضي‪ .‬وعليه‬ ‫يكون األمر ‪ SELECT‬بصورته األشمل كالتالي‪:‬‬ ‫}…]‪SELECT * | {Column1 [as OtherName1], Column2 [as OtherName2‬‬ ‫}…‪FROM table [WHERE Condition] ORDER BY {Column1, Column2 ,‬‬ ‫;]‪[ASC | DESC‬‬ ‫األمر التالي يعيد لنا جميع األصدقاء مرتبين حسب تاريخ ميالدهم من األصغر إلى األكبر‪:‬‬

‫* ‪SELECT‬‬ ‫‪FROM Friends‬‬ ‫;‪ORDER BY BirthDay DESC‬‬

‫الترتيب قد يكون حسب أكثر من حقل‪ .‬مثال ً األمر التالي يعيد لنا جميع األصدقاء مرتبين حسب‬ ‫تاريخ ميالدهم من األصغر إلى األكبر وأيضا ً حسب أسماء العائلة مرتبة ترتيبا ً أبجديا ً تنازليا ً‪:‬‬

‫‪130‬‬


‫* ‪SELECT‬‬ ‫‪FROM Friends‬‬ ‫;‪ORDER BY LName DESC , BirthDay DESC‬‬

‫استخراج معلومات من أكثر من جدول‬ ‫من الصعب جدًا أن نجد أو أن نصمم قاعدة بيانات تخزن المعلومات في جداول منفصلة عن بعضها‬ ‫البعض‪ .‬وإنما من الطبيعي أن نجد القاعدة مكونة من جداول عدة تربط بين معظمها عالقات‪ .‬ولذلك‬ ‫سنتعلم اآلن كيفية صياغة أوامر ‪ SQL‬الستخراج المعلومات من أكثر من جدول تربط بينها عالقات‬ ‫مختلفة‪ .‬هذه العالقات تنشأ عادةً من خالل حقول مفاتيح مشتركة بين هذه الجداول‪ .‬من المعروف أن‬ ‫العالقات الممكنة ثالث‪:‬‬ ‫•‬

‫واحد لواحد )‪)1  1‬‬

‫•‬

‫واحد لكثير )‪)1  N‬‬

‫•‬

‫كثير لكثير )‪)M  N‬‬

‫لنأخذ على سبيل المثال الجدولين التاليين (جدول الدول وجدول العواصم) والذين تربط بينهم عالقة‬ ‫واحد لواحد وذلك من خالل اشتراكهما في الحقل ‪ .IDCapital‬هذا الحقل يكون في الجدول‬ ‫‪ Capitals‬مفتاحًا رئيسيًا أي ‪ Primary Key‬وفي الجدول الثاني أي ‪ Countries‬يكون مفتاحًا‬ ‫غريبًا أي ‪Foreign Key‬‬ ‫‪131‬‬


132


133


‫اآلن نريد كتابة استعالم يعيد لنا اسم الدول واسم عاصمتها وعدد سكان العاصمة‪ .‬أي يعيد لنا الجدول‬ ‫التالي‪:‬‬

‫الحظ أن المعلومات المطلوبة موجودة في جدولين‪ .‬ولذلك علينا أن نعيد األسطر التي تشترك في‬ ‫قيمة الحقل الرابط ‪ .IDCapital‬الشكل التالي يوضح ذلك‪:‬‬

‫األمر التالي يعيد لنا النتيجة المطلوبة‪:‬‬

‫‪SELECT Countries.Name, Capitals.Name, Capitals.Inhabitants‬‬ ‫‪FROM Capitals, Countries‬‬ ‫;‪WHERE Capitals.IDCapital=Countries.IDCapital‬‬

‫‪134‬‬


‫الحظ أننا كتبنا قبل كل اسم حقل اسم الجدول الذي يحتويه وذلك للحيلولة دون حصول تعارض بين‬ ‫أسماء الحقول المتساوية‪.‬‬ ‫اإلمكانية الثانية للحصول على هذه النتيجة تكون من خالل استعمال األمر ‪ INNER JOIN‬والذي‬ ‫يعني دمج جدولين في جدول نتيجة واحد بنا ًء على حقل مشترك (أي قيم مشتركة)‪:‬‬ ‫‪SELECT Countries.Name, Capitals.Name, Capitals.Inhabitants‬‬ ‫‪FROM Capitals‬‬ ‫‪INNER JOIN Countries‬‬ ‫;‪ON Capitals.IDCapital = Countries.IDCapital‬‬

‫أمر االتحاد ‪ INNER JOIN‬يقوم بدمج السجالت أي األسطر من جدولين أينما وجدت قيم متطابقة‬ ‫في حقل مشترك‪ .‬السجالت التي ال تحقق الشرط المذكور في األمر وراء الكلمة ‪ ON‬ال تُعاد‪ .‬الحظ‬ ‫أن األمر ‪ INNER JOIN‬يستعمل الكلمة ‪ ON‬بدالً من الكلمة ‪.WHERE‬‬ ‫المبنى العام لألمر‬ ‫‪SELECT columns‬‬ ‫‪FROM table1‬‬ ‫‪INNER JOIN table2‬‬ ‫‪ON table1.field1 compopr table2.field2‬‬ ‫بحيث أن‪:‬‬ ‫‪ table1‬و ‪ table2‬أسماء الجداول التي يتم تجميع السجالت منها‪.‬‬ ‫‪ field1‬و ‪ field2‬أسماء الحقول المتصلة‪.‬‬ ‫‪ compopr‬أية عملية مقارنة منطقية (أي ><‪.)=, <,<=,>,>=,‬‬

‫‪135‬‬


‫مثال لعالقة ‪: 1  N‬‬ ‫الشكل التالي يبين الجدول طالب ‪ Students‬والجدول صفوف ‪ Classes‬ويبين أن العالقة بينهم هي‬ ‫عالقة واحد لكثير‪ .‬ففي الصف الواحد يتعلم كثير من الطالب‪ .‬الحقل الواصل هو الحقل ‪.IDClass‬‬

‫نريد كتابة أمر دمج يعيد لنا الجدول التالي الذي يعرض بعض تفاصيل الطالب الموجودة في الجدول‬ ‫‪ Students‬وبعض التفاصيل عن صفه الموجودة في الجدول ‪:Classes‬‬

‫‪136‬‬


‫األمر التالي يستعين باألمر ‪ INNER JOIN‬إلعادة المعلومات المطلوبة‪:‬‬

‫‪SELECT Students.FirstName, Students.LastName, Students.DayOfBirth,‬‬ ‫‪Classes.Name AS Class, Classes.Room‬‬ ‫‪FROM Classes‬‬ ‫‪INNER JOIN Students‬‬ ‫;‪ON Classes.IDClass = Students.IDClass‬‬ ‫أمر االتحاد ‪ LEFT JOIN‬يعيد جميع السجالت الموجودة في الجدول األيسر (أي ‪ )table1‬حتى‬ ‫لو لم تحقق الشرط المذكور في األمر وراء الكلمة ‪ ON‬أي حتى ولو لم يجد سجالت مناسبة في‬ ‫الجدول األيمن (أي ‪.)table2‬‬ ‫المبنى العام لألمر‬ ‫‪SELECT columns‬‬ ‫‪FROM table1‬‬ ‫‪LEFT JOIN table2‬‬ ‫‪ON table1.field1 compopr table2.field2‬‬ ‫مثالً لدينا الجدول رسائل ‪ Messages‬الذي تربطه عالقة واحد لكثير مع جدول الطالب المذكور‬ ‫أعاله‪ .‬كل طالب يستطيع كتابة رسائل كثيرة في منتدى المدرسة على سبيل المثال‪ .‬إذا دمجنا‬ ‫الجدولين بواسطة األمر ‪ INNER JOIN‬فهذا سيعيد لنا تفاصيل الطالب الذين كتبوا رسائل‬ ‫وتفاصيل الرسائل التي كتبوها‪ .‬أي أن تفاصيل الطالب الذين لم يشاركوا في المنتدى سوف ال تعاد‪.‬‬ ‫كيف نستطيع الحصول أيضًا على تفاصيل الطالب الذين لم يشاركوا في المنتدى؟ هذا هو بالضبط ما‬ ‫يقوم به األمر ‪ LEFT JOIN‬الذي يعيد تفاصيل الطالب حتى ولو لم يجد سجالت مناسبة في جدول‬ ‫الرسائل‪:‬‬

‫‪137‬‬


:‫محتوى الجدولين‬

:‫ التالي‬INNER JOIN ‫األمر‬ SELECT Students.FirstName, Students.LastName, Messages.Message FROM Students INNER JOIN Messages ON Students.IDStudent = Messages.IDStudent;

138


‫يعيد لنا الجدول التالي الذي يحتوي على تفاصيل الطالب الذين شاركوا في المنتدى‪:‬‬

‫بينما األمر ‪ LEFT JOIN‬التالي‬

‫‪SELECT Students.FirstName, Students.LastName, Messages.Message‬‬ ‫‪FROM Students‬‬ ‫‪LEFT JOIN Messages‬‬ ‫;‪ON Students.IDStudent=Messages.IDStudent‬‬ ‫سيعيد لنا تفاصيل الجميع أي تفاصيل الذين شاركوا والذين لم يشاركوا‪:‬‬

‫‪139‬‬


‫الحظ أن األمر أعاد لنا السجالت من الجدول األيسر مع أنه لم يجد سجالت تحقق الشرط في الجدول‬ ‫األيمن‪.‬‬ ‫مالحظة‪:‬‬ ‫األمر ‪ LEFT JOIN‬يسمى أيضًا ‪ LEFT OUTER JOIN‬وبإمكاننا كتابة‬ ‫‪ LEFT OUTER JOIN‬بدالً من ‪ LEFT JOIN‬ونحصل على نفس النتيجة‪.‬‬

‫األمر ‪RIGHT JOIN‬‬ ‫من الممكن أن نسأل السؤال التالي‪ :‬هل يوجد مشاركات في المنتدى ألناس ليسوا طالبًا في المدرسة؟‬ ‫من الواضح أن وجود مثل هذه السجالت يدل على خطأ في تصميم قاعدة البيانات‪ .‬ألن وجودها يعني‬ ‫استعمال مفتاح غريب في جدول الرسائل ال أصل له في جدول الطالب‪ .‬مع أن الخطوة التي نعرف‬ ‫فيها العالقات بين الجداول تفترض أيضا أن نضمن مبدأ ما يسمى بالتكامل المرجعي ( ‪Referential‬‬ ‫‪ .)Integrity‬هذا المبدأ يُطلب من مدير قاعدة البيانات‬ ‫)‪ (DBMS: Data Base Management System‬ويضمن‪:‬‬ ‫•‬

‫عدم السماح بإدخال قيم لمفتاح غريب غير موجودة كقيم للمفتاح الرئيسي‪.‬‬

‫•‬

‫إذا حُذف سجل أب تُحذف كل سجالت االبن المرتبطة به وذلك لكي ال تبقى سجالت غير‬ ‫مرتبطة بشيء في الجدول األصلي‪.‬‬

‫مع ذلك لو حصل الخطأ كيف يمكننا أن نحصل على هذه السجالت؟ هذا هو بالضبط ما يقوم به األمر‬ ‫‪ .RIGHT JOIN‬فهو يعيد جميع السجالت الموجودة في الجدول األيمن (أي ‪ )table2‬حتى لو لم‬ ‫تحقق الشرط المذكور في األمر وراء الكلمة ‪ ON‬أي حتى ولو لم يجد سجالت مناسبة في الجدول‬ ‫األيسر (أي ‪.)table1‬‬ ‫من أجل إعطاء مثال قمت بإيقاف فحص التكامل المرجعي في قاعدة البيانات وأدخلت رسائل من‬ ‫أناس غير موجودين في جدول الطالب ومن ثم نفذت األمر التالي‪:‬‬ ‫‪140‬‬


‫‪SELECT Students.FirstName, Students.LastName, Messages.Message‬‬ ‫‪FROM Students‬‬ ‫‪RIGHT JOIN Messages‬‬ ‫;‪ON Students.IDStudent=Messages.IDStudent‬‬ ‫وحصلت على الجدول التالي الذي يعرض أيضًا رسالة كاتبها غير موجود في جدول الطالب‪:‬‬

‫مثال لعالقة ‪: M  N‬‬ ‫الشكل التالي يبين الجدول طالب( ‪ ( Students‬والجدول دروس ( ‪ ( Lessos‬ويبين أن العالقة‬ ‫بينهم هي عالقة كثير لكثير‪ .‬فكل طالب يتعلم أكثر من درس وكل درس يتعلمه أكثر من طالب‪.‬‬ ‫معروف أن هذه العالقة تُصمم بمساعدة جدول ثالث ( ‪ ) LessonsStudents‬تُحفظ فيه المفاتيح‬ ‫الرئيسية كمفاتيح غريبة (اندكسات) مع إمكانية التكرار( ‪.)IDLesson, IDStudent‬‬

‫‪141‬‬


‫السؤال اآلن هو كيف يمكننا أن نستخرج المعلومات من هذه الجداول الثالث لنحصل على تفاصيل‬ ‫الطالب وتفاصيل الدروس التي يدرسونها؟ أي أن جدول النتيجة يجب أن يعرض من يدرس ماذا‬ ‫كالتالي‪:‬‬

‫من الجداول التالية‪:‬‬

‫‪142‬‬


INNER JOIN ‫األمر الذي يعيد لنا المعلومات وفق النسق المطلوب هو أمر مركب يستعمل األمر‬ :‫بشكل متداخل‬

SELECT Students.FirstName, Students.LastName, Lessons.Name FROM Students INNER JOIN (Lessons INNER JOIN LessonsStudents ON Lessons.IDLesson = LessonsStudents.IDLesson) ON Students.IDStudent = LessonsStudents.IDStudent;

143


‫األمر الداخلي‬ ‫‪Lessons INNER JOIN LessonsStudents‬‬ ‫‪ON Lessons.IDLesson = LessonsStudents.IDLesson‬‬ ‫يعيد لنا نتيجة دمج الجدول ‪ Lessons‬مع جدول الربط ‪ LessonsStudents‬بنا ًء على الحقل‬ ‫المشترك ‪ .IDLesson‬بعد ذلك نقوم بدمج هذه النتيجة مع الجدول ‪ Students‬بنا ًء على الحقل‬ ‫المشترك ‪.IDStudent‬‬ ‫مثال على أوامر ‪ SELECT‬متداخلة‬ ‫أكتب استعال ًما يعيد قائمة بتفاصيل الدروس التي ال يدرسها أحد‪.‬‬ ‫واضح أنه علينا أن نبحث داخل الجدول ‪Lessons‬عن مفاتيح الدروس الموجودة فيه ولكنها ال تظهر‬ ‫في الجدول ‪ .LessonsStudents‬ألنها لو كانت تُدرس من قبل أي طالب لوجب ظهور رقم الدرس‬ ‫في جدول الربط ‪ .LessonsStudents‬نُنجز ذلك من خالل إعادة جميع مفاتيح الدروس المختلفة‬ ‫الموجودة في الجدول ‪ LessonsStudents‬بواسطة أمر ‪ SQL‬داخلي يعيد لنا قائمة بهذه األرقام‪:‬‬

‫‪SELECT DISTINCT IDLesson FROM LessonsStudents‬‬ ‫ثم نقوم بواسطة أمر ‪ SQL‬خارجي باستخراج تفاصيل الدروس التي ال تظهر أرقامها في القائمة أنفة‬ ‫الذكر وذلك بمساعدة األمر‪ IN‬مع عملية النفي ‪:NOT‬‬ ‫* ‪SELECT‬‬ ‫‪FROM Lessons‬‬ ‫‪WHERE IDLesson NOT IN (SELECT DISTINCT IDLesson FROM‬‬ ‫;)‪LessonsStudents‬‬

‫‪144‬‬


‫تمرين رقم ‪1‬‬ ‫أكتب استعال ًما يعيد قائمة بأسماء الدروس التي ال يدرسها طالب معين‪.‬‬

‫األمر ‪SELECT INTO‬‬ ‫يُستعمل األمر ‪ SELECT INTO‬الستخراج معلومات من جدول موجود وحفظُها في جدول جديد‬ ‫يتم إنشاؤه من قبل األمر ‪ .SELECT INTO‬إذا كان الجدول الجديد موجودًا حينها يتم حذفه ومن ثم‬ ‫إنشاؤه من جديد‪ .‬يُستعمل هذا األمر عادةً إلنشاء نُسخ عن الجداول وهو ما يُسمى باألرشيفات‪.‬‬ ‫المبنى العام لألمر‪:‬‬

‫‪SELECT * | Columns Names‬‬ ‫]‪INTO New_Table_Name [IN ExternalDataBase‬‬ ‫‪FROM Old_TableName‬‬ ‫يبين المبنى العام لألمر أنه من الممكن إنشاء الجدول الجديد في قاعدة بيانات خارجية‪ .‬يُفترض في‬ ‫القاعدة الخارجية أن تكون موجودة وعدم وجودها يحدث خطًأ‪ .‬إضافة إلى ذلك ال بد من كتابة المسار‬ ‫المطلق لملف القاعدة الخارجية‪.‬‬ ‫مثال‪:‬‬ ‫األمر التالي ينسخ الجدول ‪ Lessons‬إلى القاعدة الخارجية ‪D:\SQL\DBArchive.mdb‬‬ ‫ويعطيه هناك نفس االسم‪:‬‬ ‫* ‪SELECT‬‬ ‫'‪INTO Lessons IN 'D:\SQL\DBArchive.mdb‬‬ ‫‪FROM Lessons‬‬ ‫مثال‬

‫‪145‬‬


‫األمر التالي ينسخ الجدول ‪ Lessons‬إلى نفس القاعدة لكن يعطيه االسم الجديد‬ ‫‪:Lessons_BackUp‬‬ ‫* ‪SELECT‬‬ ‫‪INTO Lessons_BackUp‬‬ ‫‪FROM Lessons‬‬ ‫انتبه إلى أنه ال يجوز وجود أكثر من جدول بنفس االسم في نفس قاعدة البيانات‪ .‬من هنا وجب إعطاء‬ ‫الجدول اس ًما جديدًا مختلفًا عن االسم الموجود‪.‬‬

‫‪146‬‬


‫تمرين رقم ‪2‬‬ ‫صمم قاعدة بيانات باسم ‪ Courses.mdb‬إلدارة معلومات حول التسجيل لدورات استكمال فيه‬ ‫الجداول التالية‪:‬‬

‫العالقات‬ ‫•‬

‫بإمكان كل طالب أن يتسجل ألكثر من دورة‬

‫•‬

‫الدورة الواحدة يتسجل لها أكثر من طالب‬

‫الجداول‬ ‫•‬

‫الجدول ‪ Admins‬يحتوي على كلمات المرور وأسماء المستخدمين لمديري موقع التسجيل‬ ‫للدورات‬

‫•‬

‫الجدول ‪ Announcements‬يحتوي على آخر األخبار‬

‫المطلوب‬ ‫▪‬

‫أعد تصميم الجدولين ‪ Students‬و ‪ Courses‬بحيث تحقق العالقات التي يجب أن تكون‬ ‫بينهم‬

‫▪‬

‫أمأل جداول قاعدة البيانات بقيم من اختيارك‪ .‬حاول إدخال بعض القيم بواسطة األمر‬ ‫‪INSERT INTO‬‬

‫▪‬

‫أكتب استعالما يطبع تفاصيل جميع الطالب ولكل طالب تفاصيل الدورات ال ُمسجل فيها‪.‬‬ ‫‪147‬‬


‫▪‬

‫أكتب استعالما يعيد لطالب معين تفاصيل الدورات ال ُمسجل فيها‪ .‬االستعالم يطلب ‪.ID‬‬ ‫الطالب عند تشغيل االستعالم‪.‬‬

‫▪‬

‫أكتب استعالما يعيد لدورة معينة تفاصيل الطالب ال ُمسجلين فيها‪.‬‬

‫▪‬

‫أكتب استعالما يطبع تفاصيل جميع الطالب الذين لم يسجلوا ألية دورة‪.‬‬

‫▪‬

‫أكتب استعالما يطبع تفاصيل جميع األطباء الذين ال يعالجون مرضى بعد أي (الذين ال‬ ‫مرضى لهم)‬

‫تمرين رقم ‪3‬‬ ‫صمم قاعدة بيانات باسم ‪ Hospital.mdb‬إلدارة معلومات في مستشفى وفق المخطط التالي‪:‬‬

‫المطلوب‬ ‫▪‬

‫أمأل جداول قاعدة البيانات ‪ Hospital.mdb‬بقيم من اختيارك‪ .‬حاول إدخال بعض القيم‬ ‫بواسطة األمر ‪INSERT INTO‬‬ ‫‪148‬‬


‫▪‬

‫أكتب استعالما يطبع تفاصيل جميع المرضى ولكل مريض تفاصيل األطباء المعالجين‬

‫▪‬

‫أكتب استعالما يعيد لمريض معين تفاصيل ألطباء المعالجين‪ .‬االستعالم يطلب ‪ ID‬المريض‬ ‫عند تشغيل االستعالم‪.‬‬

‫▪‬

‫أكتب استعالما يعيد لطبيب معين تفاصيل المرضى الذين يعالجهم‬

‫▪‬

‫أكتب استعالما يطبع تفاصيل جميع المرضى الذين ال يعالجون بعد (أي الذين ال طبيب لهم)‬

‫▪‬

‫أكتب استعالما يطبع تفاصيل جميع األطباء الذين ال يعالجون مرضى بعد أي (الذين ال‬ ‫مرضى لهم)‬

‫اإلدخال‬ ‫يتم إدخال سجالت جديدة إلى جدول ما بواسطة األمر ‪INSERT INTO‬‬ ‫الصيغة العامة لألمر هي كالتالي‪:‬‬ ‫(… ‪INSERT INTO TableName )Column1, Column2,‬‬ ‫;) … ‪VALUES (ValueOfColumn1, ValueOfColumn2,‬‬ ‫أي‬ ‫)قائمة بأسماء الحقول التي نريد إدخال قيم إليها( ‪INSERT INTO TableName‬‬ ‫;)قائمة بقيم الحقول التي نريد إدخالها( ‪VALUES‬‬

‫• يجب إحاطة قيمة الحقول التي من نوع نص بشطائر منفردة‪.‬‬ ‫• يجب إحاطة قيمة الحقول التي من نوع تاريخ ‪ /‬وقت بالرمز ‪.#‬‬ ‫• إذا وجد في الجدول حقل من نوع ‪ Auto Number‬ال يجوز لنا أن نبقي قائمة أسماء الحقول‬ ‫فارغة‪ ،‬بل يجب كتابة الحقول التي نريد إدخال قيم إليها باستثناء حقل الـ ‪( Auto Number‬أي‬ ‫ال نكتبه ألن الـ ‪ DBMS‬مسئول عن إعطاء قيم له)‪ .‬أما في الجدول الذي ال يحتوي على حقل‬ ‫من نوع ‪ Auto Number‬فبإمكاننا أن نترك قائمة أسماء الحقول فارغة وتزويد قيم لكل‬ ‫الحقول‪.‬‬ ‫‪149‬‬


‫ نريد إدخال سجالت جديدة إلى الجدول‬.2 ‫ معطاة قاعدة البيانات من الفعالية رقم‬:‫أمثلة‬ :Courses

:‫الحل‬ INSERT INTO Courses ([Name], [Hours], [Location], [BeginDate], [EndDate]) VALUES(‘VB’,80,’college’,#1/9/12#,#10/10/12#)

‫ من المفضل إحاطة جميع أسماء الحقول باألقواس ] [ لمنع أي تعارض مع أي أسماء‬:‫مالحظة‬ .SQL ‫محجوزة بلغة‬ ‫أمثلة‬ :‫ كالتالي‬Courses ‫ليكن محتوى الجدول‬

CourseID 1 2 3 4 5

Code 100 102 104 106 108

Date 20/12/2011 30/12/2011 03/12/2011 11/11/2011 22/09/2010

Category CS CS En Ar CS

150

Title C# Java English Level 1 Arabic For Beginners SQL Basics

Hours 112 112 56 112 112


:‫أكتب استعالما يضيف سجال جديدا بالمعطيات التالية‬

CourseID 6

Code 110

Date 02/09/2010

Category CS

Title MS Access

Hours 112

‫الحل‬ INSERT INTO Courses ([Code], [Date], [Category], [Title], [Hours]) VALUES (110, #02/09/2010#, 'CS', 'MS Access', 112)

:‫بعد تنفيذ األمر يصبح محتوى الجدول كالتالي‬ CourseID 1 2 3 4 5 6

Code 100 102 104 106 108 110

Date 20/12/2011 30/12/2011 03/12/2011 11/11/2011 22/09/2010 02/09/2010

Category CS CS En Ar CS CS

Title C# Java English Level 1 Arabic For Beginners SQL Basics MS Access

Hours 112 112 56 112 112 112

‫ وليس من قبلنا ألن الحقل من نوع‬Access ‫ من قبل‬CourseID ‫ أُعطيت للحل‬6 ‫الحظ أن القيم‬ .Auto Number

151


‫التحديث‬ ‫تتم حتلنة سجالت موجودة في جدول ما بواسطة األمر ‪UPDATE‬‬ ‫الصيغة العامة لألمر هي كالتالي‪:‬‬ ‫‪UPDATE TableName SET {Column1=Value1, Column2= Value2, …} [WHERE‬‬ ‫]‪Condition‬‬

‫أي قم بتعديل الجدول المعطى اسمه واجعل قيم الحقول الموجودة في القائمة بحسب القيم المعطاة‪.‬‬ ‫• األقواس ] [ تعني أن استعمال الجزء الذي بين األقواس غير ملزم‪ ،‬أي أن كتابة الشرط غير‬ ‫ملزمة‪ .‬الحظ أن استعمال األمر ‪ UPDATE‬بدون شرط سيؤدي إلى تغيير جميع السجالت‬ ‫الموجودة في الجدول‪.‬‬ ‫• األقواس } { تعني سلسلة أو قائمة غير فارغة أي فيها على األقل زوج واحد مكون من اسم‬ ‫الحقل وقيمته يفصل بينهم الرمز =‪.‬‬ ‫أمثلة‬ ‫ليكن محتوى الجدول ‪ Courses‬كالتالي‪:‬‬

‫‪Hours‬‬ ‫‪112‬‬ ‫‪112‬‬ ‫‪56‬‬ ‫‪112‬‬ ‫‪112‬‬ ‫‪112‬‬

‫‪Title‬‬ ‫‪C#‬‬ ‫‪Java‬‬ ‫‪English Level 1‬‬ ‫‪Arabic For Beginners‬‬ ‫‪SQL Basics‬‬ ‫‪MS Access‬‬

‫‪Category‬‬ ‫‪CS‬‬ ‫‪CS‬‬ ‫‪En‬‬ ‫‪Ar‬‬ ‫‪CS‬‬ ‫‪CS‬‬

‫‪Date‬‬ ‫‪20/12/2011‬‬ ‫‪30/12/2011‬‬ ‫‪03/12/2011‬‬ ‫‪11/11/2011‬‬ ‫‪22/09/2010‬‬ ‫‪02/09/2010‬‬

‫‪Code‬‬ ‫‪100‬‬ ‫‪102‬‬ ‫‪104‬‬ ‫‪106‬‬ ‫‪108‬‬ ‫‪110‬‬

‫‪CourseID‬‬ ‫‪1‬‬ ‫‪2‬‬ ‫‪3‬‬ ‫‪4‬‬ ‫‪5‬‬ ‫‪6‬‬

‫أكتب استعالما يحتلن السجل الذي رقمه ‪( 3‬أي ‪ )CourseID=3‬بحيث يجعل عدد الساعات ‪112‬‬ ‫بدال من ‪:56‬‬

‫‪152‬‬


‫الحل‬ UPDATE Courses SET [Hours]=112 WHERE CourseID=3

:‫بعد تنفيذ األمر يصبح محتوى الجدول كالتالي‬

CourseID 1 2 3 4 5 6

Code 100 102 104 106 108 110

Date 20/12/2011 30/12/2011 03/12/2011 11/11/2011 22/09/2010 02/09/2010

Category CS CS En Ar CS CS

Title C# Java English Level 1 Arabic For Beginners SQL Basics MS Access

Hours 112 112 112 112 112 112

‫ بدال‬56 ‫) بحيث يجعل عدد الساعات‬CourseID=4 ‫ (أي‬4 ‫أكتب استعالما يحتلن السجل الذي رقمه‬ :05/11/2011 ‫ لتصبح‬Date ‫ ويغير قيمة الحقل‬112 ‫من‬ ‫الحل‬ UPDATE Courses SET [Hours]=56, [Date]=# 05/11/2011# WHERE CourseID=4

:‫بعد تنفيذ األمر يصبح محتوى الجدول كالتالي‬ CourseID 1 2 3 4 5 6

Code 100 102 104 106 108 110

Date 20/12/2011 30/12/2011 03/12/2011 05/11/2011 22/09/2010 02/09/2010

Category CS CS En Ar CS CS

153

Title C# Java English Level 1 Arabic For Beginners SQL Basics MS Access

Hours 112 112 112 56 112 112


‫الحذف‬ ‫يتم حذف سجالت موجودة في جدول ما بواسطة األمر ‪DELETE‬‬ ‫الصيغة العامة لألمر هي كالتالي‪:‬‬ ‫]‪DELETE * FROM TableName [WHERE Condition‬‬ ‫أي قم بحذف جميع السجالت من الجدول المعطى وفق الشرط المعطى‪ .‬الحظ أن استعمال األمر‬ ‫‪ DELETE‬بدون شرط سيؤدي الى حذف جميع السجالت الموجودة في الجدول‪ .‬أي أن األمر‬

‫‪DELETE * FROM TableName‬‬ ‫يُستعمل لتفريغ الجداول من محتواها‪.‬‬

‫أمثلة‬ ‫ليكن محتوى الجدول ‪ Courses‬كالتالي‪:‬‬ ‫‪Hours‬‬ ‫‪112‬‬ ‫‪112‬‬ ‫‪56‬‬ ‫‪112‬‬ ‫‪112‬‬ ‫‪112‬‬

‫‪Title‬‬ ‫‪C#‬‬ ‫‪Java‬‬ ‫‪English Level 1‬‬ ‫‪Arabic For Beginners‬‬ ‫‪SQL Basics‬‬ ‫‪MS Access‬‬

‫‪Category‬‬ ‫‪CS‬‬ ‫‪CS‬‬ ‫‪En‬‬ ‫‪Ar‬‬ ‫‪CS‬‬ ‫‪CS‬‬

‫‪Date‬‬ ‫‪20/12/2011‬‬ ‫‪30/12/2011‬‬ ‫‪03/12/2011‬‬ ‫‪11/11/2011‬‬ ‫‪22/09/2010‬‬ ‫‪02/09/2010‬‬

‫‪Code‬‬ ‫‪100‬‬ ‫‪102‬‬ ‫‪104‬‬ ‫‪106‬‬ ‫‪108‬‬ ‫‪110‬‬

‫‪CourseID‬‬ ‫‪1‬‬ ‫‪2‬‬ ‫‪3‬‬ ‫‪4‬‬ ‫‪5‬‬ ‫‪6‬‬

‫أكتب استعالما جميع السجالت التي قيمة الحقل ‪ Category‬عندها ‪CS‬‬ ‫الحل‬ ‫’‪DELETE * FROM Courses WHERE Category=’CS‬‬

‫‪154‬‬


:‫بعد تنفيذ األمر يصبح محتوى الجدول كالتالي‬

CourseID 3 4

Code 104 106

Date 03/12/2011 11/11/2011

Category En Ar

Title English Level 1 Arabic For Beginners

Hours 112 112

:‫ على النحو التالي‬IN ‫إمكانية أخرى للحل تكمن في استعمال المعامل‬

DELETE * FROM Courses WHERE CourseID IN (1,2,5,6) :‫ على النحو التالي‬BETWEEN ‫أو بواسطة استعمال المعامل‬

DELETE * FROM Courses WHERE CourseID BETWEEN 1 AND 2 OR CourseID BETWEEN 5 AND 6

155


‫الدوال‬ ‫توفر لغة ‪ SQL‬مجموعة من الدوال‬ ‫• الحسابية )‪ (SQL Aggregate Functions‬التي تعيد قيمة واحدة بناء على حسابات تمت لقيم‬ ‫حقل أو عمود كامل‬ ‫• والدوال الثابتة أو السكاالرية )‪ (SQL Scalar functions‬التي تأخذ قيمة واحدة وتعيد أيضا‬ ‫قيمة واحدة فقط‪.‬‬ ‫الجدول التالي ‪ WorkHours‬سيخدمنا لشرح األمثلة‪ .‬الجدول يخزن عدد ساعات العمل لكل يوم من‬ ‫أيام العمل لعمال معينين‪:‬‬ ‫‪Hours‬‬ ‫‪8‬‬ ‫‪9‬‬ ‫‪8‬‬ ‫‪8‬‬ ‫‪10‬‬ ‫‪8‬‬

‫‪MyDate‬‬ ‫‪20/12/2011‬‬ ‫‪21/12/2011‬‬ ‫‪22/12/2011‬‬ ‫‪20/12/2011‬‬ ‫‪21/12/2011‬‬ ‫‪22/12/2011‬‬

‫‪WorkerID‬‬ ‫‪100‬‬ ‫‪100‬‬ ‫‪100‬‬ ‫‪106‬‬ ‫‪106‬‬ ‫‪106‬‬

‫‪ID‬‬ ‫‪1‬‬ ‫‪2‬‬ ‫‪3‬‬ ‫‪4‬‬ ‫‪5‬‬ ‫‪6‬‬

‫ولنبدأ بشرح الدوال الحسابية‬ ‫الدالة )‪ AVG(Column‬تتلقى اسم حقل من نوع ‪ Number‬وتعيد لنا معدل قيم الحقل ( العمود )‬ ‫الذي حددناه لها وفقط للسجالت التي ال تكون فارغة‪.‬‬

‫مثال‪ :‬أكتب استعالما يعيد معدل ساعات العامل الذي رقمه ‪.100‬‬ ‫الحل‪:‬‬ ‫‪156‬‬


‫]‪SELECT AVG(Hours) AS [Hours Average‬‬ ‫‪FROM WorkHours‬‬ ‫‪WHERE WorkerID=100‬‬ ‫النتيجة‪:‬‬

‫‪Hours Average‬‬ ‫‪8.3333333333‬‬ ‫مالحظة‬ ‫من المفضل استعمال المعامل ‪ AS‬إلعطاء اسما جديدا لحقل النتيجة وذلك ألن ‪ Access‬يعطي اسما‬ ‫عشوائيا ال معنى له )‪ (Expr1000‬لهذا الحقل اذا لم نستعمل ‪ .AS‬فجدول النتيجة سيكون كالتالي‬ ‫بدون ‪AS‬‬

‫‪Expr1000‬‬ ‫‪8.3333333333‬‬

‫الدالة )‪ SUM(Column‬تتلقى اسم حقل من نوع ‪ Number‬وتعيد لنا المجموع الكلي لقيم الحقل (‬ ‫العمود ) الذي حددناه لها وفقط للسجالت التي ال تكون فارغة‪.‬‬ ‫مثال‪ :‬أكتب استعالما يعيد مجموع الساعات الكلي للعامل الذي رقمه ‪.106‬‬

‫الحل‪:‬‬

‫‪157‬‬


‫]‪SELECT SUM(Hours) AS [Sum Of Hours‬‬ ‫‪FROM WorkHours‬‬ ‫‪WHERE WorkerID=106‬‬ ‫النتيجة‪:‬‬

‫‪Sum Of Hours‬‬ ‫‪26‬‬

‫مثال‪ :‬أكتب استعالما يعيد مجموع الساعات الكلي لجميع العمال يوم ‪.2011/12/21‬‬ ‫الحل‪:‬‬ ‫]‪SELECT SUM(Hours) AS [Sum Of Hours‬‬ ‫‪FROM WorkHours‬‬ ‫‪WHERE MyDate=#21/12/2011#‬‬ ‫النتيجة‪:‬‬

‫‪Sum Of Hours‬‬ ‫‪19‬‬

‫الدالة )‪ COUNT(Column‬تتلقى اسم حقل وتعيد لنا عدد السجالت التي تحقق شرطا معينا‪ .‬اذا‬ ‫كتبنا مكان اسم الحقل الرمز * (وبدون شرط) فان الدالة تعيد عدد جميع األسطرالموجودة في‬ ‫الجدول‪.‬‬ ‫مالحظة‪ :‬استعمال هذه الدالة يكون في أغلب األحيان بالصيغة الثانية أي مع الرمز *‪.‬‬

‫‪158‬‬


‫مثال‪ :‬أكتب استعالما يعيد حجم الجدول ‪( WorkHours‬أي عدد جميع األسطرالموجودة في‬ ‫الجدول)‪.‬‬ ‫الحل‪:‬‬ ‫]‪SELECT COUNT(*) AS [Total Num Of Rows‬‬ ‫‪FROM WorkHours‬‬ ‫النتيجة‪:‬‬ ‫‪Total Num Of Rows‬‬ ‫‪6‬‬

‫مثال‪ :‬أكتب استعالما يعيد عدد األيام التي عملها العامل الذي رقمه ‪ 100‬خالل شهر ‪ 12‬سنة ‪2011‬‬ ‫الحل‪:‬‬ ‫]‪SELECT COUNT(*) AS [Num Of Days‬‬ ‫‪FROM WorkHours‬‬ ‫‪WHERE WorkerID=100 AND MyDate BETWEEN #1/12/2011# AND‬‬ ‫‪#31/12/2011#‬‬ ‫النتيجة‪:‬‬

‫‪Num Of Days‬‬ ‫‪3‬‬

‫الدالة )‪ MAX(Column‬تتلقى اسم حقل من نوع ‪ Number‬أو ‪ Date/Time‬وتعيد لنا أكبر قيمة‬ ‫لهذا الحقل (العمود) الذي حددناه لها وفقط للسجالت التي ال تكون فارغة‪.‬‬ ‫مثال‪ :‬أكتب استعالما يعيد أكبر عدد ساعات عمله العامل الذي رقمه ‪ 100‬خالل شهر ‪ 12‬سنة‬ ‫‪.2011‬‬

‫‪159‬‬


‫الحل‪:‬‬ ‫]‪SELECT MAX(Hours) AS [Max Hours in 12/2011‬‬ ‫‪FROM WorkHours‬‬ ‫‪WHERE WorkerID=100‬‬ ‫‪AND MyDate BETWEEN #1/12/2011# AND #31/12/2011#‬‬ ‫النتيجة‪:‬‬

‫‪Max Hours in 12/2011‬‬ ‫‪9‬‬

‫واحدة من أهم استعماالت هذه العملية تكمن في استخراج قيمة المفتاح الرئيسي آلخر سجل أُدخل الى‬ ‫جدول مفتاحه الرئيسي من نوع ‪.Auto Number‬‬ ‫الدالة )‪ MIN(Column‬تتلقى اسم حقل من نوع ‪ Number‬أو ‪ Date/Time‬وتعيد لنا أصغر قيمة‬ ‫لهذا الحقل ( العمود ) الذي حددناه لها وفقط للسجالت التي ال تكون فارغة‪.‬‬

‫‪160‬‬


‫إنشاء مجموعات في جدول النتيجة‬ ‫اإلضافة ‪ Group BY‬تمكننا من إنشاء مجموعات في جدول النتيجة‪ .‬لبيان ذلك نفرض أننا نريد‬ ‫استخراج معلومات من جدول الطالب التالي بحيث يُعرض معدل كل طالب في جميع المواضيع‬ ‫حسب رقم الطالب )‪:(StudentID‬‬ ‫جدول ‪:Students‬‬ ‫‪Mark‬‬ ‫‪80‬‬ ‫‪90‬‬ ‫‪89‬‬ ‫‪88‬‬ ‫‪100‬‬ ‫‪95‬‬

‫‪StudentID‬‬ ‫‪100‬‬ ‫‪100‬‬ ‫‪100‬‬ ‫‪106‬‬ ‫‪106‬‬ ‫‪106‬‬

‫‪SubjectID‬‬ ‫‪4‬‬ ‫‪5‬‬ ‫‪6‬‬ ‫‪4‬‬ ‫‪5‬‬ ‫‪6‬‬

‫‪ID‬‬ ‫‪1‬‬ ‫‪2‬‬ ‫‪3‬‬ ‫‪4‬‬ ‫‪5‬‬ ‫‪6‬‬

‫جدول النتيجة يجب أن يكون كالتالي‪:‬‬ ‫‪Average‬‬ ‫‪86.333‬‬ ‫‪94.333‬‬

‫‪StudentID‬‬ ‫‪100‬‬ ‫‪106‬‬

‫الحظ أن الجدول يحوي معدل كل طالب في الثالثة مواضيع التي تقدم إليها‪ .‬حتى اآلن كنا نحصل‬ ‫على قيمة واحدة (معدل أو مجموع أو عدد ‪ .)...‬االستعالم التالي ينجز المطلوب‪:‬‬

‫]‪SELECT StudentID, AVG(Mark) AS [Average‬‬ ‫‪FROM Students‬‬ ‫‪GROUP BY StudentID‬‬

‫‪161‬‬


‫الجزء األخير ‪ GROUP BY StudentID‬يؤدي إلى تقسيم الجدول إلى مجموعات ‪ Groups‬بناء‬ ‫على اسم الحقل الذي جاء بعد ‪ GROUP BY‬أي ‪ .StudentID‬بعد هذا التقسيم إلى مجموعات يتم‬ ‫حساب المعدل لكل مجموعة على حدا‪:‬‬

‫‪Mark‬‬ ‫‪80‬‬ ‫‪90‬‬ ‫‪89‬‬ ‫‪88‬‬ ‫‪100‬‬ ‫‪95‬‬

‫‪StudentID‬‬ ‫‪100‬‬ ‫‪100‬‬ ‫‪100‬‬ ‫‪106‬‬ ‫‪106‬‬ ‫‪106‬‬

‫‪SubjectID‬‬ ‫‪4‬‬ ‫‪5‬‬ ‫‪6‬‬ ‫‪4‬‬ ‫‪5‬‬ ‫‪6‬‬

‫‪ID‬‬ ‫‪1‬‬ ‫‪2‬‬ ‫‪3‬‬ ‫‪4‬‬ ‫‪5‬‬ ‫‪6‬‬

‫المجموعة األولى‬

‫المجموعة الثانية‬

‫طبعا بإمكاننا أن نرتب النتائج ترتيبا تنازليا مثال بحسب المعدل المحسوب من خالل استعمال‬ ‫‪:ORDER BY‬‬ ‫‪SELECT StudentID, AVG(Mark) AS Average‬‬ ‫‪FROM Students‬‬ ‫‪GROUP BY StudentID‬‬ ‫‪ORDER BY AVG(Mark) DESC‬‬ ‫حينها يكون جدول النتيجة كالتالي‪:‬‬ ‫‪Average‬‬ ‫‪94.333‬‬ ‫‪86.333‬‬

‫‪StudentID‬‬ ‫‪106‬‬ ‫‪100‬‬

‫الحظ أنه ليس بالضرورة للحقل الذي يتم تقسيم الجدول بحسبه (‪ StudentID‬في المثال) أن يكون‬ ‫ضمن األمر ‪ .SELECT‬لكن حينها ال يظهر هذا الحقل في جدول النتيجة‪ .‬لذلك ألالستعالم التالي‬ ‫يعيد الجدول التالي‪:‬‬

‫‪162‬‬


SELECT AVG(Mark) AS Average FROM Students GROUP BY StudentID ORDER BY AVG(Mark) DESC

Average 94.333 86.333

163


‫‪ADO.NET‬‬ ‫‪ActiveX Data Objects‬‬

‫ما هي تقنية ‪Ado.net‬‬ ‫هي مجموعة من الفئات (‪ )Classes‬المدمجة مع إطار عمل دوت نت (أي الـ ‪DOT NET‬‬ ‫‪ (Framework‬والتي تمكننا من الوصول إلى البيانات الموجودة في قاعدة بيانات ما من أجل‬ ‫استخراج المعلومات أو من أجل تعديلها أو حذفها أو إضافة سجالت جديدة إليها‪.‬‬ ‫هذه الفئات موجودة ضمن فضاء األسماء ‪ System.Data.OleDb‬ولذلك يجب علينا أن نضيف هذا‬ ‫الفضاء إلى التطبيق من خالل األمر‬ ‫‪Import System.Data. OleDb‬‬ ‫الشكل التالي يبين لنا ما يسمى بمعمارية الفئات (أي الـ ‪.)ADO.NET Classes Architecture‬‬ ‫المصدر‪http://msdn.microsoft.com/en-us/library/ff647768.aspx :‬‬

‫نقاط هامة لفهم المكونات الظاهرة بالصورة والتي معظمها أسماء لفئات معينة‬

‫‪164‬‬


‫‪ .1‬الوصول الى المعلومات الموجودة بأي ملف يقتضي معرفة اسم الملف الكامل أي يشمل‬ ‫مكان وجوده في القرص الصلب للحاسوب وهو ما يسمى بالمسار الكامل ( ‪Full‬‬ ‫‪ .)Path‬ثم يتم بعد ذلك فتح الملف لمعالجة المعلومات‪ .‬الفئة المسؤولة عن فتح قواعد‬ ‫البيانات والتي توفر لنا عمليات مناسبة للقيام بذلك هي الفئة ‪ Connection‬أو‬ ‫‪ .OleDbConnection‬واضح أن االسم يشير الى وظيفة إنشاء اتصال مع قاعدة‬ ‫البيانات‪.‬‬ ‫‪ .2‬االتصال المباشر مع قاعدة البيانات يتم من خالل مكتبات )‪ (Software Libraries‬خاصة‬ ‫تسمى مزودات أي ‪ .Providers‬تحتوي هذه المكتبات على مجموعة من العمليات (أي الدوال‬ ‫واإلجراءات) التي تمكننا من الوصول إلى القاعدة وفتحها وقراءة وكتابة البيانات‪.‬‬

‫‪ .3‬معالجة البيانات الموجودة في قاعدة بيانات عالئقية تتم من خالل االستعانة بلغة ‪SQL‬‬ ‫فقط‪ .‬األوامر المكتوبة بلغة ‪ SQL‬تسمى ‪ Commands‬أو ‪.SQL Statements‬‬ ‫الفئة المسؤولة عن تنفيذ مثل هذه األوامر هي الفئة ‪ Command‬أو‬ ‫‪ .OleDbCommand‬تمكننا هذه الفئة من تنفيذ جميع األوامر التي نعرفها من لغة‬ ‫‪ SQL‬وهي‪SELECT, DELETE, UPDATE, INSERT INTO :‬‬ ‫وغيرها‪.‬‬ ‫‪ .4‬تُسمى قاعدة البيانات ‪ Data Base‬أو ‪.Data Source‬‬ ‫‪ .5‬نتيجة تنفيذ األمر ‪ SELECT‬تكون دائما جدول معلومات أي ‪ .DataTable‬هذا‬ ‫الجدول قد يكون فار ًغا ولكن مبناه حتى عندما يكون فار ًغا يكون وفق مبنى االستعالم‬ ‫أي وفق مجموعة الحقول التي طلبنا قيمها‪.‬‬ ‫‪ .6‬الفئة ‪ DataSet‬عبارة عن مجموعة أي ‪Set‬‬ ‫• من كائنات ‪ DataTable‬أي مجموعة جداول‬ ‫• والعالقات بين الجدوال (ان ُوجدت)‬ ‫ولذلك يمكننا النظر الى كائن من نوع ‪ DataSet‬على أنه كل قاعدة البيانات‪.‬‬ ‫‪ .7‬تخزين هذه النتيجة في كائن من نوع ‪ DataTable‬أو ‪ DataSet‬يتم من قبل وسيط ما‬ ‫بين الوسط المادي أي الملف نفسه )‪ (Physical File‬والكائن‪ .‬الفئة التي تقوم بدور هذا‬ ‫الوسيط هي الفئة ‪ DataAdapter‬أو ‪ .OleDbDataAdapter‬تمثل هذه الفئة‬ ‫الجسر الذي يربط بين ‪ DataSet‬وقاعدة البيانات ويدعم أوامر ‪Select - Update -‬‬ ‫‪165‬‬


‫‪ Delete - Insert‬وبالتالي بإمكانه القيام بعمليات مختلفة على البيانات كما أنه‬ ‫المسؤول عن تحميل أو تعبئة كائن ‪ DataSet‬بالبيانات‪ .‬الحظ أن عمل هذه الفئة يتم‬ ‫باالتجاهين‪ :‬من قاعدة البيانات الى الـ ‪ DataSet‬والعكس‪.‬‬

‫‪166‬‬


‫الوصول الى البيانات‬ ‫• يُلخص الجدول التالي األوامر الالزمة لفتح قاعدة البيانات برمجيًا وانشاء كائن اتصال معها‪.‬‬ ‫نفضل في هذه المرحلة أن يكون اسم قاعدة البيانات ‪ DB.accdb‬وذلك ألننا سوف نستعمل في‬ ‫التطبيقات قاعدة واحدة فقط‪ .‬بشكل عام بامكاننا تمرير اسم القاعدة كبارامتر الى العملية التي تفتح‬ ‫القاعدة ونترك ذلك كتمرين اضافي للقارئ‪.‬‬ ‫الشرح‬ ‫هنا يتم تجهيز نص االتصال أي الـ‬

‫األمر‬ ‫‪Dim ConnectionString, strDB As String‬‬

‫‪ Connection String‬لقاعدة بيانات‬

‫‪strDB = Application.StartupPath +‬‬

‫من نوع ‪ .MS Access‬نص‬ ‫االتصال عبارة عن نص يحتوي على‬ ‫معلومات عن قاعدة البيانات وعن‬

‫"‪"\App_Data\DB.accdb‬‬ ‫= ‪ConnectionString‬‬ ‫‪"Provider=Microsoft.ACE.OLEDB.12.0;Data‬‬ ‫‪Source=" + strDB‬‬

‫ال ُمزود التابع لها‪ .‬نص االتصال مكون‬ ‫من مجموعة من األزواج التي يفصل‬ ‫بينها الرمز ; كل زوج مكون من اسم‬ ‫وقيمة يفصل بينها الرمز =‪ .‬الشرح‬ ‫ال ُمفصَّل موجود في الجدول التالي‪.‬‬ ‫إنشاء كائن من الفئة‬ ‫‪ OleDbConnection‬وتزويده‬

‫‪Dim OleDBConn As OleDbConnection = New‬‬ ‫)‪OleDbConnection(ConnectionString‬‬

‫بنص االتصال الذي يحتوي على‬ ‫معلومات عن القاعدة‪.‬‬ ‫فتح القاعدة بمساعدة العملية ‪Open‬‬

‫;)(‪OleDBConn.Open‬‬

‫التابعة للفئة ‪OleDbConnection‬‬

‫‪167‬‬


‫يحتوي الجدول التالي على شرح ُمفصَّل لمبنى نص االتصال‬ ‫الشرح‬

‫القيمة‬

‫االسم‬

MS 2010 ‫ هذه القيمة تدل على أن قاعدة البيانات من نوع‬Microsoft.ACE.OLEDB.12.0 Provider Access ‫ حفظ قاعدة البيانات في‬VB.NET ‫من ال ُمعتاد في برامج‬

.‫ المسار الكامل لقاعدة البيانات‬Data

.App_Data ‫مجلد خاص ضمن مجلدات البرنامج باسم‬

Source

‫ تعيد لنا مسار‬Application.StartupPath ‫الخاصية‬ ‫المجلد أي المكان المخزن فيه ملف التشغيل وهو (خالل‬ App_Data ‫ المجلد‬.Release ‫ أو‬Debug ‫البرمجة) اما‬ ‫يجب أن يكون (في هذه الحالة) مجلدا داخل واحد من‬ Release ‫ أو‬Debug ‫المجلدين‬

Dbase ‫ ضمن الفئة‬MakeConnection ‫ضعت هذه األوامر في العملية‬ ِ ‫ُو‬ :‫ادعاء الدخول‬ OleDbConnection ‫ تعيد مؤشرًا على كائن االتصال أي كائن من الفئة‬:‫ادعاء الخروج‬ Public Class Dbase Public Function MakeConnection() As OleDb.OleDbConnection Dim connectionString, strDB As String strDB = Application.StartupPath + "\App_Data\DB.accdb" connectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + strDB Dim OleDBConn As OleDbConnection = New OleDbConnection(connectionString) OleDBConn.Open() Return OleDBConn End Function End Class

168


‫تنفيذ استعالمات أي ‪SELECT Queries‬‬ ‫ضعت أوامر تنفيذ االستعالمات في العملية ‪ SelectFromTable‬ضمن الفئة ‪ .Dbase‬وتم‬ ‫ُو ِ‬ ‫شرحها سطرًا سطرًا‪.‬‬ ‫ادعاء الدخول‪ :‬نص االستعالم ‪strSql‬‬ ‫ادعاء الخروج‪ :‬تنفذ االستعالم على القاعدة وتعيد مؤشرًا على كائن ‪ DataTable‬يحتوي على نتيجة‬ ‫االستعالم‬ ‫‪Public Function SelectFromTable(ByVal strSql As String) As DataTable‬‬ ‫انشاء اتصال مع قاعدة البيانات '‬ ‫‪Dim c As OleDbConnection‬‬ ‫)(‪c = MakeConnection‬‬ ‫انشاء كائن لتنفيذ أوامر ‪' SQL‬‬ ‫‪Dim comm As New OleDbCommand‬‬ ‫اعطاؤه نص االستعالم '‬ ‫‪comm.CommandText = strSql‬‬ ‫واعطاؤه كائن االتصال '‬ ‫‪comm.Connection = c‬‬ ‫انشاء كائن لحفظ نتيجة االستعالم '‬ ‫‪Dim dt As New DataTable‬‬ ‫انشاء كائن وسيط مسؤول عن تعبئة جدول التنيجة في الكائن ‪' dt‬‬ ‫)‪Dim da As New OleDbDataAdapter(comm‬‬ ‫تعبئة جدول التنيجة في الكائن ‪' dt‬‬ ‫)‪da.Fill(dt‬‬ ‫اغالق االتصال '‬ ‫)(‪c.Close‬‬ ‫اعادة مؤشرعلى كائن ‪' DataTable‬‬ ‫‪Return dt‬‬ ‫‪End Function‬‬

‫‪169‬‬


‫تنفيذ أوامر ‪ SQL‬ال تعيد جدول نتيجة ‪DELETE, UPDATE, INSERT INTO‬‬ ‫ضعت هذه األوامر في العملية ‪ ChangeTable‬ضمن الفئة ‪ .Dbase‬وتم شرحها سطرًا سطرًا‪.‬‬ ‫ُو ِ‬ ‫ادعاء الدخول‪ :‬نص االستعالم ‪strSql‬‬ ‫ادعاء الخروج‪ :‬تنفذ االستعالم على القاعدة وتعيد عدد األسطر أو السجالت التي تأثرت من األمر أي‬ ‫أضيفت اذا كان األمر ‪ INSERT INTO‬أو حذفت اذا كان األمر ‪ DELETE‬أو ُع ّدلت اذا كان‬ ‫األمر ‪UPDATE‬‬ ‫‪Public Function ChangeTable(ByVal strSql As String) As Integer‬‬ ‫انشاء اتصال مع قاعدة البيانات '‬ ‫‪Dim c As OleDbConnection‬‬ ‫)(‪c = MakeConnection‬‬ ‫‪Dim comm As New OleDbCommand‬‬ ‫اعطاؤه نص االستعالم '‬ ‫‪comm.CommandText = strSql‬‬ ‫واعطاؤه كائن االتصال '‬ ‫‪comm.Connection = c‬‬ ‫العملية ‪' ExecuteNonQuery‬‬ ‫تُنفذ األمر وتعيد عدد األسطر أو السجالت التي تأثرت من األمر'‬ ‫‪Dim nAffectedRows As Integer‬‬ ‫()‪nAffectedRows = comm.ExecuteNonQuery‬‬ ‫اغالق االتصال '‬ ‫)(‪c.Close‬‬ ‫اعادة عدد األسطر أو السجالت '‬ ‫‪Return nAffectedRows‬‬ ‫‪End Function‬‬

‫‪170‬‬


‫تنفيذ أوامر ‪ SQL‬تعيد قيمة واحدة‬ ‫ذكرنا فيما سبق في الفصل عن لغة ‪ SQL‬أنها توفر مجموعة من الدوال التي تُعيد قيمة واحدة‬ ‫)‪ (Scalar‬مثل الدوال (‪ .)AVG, SUM, MAX, MIN, COUNT‬لذلك سنكتب عملية مساعدة‬ ‫ضمن الفئة ‪ Dbase‬تتلقى نص استالم فيه واحدة من هذه الدوال أو شبيهاتها وتُعيد لنا القيمة الناتجة‬ ‫عن هذا التنفيذ‪.‬‬ ‫ضعت هذه األوامر في العملية ‪ ExecuteScalar‬ضمن الفئة ‪ .Dbase‬وتم شرحها سطرًا سطرًا‪.‬‬ ‫ُو ِ‬ ‫ادعاء الدخول‪ :‬نص االستعالم ‪strSql‬‬ ‫ادعاء الخروج‪ :‬تنفذ االستعالم على القاعدة وتعيد القيمة الناتجة عن هذا التنفيذ‪ .‬الحظ أن نوع القيمة‬ ‫ال ُمرجعة ‪ Object‬أي أنه يمكنها أن تكون من أي نوع ممكن من األنواع التي تدعمها وتوفرها قاعدة‬ ‫البيانات‪.‬‬ ‫‪Public Function ExecuteScalar(ByVal strSql As String) As Object‬‬ ‫انشاء اتصال مع قاعدة البيانات '‬ ‫‪Dim c As OleDbConnection‬‬ ‫)(‪c = MakeConnection‬‬ ‫‪Dim comm As New OleDbCommand‬‬ ‫اعطاؤه نص االستعالم '‬ ‫‪comm.CommandText = strSql‬‬ ‫واعطاؤه كائن االتصال '‬ ‫‪comm.Connection = c‬‬ ‫العملية ‪' ExecuteScalar‬‬ ‫تُنفذ األمر وتعيد القيمة '‬ ‫‪Dim val As Object‬‬ ‫()‪val = comm.ExecuteScalar‬‬ ‫اغالق االتصال '‬ ‫)(‪c.Close‬‬ ‫اعادة عدد األسطر أو السجالت '‬ ‫‪Return val‬‬ ‫‪End Function‬‬ ‫‪171‬‬


‫ كاملة‬Dbase ‫الفئة‬ Imports System.Data.OleDb Public Class Dbase Public Function MakeConnection() As OleDb.OleDbConnection Dim connectionString, strDB As String strDB = Application.StartupPath + "\App_Data\DB.accdb" connectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + strDB Dim OleDBConn As OleDbConnection = New OleDbConnection(connectionString) OleDBConn.Open() Return OleDBConn End Function Public Function SelectFromTable(ByVal strSql As String) As DataTable Dim c As OleDbConnection c = MakeConnection() Dim comm As New OleDbCommand comm.CommandText = strSql comm.Connection = c Dim dt As New DataTable Dim da As New OleDbDataAdapter(comm) da.Fill(dt) c.Close() Return dt End Function Public Function ChangeTable(ByVal strSql As String) As Integer Dim c As OleDbConnection c = MakeConnection() Dim comm As New OleDbCommand comm.CommandText = strSql comm.Connection = c Dim nAffectedRows As Integer nAffectedRows = comm.ExecuteNonQuery() c.Close() Return nAffectedRows End Function

172


‫‪Public Function ExecuteScalar(ByVal strSql As String) As Object‬‬ ‫‪Dim c As OleDbConnection‬‬ ‫)(‪c = MakeConnection‬‬ ‫‪Dim comm As New OleDbCommand‬‬ ‫‪comm.CommandText = strSql‬‬ ‫‪comm.Connection = c‬‬ ‫‪Dim val As Object‬‬ ‫)(‪val = comm.ExecuteScalar‬‬ ‫)(‪c.Close‬‬ ‫‪Return val‬‬ ‫‪End Function‬‬ ‫‪End Class‬‬

‫فيما يلي سنقوم بتطوير تطبيقات تستعمل قاعدة بيانات من نوع ‪ .MS Access‬هذه التطبيقات‬ ‫ستستعمل الفئة ‪ Dbase‬للوصول الى قاعدة البيانات ومن ثم عرض المعلومات والقيم بتعديلها‬ ‫وحذفها واضافة سجالت جديدة الى الجداول‪.‬‬ ‫مالحظة مهمة جدا‪ :‬في حال حصول أي خطأ في هذه العمليات فانها سوف ترمي استثناءات‪ .‬ولذلك‬ ‫علينا احاطة الكود الذي يستدعي هذه العمليات بأمر ‪.Try/Catch‬‬

‫‪173‬‬


‫‪3-Levels Architecture‬‬ ‫يتكون التطبيق عادة من عدة مكونات برمجية وهي‬ ‫• النماذج أي الـ ‪ Forms‬وظيفتها عرض البيانات لل ُمستخدم‪ .‬وتُسمى أيضا بواجهة ال ُمستخدم‬ ‫التخطيطية‬ ‫‪ (GUI – Graphical Use Interface) o‬أو ‪Presentation Layer‬‬ ‫• البرمجة (العمليات والفئات ال ُمختلفة) التي تتعامل مع قاعدة البيانات أي التي تفتح القاعدة وتقرأ‬ ‫منها معلومات أو بيانات أو تكتب فيها بيانات وتحتلنها وتُسمى أيضا‬ ‫‪Application Layer o‬‬ ‫• قاعدة (أو قواعد) البيانات وتُسمى أيضا‬ ‫‪Database Layer o‬‬ ‫لذلك يُفضل مطورو التطبيقات استعمال ما يُسمى معمارية الطبقات الثالث ‪(3-Levels‬‬ ‫)‪ .Architecture‬تفصل هذه المعمارية هذه المكونات الثالث عن بعضها البعض أي أنها تفصل ما‬ ‫بين واجهة االستخدام المعروضة وإجراءات المعالجة في التطبيق‪ ،‬وقاعدة البيانات‪ .‬من أهم ايجابيات‬ ‫هذه المعمارية أنها تمكننا من بناء تطبيقات م ِرنة وقابلة إلعادة االستخدام والصيانة‪ .‬فعند الحاجة‬ ‫إلضافة طبقات أو تعديلها ال توجد حاجة إلعادة كتابة التطبيق بالكامل أو من جديد‪ .‬وانما يكفي تبديل‬ ‫الطبقة التي تغيرت‪ .‬فمثال إذا تقرر أن تُغير قاعدة البيانات من مثال ‪ MS Access‬الى ‪MS SQL‬‬ ‫‪ Server‬فان الطبقة التي تتأثر بالتغيير هي فقط طبقة قاعدة البيانات‪ .‬إضافة الى ذلك فسوف ال نرى‬ ‫أية أوامر ‪ SQL‬مبعثرة ومتكررة داخل النماذج وانما فقط كائنات من الفئات المناسبة التي تقوم بتنفيذ‬ ‫المهام ال ُمختلفة التي تطلب النماذج تنفيذها على قاعدىة البيانات‪.‬‬ ‫لذلك سنعتمد في الفصول التالية‪ ،‬التي نبدأ فيها باستعمال قاعدة بيانات‪ ،‬هذه البُنية بحيث نكتب لكل‬ ‫جدول في قاعدة البيانات فئة بلغة ‪ VB.NET‬وبنفس اسم الجدول بعد اضافة الكلمة ‪ Class‬الى‬ ‫بدايتها لتمييزها على أنها فئة خاصة بنا (مثال ‪ ClassUsers‬لجدول باسم ‪ .)Users‬توفر هذه الفئة‬ ‫عادةً‬ ‫• خاصيّة لكل حقل من حقول الجدول‬ ‫• وتوفر مجموعة كافية من العمليات البنائية‬ ‫‪174‬‬


‫• والعمليات التي تُنفذ معظم أو كل العمليات ال ُمتوقع تنفيذها على الجدول مثل‬ ‫‪ o‬استرجاع بيانات ُمعينة (أي ‪)SELECT‬‬ ‫‪ o‬اضافة بيانات ُمعينة (أي ‪)INSERT INTO‬‬ ‫‪ o‬حذف بيانات ُمعينة (أي ‪)DELETE‬‬ ‫‪ o‬تحديث أو حتلنة بيانات ُمعينة (أي ‪)UPDATE‬‬ ‫‪ o‬اعادة قيمة واحدة‬ ‫الصورة التالية تُوضح هذه المعمارية‬

‫‪Presentation Layer‬‬ ‫عرض البيانات‬

‫‪Application Layer‬‬ ‫برمجة التواصل مع القاعدة‬

‫‪Database Layer‬‬

‫قاعدة البيانات‬

‫كمثال على ذلك سنعيد كتابة نموذج الـ ‪ Login‬الذي ُشرح سابقًا بحيث يتم هذه المرة قراءة المعلومات‬ ‫عن ال ُمستخدم من قاعدة البيانات‪.‬‬ ‫أوال سنضيف الفئة ‪ Dbase‬الى المشروع من خالل الضغط في الـ ‪ Solution Explorer‬على الزر‬ ‫األيمن للفارة ثم نختار األمر ‪ Class‬الذي يظهر عند الضغط على األمر ‪ Add‬ثم نُدخل اسم الفئة أي‬ ‫االسم ‪ .Dbase.vb‬بعد ذلك نُغلق النافذة بالضغط على الزر ‪.Add‬‬ ‫‪175‬‬


‫اآلن ننسخ عمليات الفئة ‪ Dbase‬من الصفحات السابقة ونُضيفها الى الفئة ونحفظ الملف‪.‬‬ ‫قاعدة البيانات‬ ‫نضيف الى المشروع قاعدة البيانات ‪ DB.accdb‬والتي تحتوي فقط على جدول واحد هو الجدول‬ ‫‪ Users‬وفق المبنى التالي‬

‫ننسخ قاعدة البيانات ونحفظها في المجلد ‪ App_Data‬الذي علينا أن ننشئه في المجلد ‪ Bin‬كما هو‬ ‫مبين كالتالي‪:‬‬ ‫‪MDI_App\MDI_App\Bin\Debug\App_Data‬‬

‫‪176‬‬


‫بعد ذلك نكتب الفئة ‪ ClassUsers.vb‬التي تُشكل بالنسبة للتطبيق الـ ‪.Application Layer‬‬ ‫‪Public Class ClassUsers‬‬ ‫لكل حقل خاصيّة أو صفة‬

‫‪Private UserID, UserName, UserPW As String‬‬

‫)‪Public Sub New(UserName As String, UserPW As String‬‬ ‫‪Me.UserName = UserName‬‬ ‫عملية بنائيّة‬ ‫‪Me.UserPW = UserPW‬‬ ‫‪End Sub‬‬ ‫‪Public Function Login() As Boolean‬‬ ‫عملية تبحث في القاعدة عن ُمستخدم‬ ‫‪Dim strRet As String‬‬ ‫صا‬ ‫بالمواصفات المعطاة‪ .‬العملية تُعيد ن ً‬ ‫"‪strRet = "Not Found‬‬ ‫فار ًغا للداللة على نجاح عملية البحث‪.‬‬ ‫‪Try‬‬ ‫إذا لم تجده تُعيد النص ‪.Not Found‬‬ ‫‪Dim strSQL As String‬‬ ‫أما إذا حصل خطأ ما من نوع استثناء‬ ‫‪Dim Db As New Dbase‬‬ ‫فانها تعيد نص الخطأ الذي يوفره الكائن‬ ‫‪Dim dt As New DataTable‬‬ ‫‪.ex‬‬ ‫"'" ‪Dim strUN = "'" + UserName +‬‬ ‫"'" ‪Dim strPW = "'" + UserPW +‬‬ ‫‪strSQL = "SELECT * FROM Users WHERE UserName=" + strUN‬‬ ‫‪strSQL += " AND UserPW=" + strPW‬‬ ‫صا للداللة على‬ ‫اخترنا أن تعيد الدالة ن ً‬ ‫)‪dt = Db.SelectFromTable(strSQL‬‬ ‫النجاح أو الخطأ حتى نُرجع نص الخطأ‬ ‫‪If dt.Rows.Count = 1 Then‬‬ ‫‪ ex.Message‬للمقطع الذي استدعى‬ ‫"" = ‪strRet‬‬ ‫هذه العملية وبالتالي يتمكن ال ُمبرمج من‬ ‫‪End If‬‬ ‫معرفة مصدر الخطأ‪.‬‬ ‫‪Catch ex As Exception‬‬ ‫‪strRet = ex.Message‬‬ ‫‪End Try‬‬ ‫‪Return strRet‬‬ ‫‪End Function‬‬ ‫‪End Class‬‬

‫الفئة ‪DataTable‬‬ ‫نتيجة تنفيذ أي أمر ‪ SELECT‬بواسطة العملية ‪ SelectFromTable‬التابعة للفئة ‪ Dbase‬تُعيد لنا‬ ‫دائما كائنًا من نوع ‪ DataTable‬يحتوي على جدول النتيجة أي يحتوي على الجدول الذي حصلنا‬ ‫عليه بعد تنفيذ أمر الـ ‪ .SELECT‬أسطر هذا الجدول موجودة في الخاصيّة ‪ Rows‬التابعة لهذا‬ ‫الكائن‪ .‬هذه الخاصيّة توفر من خالل الخاصيّة ‪Count‬عدد األسطر الموجودة في جدول النتيجة‪.‬‬ ‫يظهر ذلك في الكود عند استعمال األمر ‪ dt.Rows.Count‬لمعرفة وفحص عدد األسطر التي‬ ‫حصلنا عليها‪ .‬فان كان عددها يساوي ‪ 1‬معنى ذلك أننا عثرنا على هذا ال ُمستخدم وهو حقًا موجود في‬ ‫جدول الـ ‪ Users‬وبالتالي يُسمح له باستعمال التطبيق‪ .‬الحقًا سنتعرف على كيفية تمشيط كائن من‬ ‫نوع ‪ DataTable‬وقراءة المعلومات منه‪.‬‬ ‫‪177‬‬


FormLogIn ‫ في النموذج‬Login ‫ التابع للزر‬Click ‫برمجة معالج الحدث‬ ‫واآلن نعيد كتابة هذا المعالج بحيث نبحث عن ال ُمستخدم في قاعدة البيانات من خالل استعمال الفئة‬ ClassUsers Private Sub ButtonLogIn_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonLogIn.Click Dim obj As New ClassUsers(TextBoxUserName.Text, TextBoxPassword.Text) Dim strRet As String ClassUsers ‫ من الفئة‬obj ‫ننشئ الكائن‬ strRet = obj.Login() Login ‫ونستدعي العملية‬ If strRet <> "" Then MessageBox.Show(strRet) Me.DialogResult = DialogResult.No Return End If Me.DialogResult = DialogResult.Yes Me.Close() End Sub

‫مقارنة بسيطة بين صيغتي هذا المعالج (السابقة وهذه) تُبرز أهمية وصحة هذا المنهج أي منهج‬ .‫الطبقات الثالث‬

178


‫‪Data Controls‬‬ ‫سوف نقوم في هذا الفصل بشرح تفاصيل التواصل مع قاعدة البيانات من خالل تطوير تطبيق‬ ‫يستعمل قاعدة بيانات الدارة محتوى دليل تلفونات أو ما يُسمى أيضا دفتر تلفونات‪.‬‬

‫قاعدة البيانات‬ ‫فيما يلي نُلخص مكونات القاعدة من جداول وعالقات‬

‫الجداول‬ ‫الجدول ‪ Contacts‬يحتوي هذا الجدول على تفاصيل األشخاص الموجودين في دفتر التلفونات‬

‫الجدول ‪ Groups‬يحتوي هذا الجدول على تفاصيل المجموعات‪ .‬يُمكنُنا هذا التطبيق من انشاء‬ ‫مجموعات لألشخاص الموجودين في دفتر التلفونات مثل مجموعة األصدقاء أو مجموعة األقارب أو‬ ‫أوالد الصف وما الى ذلك‪ .‬الحظ أن الشخص الواحد قد يكون في أكثر من مجموعة وأن المجموعة‬ ‫تحتوي عادة على أكثر من شخص‪ .‬أي أن العالقة بين هذا الجدول والجدول ‪ Contacts‬هي عالقة‬ ‫كثير لكثير كما سيظهر ذلك الحقًا في ُمخطط العالقات‬

‫‪179‬‬


‫الجدول ‪ ContactsGroups‬يربط هذا الجدول بين الجدول ‪ Contacts‬والجدول ‪Groups‬‬ ‫بعالقة كثير‬

‫الجدول ‪ :Users‬يحتوي هذا الجدول على تفاصيل ال ُمستخدمين للتطبيق‬

‫العالقات‬

‫‪180‬‬


‫النموذج الرئيسي‬ ‫تُبين الصور التالية للنموذج الرئيسي أنه يحتوي على ‪ 3‬عناصر قائمة رئيسية وهي‬ ‫• ‪ File‬وهي تحتوي بداخلها على ‪ 3‬عناصر‬ ‫‪ Contacts o‬تحتوي على أوامر الدارة تفاصيل األشخاص‬ ‫‪ Groups o‬تحتوي على أوامر الدارة تفاصيل المجموعات‬ ‫‪ Close o‬الغالق وانهاء عمل التطبيق‬ ‫• ‪ Logout‬للخروج بدون انهاء عمل التطبيق‪ .‬اسم هذا العنصر بعد الخروج يُصبح ‪ Login‬كما‬ ‫ُشرح سابقًا‬ ‫• ‪ Help‬الظهار نموذج يحتوي على شرح لكيفية عمل التطبيق‬

‫‪181‬‬


‫األمر ‪FileContactsAdd‬‬ ‫ولنبدأ بشرح تفاصيل األمر ‪ Add‬التابع للقائمة ‪ .Contacts‬وظيفة هذا األمر تمكين ال ُمستخدم من‬ ‫اضافة أشخاص جدد الى دفتر التلفونات‪ .‬عند اختيار هذا األمر يظهر النموذج التالي‬

‫واضح أننا نوفر هنا لكل حقل من حقول الجدول ‪ Contacts‬أداة مناسبة الدخال قيم الى هذا الحقل‪.‬‬ ‫باستثناء الحقل ‪ ContactID‬الذي هو عبارة عن المفتاح الرئيسي للجدول وهو من نوع رقم تلقائي‬ ‫وبالتالي فالمسؤول عن اعطاء قيمة جديدة لكل سجل جديد هو ‪ MS Access‬نفسه وليس ال ُمستخدم‪.‬‬ ‫األزرار‬ ‫• الزر ‪ Reset‬يقوم بتفريغ الصناديق‬ ‫• الزر ‪ Close‬يُغلق النموذج‬ ‫• الزر ‪ Save‬يقوم بحفظ تفاصيل الشخص الجديد بعد التأكد من صحة االدخال ومن أنه ال‬ ‫يوجد شخص بالدفتر له نفس رقم الهاتف أو نفس رقم الجوال‬

‫‪182‬‬


‫برمجة معالج الحدث ‪ Click‬للزر ‪Reset‬‬ ‫تفريغ الصناديق يتم من خالل اعطاء الخاصيّة ‪ Text‬التابعة لكل صندوق النص الفارغ كقيمة‪ .‬الحظ‬ ‫أننا كتبنا عملية خاصة لهذا الغرض باسم ‪ResetControls‬‬ ‫‪Private Sub ButtonReset_Click(ByVal sender As System.Object,‬‬ ‫)‪ByVal e As System.EventArgs‬‬ ‫‪Handles ButtonReset.Click‬‬ ‫)(‪ResetControls‬‬ ‫‪End Sub‬‬ ‫)(‪Private Sub ResetControls‬‬ ‫"" = ‪TextBoxName.Text‬‬ ‫"" = ‪TextBoxMobileNr.Text‬‬ ‫"" = ‪TextBoxPhoneNr.Text‬‬ ‫"" = ‪TextBoxAddress.Text‬‬ ‫"" = ‪TextBoxDOB.Text‬‬ ‫‪End Sub‬‬

‫برمجة معالج الحدث ‪ Click‬للزر ‪Save‬‬ ‫وظيفة هذا الزر حفظ تفاصيل الشخص الجديد بعد التأكد من صحة االدخال ومن أنه ال يوجد شخص‬ ‫بالدفتر له نفس رقم الهاتف أو نفس رقم الجوال‪.‬‬ ‫قبل أن نبدأ ببرمجة هذا المعالج علينا توفير الفئة ‪ ClassContacts‬التي ستكون مسؤولة عن كل‬ ‫عمليات التواصل التي يطلبها النموذج من قاعدة البيانات‪ .‬كما ذكرنا سابقًا فان هذه الفئة ستكون من‬ ‫مكونات الطبقة ‪.Application Layer‬‬ ‫الفئة ‪ClassContacts‬‬ ‫من ال ُمفضل انشاء مجلد جديد ضمن المشروع باسم ‪ App_Code‬نحفظ فيه جميع الفئات ال ُمكونة‬ ‫لطبقة الـ ‪ .Application‬بامكاننا انشاء المجلد الجديد من خالل الضغط في الـ ‪Solution‬‬ ‫‪ Explorer‬على الزر األيمن للفارة ثم نختار األمر ‪ New Folder‬الذي يظهر عند الضغط على‬ ‫األمر ‪ .Add‬انقل الى هذا المجلد الفئة ‪ Dbase.vb‬آنفة الذكر‪ .‬الصورة التالية تبين هذا المجلد‬ ‫ومحتواه حتى اآلن‬ ‫‪183‬‬


‫برمجة الفئة ‪ClassContacts‬‬ ‫يُلخص الجدول التالية واجهة هذه الفئة‪ .‬بعد ذلك سيتم عرض وشرح برمجة الفئة بشكل كامل‪.‬‬ ‫الخاصيّة أو العملية‬

‫الشرح‬ ‫لكل حقل من حقول الجدول خاصيّة باسمه‬ ‫العمليات البنائية ُكتبت بحسب الحاجة وسهولة االستعمال‪.‬‬

‫‪Get/Set‬‬ ‫تفحص هذه العملية ما إذا كان الشخص موجودًا في الدفتر‬ ‫بنا ًء على أرقام الهواتف‪ .‬إذا لم يكن موجو ًدا تعيد العملية‬ ‫صا فارغا‪ .‬خالف ذلك تعيد شرحا ً اما عن الخطأ إذا‬ ‫ن ً‬ ‫حصل خطأ أو شرحً ا بأنه موجود‪.‬‬ ‫تعيد هذه العملية تفاصيل الشخص بحسب الـ‬ ‫‪ ContactID‬ال ُمزودة من خالل الكائن‪ .‬إذا كان الشخص‬ ‫صا فارغا‪ .‬خالف‬ ‫غير موجود في الدفتر تعيد العملية ن ً‬ ‫ذلك تعيد شر ًحا اما عن الخطأ إذا حصل خطأ أو شر ًحا‬ ‫بأنه غير موجود‪.‬‬ ‫تعيد هذه العملية مصفوفة األشخاص الذين يُشبه اسمهم‬ ‫النص الموجود في ‪ MyName‬ال ُمزود من خالل الكائن‪.‬‬ ‫عملية المقارنة تتم من خالل استعمال المعامل ‪LIKE‬‬ ‫الذي تُوفره لغة ‪.SQL‬‬ ‫تعيد هذه العملية مصفوفة أشخاص فيها تفاصيل جميع‬ ‫األشخاص الموجودين في الدفتر الذي تُوفره لغة ‪.SQL‬‬ ‫تعيد هذه العملية كائن ‪ DataTable‬فيه تفاصيل جميع‬ ‫األشخاص الموجودين في الدفتر‪.‬‬

‫‪ContactID MyName, MobileNr As String‬‬ ‫‪PhoneNr, MyAddress, DateOfBirth As String‬‬ ‫)(‪Public Sub New‬‬ ‫)‪Public Sub New(ContactID As String‬‬ ‫‪Public Sub New(MobileNr As String,‬‬ ‫)‪PhoneNr As String‬‬ ‫‪Public Sub New(MyName As String,‬‬ ‫‪MobileNr As String, PhoneNr As String,‬‬ ‫)‪MyAddress As String, DateOfBirth As String‬‬ ‫… ‪Public Property‬‬ ‫‪Public Function Exists() As String‬‬

‫‪184‬‬

‫‪Public Function GetByContactID() As String‬‬

‫‪Public Function GetByName(ByRef strRet As‬‬ ‫)(‪String) As ClassContacts‬‬

‫‪Public Function GetAllAsArray(ByRef strRet‬‬ ‫)(‪As String) As ClassContacts‬‬ ‫‪Public Function GetAll(ByRef strRet As‬‬ ‫‪String) As DataTable‬‬


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

‫‪Public Function Insert() As String‬‬

‫‪Public Function Delete() As String‬‬

‫‪Public Function Update() As String‬‬

‫ال بد من مالحظة أن جميع هذه العمليات‬ ‫• تستعمل ‪ Try/Catch‬للقيام بمهامها تحسبًا ألي خطأ قد يحصل خالل تنفيذ العملية وتشغيل‬ ‫التطبيق‪.‬‬ ‫صا يحتوي على شرح عن الخطأ‪.‬‬ ‫• تعيد نصًا فارغا للداللة على النجاح أو ن ً‬ ‫• معظم العمليات‪ ،‬تتوقع تزويد الكائن‪ ،‬عند انشائه بمساعدة العمليات البنائية ال ُمختلفة‪ ،‬بقيم‬ ‫لبعض الخصائص حتى تتمكن من القيام بمهامها‪.‬‬ ‫‪Public Class ClassContacts‬‬ ‫‪Private m_ContactID, m_MyName, m_MobileNr As String‬‬ ‫نوفر لكل حقل خاصيّة‬ ‫‪Private m_PhoneNr, m_MyAddress, m_DateOfBirth As String‬‬ ‫)(‪Public Sub New‬‬ ‫‪'The Default Constructor‬‬ ‫‪End Sub‬‬ ‫)‪Public Sub New(ContactID As String‬‬ ‫توفر الفئة مجموعة من‬ ‫‪Me.m_ContactID = ContactID‬‬ ‫العمليات البنائية بحسب‬ ‫"" = ‪Me.m_MyName‬‬ ‫الحاجة كما سيتبين ذلك‬ ‫"" = ‪Me.m_MobileNr‬‬ ‫في االستعماالت التي‬ ‫"" = ‪Me.m_PhoneNr‬‬ ‫في العمليات‬ ‫"" = ‪Me.m_MyAddress‬‬ ‫"" = ‪Me.m_DateOfBirth‬‬ ‫‪End Sub‬‬ ‫)‪Public Sub New(MobileNr As String, PhoneNr As String‬‬ ‫"" = ‪Me.m_MyName‬‬ ‫‪Me.m_MobileNr = MobileNr‬‬ ‫‪Me.m_PhoneNr = PhoneNr‬‬ ‫"" = ‪Me.m_MyAddress‬‬ ‫"" = ‪Me.m_DateOfBirth‬‬ ‫‪End Sub‬‬

‫‪185‬‬


Public Sub New(MyName As String, MobileNr As String, PhoneNr As String, MyAddress As String, DateOfBirth As String) Me.m_MyName = MyName Me.m_MobileNr = MobileNr Me.m_PhoneNr = PhoneNr Me.m_MyAddress = MyAddress Me.m_DateOfBirth = DateOfBirth End Sub Public Property ContactID() As String Get Return m_ContactID End Get Set(ByVal value As String) m_ContactID = value End Set End Property

‫نوفر لكل حقل أو صفة‬ Private ‫محميّة‬ Property ‫خاصيّة أي‬ Public ‫محميّة‬

Public Property MyName() As String Get Return m_MyName End Get Set(ByVal value As String) m_MyName = value End Set End Property Public Property MobileNr() As String Get Return m_MobileNr End Get Set(ByVal value As String) m_MobileNr = value End Set End Property Public Property PhoneNr() As String Get Return m_PhoneNr End Get Set(ByVal value As String) m_PhoneNr = value End Set End Property

186


Public Property MyAddress() As String Get Return m_MyAddress End Get Set(ByVal value As String) m_MyAddress = value End Set End Property Public Property DateOfBirth() As String Get Return m_DateOfBirth End Get Set(ByVal value As String) m_DateOfBirth = value End Set End Property Public Function Exists() As String ‫تفحص هذه العملية ما إذا كان الشخص‬ Dim strRet As String .‫موجودًا في الدفتر بنا ًء على أرقام الهواتف‬ strRet = "" .‫صا فارغا‬ ً ‫إذا لم يكن موجودًا تعيد العملية ن‬ Try ‫خالف ذلك تعيد شرحا ً اما عن الخطأ إذا‬ Dim strSQL As String .‫حصل خطأ أو شر ًحا بأنه موجود‬ Dim Db As New Dbase Dim dt As New DataTable strSQL = "SELECT * FROM Contacts WHERE MobileNr='{0}' OR PhoneNr='{1}'" ‫تفترض هذه العملية أن ال ُمبرمج زودها‬ strSQL = String.Format(strSQL, m_MobileNr, m_PhoneNr) MobileNr, ‫بقيم للخصائص‬ dt = Db.SelectFromTable(strSQL) ‫يتم‬ ‫التي‬ ‫الهواتف‬ ‫ أي ألرقام‬PhoneNr If dt.Rows.Count = 1 Then ‫ تزويد القيم يتم عند انشاء‬.‫البحث عنها‬ strRet = "A Contact with this number already exists" .‫كائن من الفئة الستدعاء العمليّة‬ End If Catch ex As Exception strRet = "Error in ClassContacts.Exists(): " + ex.Message End Try Return strRet End Function

187


‫تعيد هذه العملية تفاصيل الشخص بحسب الـ‬ ‫ إذا‬.‫ ال ُمزودة من خالل الكائن‬ContactID ‫كان الشخص غير موجود في الدفتر تعيد‬ ‫ خالف ذلك تعيد شر ًحا‬.‫صا فارغا‬ ً ‫العملية ن‬ ‫اما عن الخطأ إذا حصل خطأ أو شرحً ا بأنه‬ .‫غير موجود‬

Public Function GetByContactID() As String Dim strRet As String strRet = "" Try Dim strSQL As String Dim Db As New Dbase Dim dt As New DataTable strSQL = "SELECT * FROM Contacts WHERE ContactID={0}" strSQL = String.Format(strSQL, m_ContactID) dt = Db.SelectFromTable(strSQL) ‫الحظ أن العملية تقوم بتعبئة جميع‬ If dt.Rows.Count = 1 Then ‫خصائص الكائن الحالي بالقيم التي تم‬ Dim dr As DataRow ‫ نقوم‬.‫الحصول عليها من قاغدة البيانات‬ ‫ سطرا سطرا‬dt ‫هنا بتمشيط الكائن‬ dr = dt.Rows(0) ‫ واألستعانة بكائن‬for ‫بواسطة حلقة‬ m_ContactID = dr("ContactID").ToString() ‫ لحفظ السطر الحالي في‬DataRow m_MyName = dr("MyName").ToString() ‫كل دورة لتسهيل عملية الوصول الى قيم‬ m_MyAddress = dr("MyAddress").ToString() ‫ الحظ أننا نصل الى قيم كل‬.‫الحقول‬ m_PhoneNr = dr("PhoneNr").ToString() ‫ ليس عن طريق‬dr ‫حقل أو خلية في‬ m_DateOfBirth = dr("DateOfBirth").ToString() ‫االندكس وانا عن طريق اسم الحقل كما‬ m_MobileNr = dr("MobileNr").ToString() ‫ هذه الطريقة‬.‫يظهر في جدول النتيجة‬ strRet = "" ‫أفضل من استعمال االندكس ألنها تجعل‬ End If .‫الكود أسهل للفهم‬ Catch ex As Exception strRet = "Error in ClassContacts.GetByContactID(): " + ex.Message End Try Return strRet End Function

188


Public Function GetByName(ByRef strRet As String) As ClassContacts() strRet = "" Dim A() As ClassContacts ‫تعيد هذه العملية مصفوفة األشخاص الذين يُشبه‬ ‫ ال ُمزود من‬MyName ‫اسمهم النص الموجود في‬ Try ‫ عملية المقارنة تتم من خالل‬.‫خالل الكائن‬ Dim strSQL As String . SQL ‫ الذي تُوفره لغة‬LIKE ‫استعمال المعامل‬ Dim Db As New Dbase Dim dt As New DataTable strSQL = "SELECT * FROM Contacts WHERE MyName LIKE '%{0}%'" strSQL = String.Format(strSQL, m_MyName) ‫ قلنا عندما شرحنا المعامل‬:‫تنبيه‬ dt = Db.SelectFromTable(strSQL) ‫ بأننا نستعمل الرمز * للداللة‬LIKE A = New ClassContacts(dt.Rows.Count - 1) {} ‫على سلسلة نصوص بطول أكبر أو‬ Dim i As Integer ‫ عند تنفيذ هذا األمر‬.0 ‫يساوي‬ For i = 0 To dt.Rows.Count - 1 ‫أن‬ ‫ يجب‬ADO.NET ‫بمساعدة‬ Dim dr As DataRow ‫ بدال من * واال‬% ‫نستعمل الرمز‬ Dim obj As New ClassContacts() .‫فاألمر ال يعمل‬ dr = dt.Rows(i) obj.ContactID = dr("ContactID").ToString() obj.MyName = dr("MyName").ToString() ‫الحظ أن العملية تقوم بتعبئة جميع‬ obj.MyAddress = dr("MyAddress").ToString() ‫خصائص الكائن الحالي بالقيم التي تم‬ obj.PhoneNr = dr("PhoneNr").ToString() .‫الحصول عليها من قاغدة البيانات‬ obj.DateOfBirth = dr("DateOfBirth").ToString() obj.MobileNr = dr("MobileNr").ToString() A(i) = obj Next Return A Catch ex As Exception strRet = "Error in ClassContacts.GetByName(): " + ex.Message End Try Return Nothing End Function

189


Public Function GetAllAsArray(ByRef strRet As String) As ClassContacts() strRet = "" Dim A() As ClassContacts ‫تعيد هذه العملية مصفوفة أشخاص فيها تفاصيل‬ ُ‫جميع األشخاص الموجودين في الدفتر الذي ت‬ ‫وفره‬ Try .SQL ‫لغة‬ Dim strSQL As String Dim Db As New Dbase Dim dt As New DataTable strSQL = "SELECT * FROM Contacts ORDER BY [MyName] ASC" dt = Db.SelectFromTable(strSQL) A = New ClassContacts(dt.Rows.Count - 1) {} Dim i As Integer For i = 0 To dt.Rows.Count - 1 Dim dr As DataRow ‫الحظ أن العملية تقوم بتعبئة‬ Dim obj As New ClassContacts() ‫المصفوفة سطرا سطرا بالمعلومات‬ dr = dt.Rows(i) .‫المأخوذة من القاعدة‬ obj.ContactID = dr("ContactID").ToString() obj.MyName = dr("MyName").ToString() obj.MyAddress = dr("MyAddress").ToString() obj.PhoneNr = dr("PhoneNr").ToString() obj.DateOfBirth = dr("DateOfBirth").ToString() obj.MobileNr = dr("MobileNr").ToString() A(i) = obj Next Return A Catch ex As Exception strRet = "Error in ClassContacts.GetByName(): " + ex.Message End Try Return Nothing End Function Public Function GetAll(ByRef strRet As String) As DataTable strRet = "" Try DataTable ‫تعيد هذه العملية كائن‬ Dim strSQL As String ‫فيه تفاصيل جميع األشخاص‬ Dim Db As New Dbase .‫الموجودين في الدفتر‬ Dim dt As New DataTable strSQL = "SELECT * FROM Contacts ORDER BY [MyName] ASC" dt = Db.SelectFromTable(strSQL) Return dt Catch ex As Exception strRet = "Error in ClassContacts.GetAll(): " + ex.Message End Try Return Nothing End Function

190


Public Function Insert() As String ‫تضيف هذه العملية تفاصيل شخص جديد الى‬ Dim strRet As String ‫ خالف ذلك‬.‫القاعدة وتعيد نصا فارغا إذا نجحت‬ strRet = "" .‫تعيد شر ًحا عن الخطأ كنص‬ Try Dim strSQL As String Dim Db As New Dbase Dim nAffectedRows As Integer strSQL = "INSERT INTO Contacts ([MobileNr], [MyName], [PhoneNr], [MyAddress], [DateOfBirth])" strSQL += " VALUES ('{0}','{1}','{2}','{3}','{4}')" strSQL = String.Format(strSQL, m_MobileNr, m_MyName, m_PhoneNr, m_MyAddress, m_DateOfBirth) nAffectedRows = Db.ChangeTable(strSQL) If nAffectedRows = 0 Then strRet = "Failed to save Contact!" End If Catch ex As Exception strRet = "Error in ClassContacts.Insert(): " + ex.Message End Try Return strRet End Function Public Function Delete() As String ‫تحذف هذه العملية تفاصيل الشخص من القاعدة‬ Dim strRet As String ‫ التابعة له وتعيد نصا‬ContactID ‫بحسب الـ‬ strRet = "" ‫ خالف ذلك تعيد شر ًحا عن‬.‫فارغا إذا نجحت‬ Try .‫الخطأ كنص‬ Dim strSQL As String Dim Db As New Dbase Dim nAffectedRows As Integer strSQL = "DELETE FROM Contacts WHERE [ContactID]={0}" strSQL = String.Format(strSQL, m_ContactID) nAffectedRows = Db.ChangeTable(strSQL) If nAffectedRows = 0 Then strRet = "Failed to delete Contact!" End If Catch ex As Exception strRet = "Error in ClassContacts.Delete(): " + ex.Message End Try Return strRet End Function

191


Public Function Update() As String ‫تقوم هذه العملية بتحديث تفاصيل الشخص من‬ Dim strRet As String ‫ التابعة له وتعيد‬ContactID ‫القاعدة بحسب الـ‬ strRet = "" ‫ خالف ذلك تعيد شر ًحا عن‬.‫نصا فارغا إذا نجحت‬ Try ‫ الحظ أن الكائن يجب أن يكون‬.‫الخطأ كنص‬ Dim strSQL As String ً .‫مجهزا بجميع القيم الجديدة‬ Dim Db As New Dbase Dim nAffectedRows As Integer strSQL = "UPDATE [Contacts] SET [MobileNr]='{0}', [MyName]='{1}', [PhoneNr]='{2}', [MyAddress]='{3}', [DateOfBirth]='{4}'" strSQL += " WHERE [ContactID]={5}" strSQL = String.Format(strSQL, m_MobileNr, m_MyName, m_PhoneNr, m_MyAddress, m_DateOfBirth, m_ContactID) nAffectedRows = Db.ChangeTable(strSQL) If nAffectedRows = 0 Then strRet = "Failed to update Contact!" End If Catch ex As Exception strRet = "Error in ClassContacts.Update(): " + ex.Message End Try Return strRet End Function End Class

192


‫ولنعد اآلن الى برمجة النموذج ال ُمعد الضافة تفاصيل جديدة الى الجدول ‪ Contacts‬وبرمجة معالج‬ ‫الحدث ‪ Click‬للزر ‪ Save‬وظيفة هذا الزر حفظ تفاصيل الشخص الجديد بعد التأكد من صحة‬ ‫االدخال ومن أنه ال يوجد شخص بالدفتر له نفس رقم الهاتف أو نفس رقم الجوال‪.‬‬

‫‪Private Sub ButtonSave_Click(ByVal sender As System.Object,‬‬ ‫‪ByVal e As System.EventArgs) Handles ButtonSave.Click‬‬ ‫‪Try‬‬ ‫أوال نتأكد من صحة االدخال‬ ‫‪If Not ValidateData() Then‬‬ ‫‪Return‬‬ ‫بعدها ننشئ كائنًا من الفئة‬ ‫‪End If‬‬ ‫‪ClassContacts‬‬ ‫‪Dim obj As New ClassContacts(TextBoxName.Text, TextBoxMobileNr.Text,‬‬ ‫‪TextBoxPhoneNr.Text, TextBoxAddress.Text,‬‬ ‫)‪TextBoxDOB.Text‬‬ ‫‪Dim strRet As String‬‬ ‫نفحص ما إذا كان هنالك شخص بالجدول وله نفس أرقام‬ ‫)(‪strRet = obj.Exists‬‬ ‫التلفونات التي نُريد ادخالها‪ .‬حينها نُخبر ال ُمستخدم‬ ‫‪If strRet <> "" Then‬‬ ‫ونرجع‪.‬‬ ‫)‪MessageBox.Show(strRet‬‬ ‫‪Return‬‬ ‫‪End If‬‬ ‫نُدخل التفاصيل الى الجدول ونُخبر ال ُمستخدم بأي خطأ‬ ‫)(‪strRet = obj.Insert‬‬ ‫يحصل خالل عملية االدخال‬ ‫‪If strRet <> "" Then‬‬ ‫)‪MessageBox.Show(strRet‬‬ ‫‪Return‬‬ ‫‪End If‬‬ ‫نُخبر ال ُمستخدم بنجاح عملية االدخال‬ ‫)"‪MessageBox.Show("Saved Successfully‬‬ ‫‪Catch ex As Exception‬‬ ‫)‪MessageBox.Show(ex.Message‬‬ ‫‪End Try‬‬ ‫‪End Sub‬‬

‫الحظ أن العملية ال تستعمل ُمطلقًا أية أوامر ‪ SQL‬وانما تتعامل مع قاعدة البانات فقط من خالل طبقة‬ ‫الـ ‪ Application‬أي فقط من خالل عمليات الفئة ‪ ClassContacts‬وهي‬ ‫• العملية البنائيّة التي تُزود الكائن بجميع التفاصيل التي أدخلها ال ًمستخدم الى الصناديق‬ ‫• العملية ‪ Exists‬التي تفحص كما بيّنا سابقًا ما إذا كان هنالك شخص بالجدول وله نفس أرقام‬ ‫التلفونات التي نُريد ادخالها‪.‬‬ ‫• العملية ‪ Insert‬التي تُدخل التفاصيل الى الجدول‬

‫‪193‬‬


‫العمليات ال ُمساعدة ال ُمستعملة‬ Private Function ValidateData() As Boolean TextBoxName.Text = TextBoxName.Text.Trim() If TextBoxName.Text = "" Then MessageBox.Show("Name is Missing") TextBoxName.Focus() Return False End If

‫عملية للتأكد من صحة االدخال‬ ‫ لصندوق‬Focus ‫استدعاء العملية‬ ‫ هو‬TextBoxName ‫النص‬ ‫لوضع مؤشر الكتابة في هذا‬ ‫الصندوق كارشاد لل ُمستخدم ولفت‬ ‫انتباهه وتركيزه على هذه األداة‬ ‫التي تحتوي على محتوى خاطئ‬

TextBoxMobileNr.Text = TextBoxMobileNr.Text.Trim() If Not IsMobileNr(TextBoxMobileNr.Text) Then MessageBox.Show("Mobile Nr is Missing") TextBoxMobileNr.Focus() Return False End If TextBoxPhoneNr.Text = TextBoxPhoneNr.Text.Trim() If Not IsPhoneNr(TextBoxPhoneNr.Text) Then MessageBox.Show("Phone Nr is Missing") TextBoxPhoneNr.Focus() Return False End If TextBoxAddress.Text = TextBoxAddress.Text.Trim() If TextBoxAddress.Text = "" Then MessageBox.Show("Address is Missing") TextBoxAddress.Focus() Return False End If TextBoxDOB.Text = TextBoxDOB.Text.Trim If Not IsDate(TextBoxDOB.Text) Then MessageBox.Show("Date of birth is Missing") TextBoxDOB.Focus() Return False End If Return True End Function

194


Private Function IsMobileNr(ByVal MobileNr As String) As Boolean Dim i As Integer ‫ رقم جوال أي‬MobileNr ‫ إذا كان‬True ‫تعيد‬ If MobileNr.Length <> 10 Then ‫مزودي‬ ‫ أرقام ويبدأ بواحدة من أرقام‬10 ‫مكون من‬ Return False ‫الخدمات المعروفين‬ End If Dim Provider As String = MobileNr.Substring(0, 3) Dim Providers() As String = {"050", "052", "053", "054", "057", "058"} If Not Exists(Providers, Provider) Then Return False End If For i = 3 To MobileNr.Length - 1 If MobileNr(i) < "0" Or MobileNr(i) > "9" Then Return False End If Next Return True End Function Private Function IsPhoneNr(ByVal PhoneNr As String) As Boolean Dim i As Integer ‫ رقم تلفون أي مكون‬PhoneNr ‫ إذا كان‬True ‫تعيد‬ If PhoneNr.Length <> 9 Then ‫ أرقام ويبدأ بواحدة من أرقام المناطق المعروفة‬9 ‫من‬ Return False End If Dim Area As String = PhoneNr.Substring(0, 2) Dim Areas() As String = {"02", "03", "04", "08", "09"} If Not Exists(Areas, Area) Then Return False End If For i = 2 To PhoneNr.Length - 1 If PhoneNr(i) < "0" Or PhoneNr(i) > "9" Then Return False End If Next Return True End Function Public Function Exists(A() As String, x As String) As Boolean Dim i As Integer A ‫ موجودًا في المصفوفة‬x ‫ إذا كان‬True ‫تعيد‬ For i = 0 To A.Length - 1 If x = A(i) Then Return True End If Next Return False End Function

195


‫تعيد ‪ True‬إذا كان ‪ Pre‬مقدمة ُمزود خدمة معروف‬ ‫‪End Function‬‬ ‫‪Public Function IsProvider(Pre As String) As Boolean‬‬ ‫‪Dim i As Integer‬‬ ‫}"‪Dim Providers() As String = {"050", "052", "053", "054", "057", "058‬‬ ‫‪For i = 0 To Providers.Length - 1‬‬ ‫‪If Pre = Providers(i) Then‬‬ ‫‪Return True‬‬ ‫‪End If‬‬ ‫‪Next‬‬ ‫‪Return False‬‬ ‫‪End Function‬‬

‫األمر ‪FileContactsDelete‬‬ ‫نقترح لبرمجة عنصر القائمة ‪ Delete‬النموذج التالي‬

‫• عند ظهور النموذج تكون القائمة ال ُمنسدلة معبأةً بأسماء جميع األشخاص الموجودين في‬ ‫الجدول ‪Users‬‬ ‫• لحذف تفاصيل شخص ما‪ ،‬يقوم ال ُمستخدم باختيار اسم الشخص من القائمة‪ ،‬ثم يضغط على‬ ‫الزر ‪Delete‬‬ ‫• معالج الحدث ‪ Click‬للزر ‪ Delete‬يتأكد من خالل سؤال ال ُمستخدم ان كان حقُا يريد حذف‬ ‫تفاصيل الشخص ال ُمختار‬ ‫• بعد التأكد يقوم معالج الحدث بحذف التفاصيل من الجدول وتحديث محتوى القائمة أي يقوم‬ ‫بحذف اسم الشخص منها‬

‫‪196‬‬


‫تعبئة القائمة ال ُمنسدلة‬ ‫هنالك أكثر من امكانية لتعبئة القائمة ال ُمنسدلة بأسماء جميع األشخاص الموجودين في الجدول‬ ‫‪ .Users‬الطريقة األولى تكمن في تمشيط جدول النتيجة سطرًا سطرًا ثم ادخال كل سطر بالطريقة‬ ‫التي تعرفنا عليها سابقًا‪ .‬الطريقة التي تهمنا هنا هي الطريقة التي تستعمل مبدأ ما يُسمى "بوصل‬ ‫األدوات بمصادر المعلومات" أو ‪ .DataBinding‬تعتبر ‪ DataBinding‬منهج أساسي من‬ ‫مناهج ميكروسفت المتعلقة بكيفيات عرض المعلومات والتعامل معها وهو ما يسمى بـ ‪Windows‬‬ ‫)‪ DataBinding .Presentation Foundation (WPF‬عبارة عن عملية وصل األداة (التي‬ ‫تمثل واجهة المستخدم الصُورية أي ‪ )Graphical User Interface‬بالكائنات التي تحتوي على‬ ‫المعلومات التي غالبا ما تُؤخذ من قاعدة البيانات‪ .‬هذا الوصل أو الربط يكون من خالل ما يلي‪:‬‬ ‫• اعطاء الكائن الذي يحتوي على المعلومات كقيمة للخاصية ‪( DataSource‬أي مصدر‬ ‫المعلومات) التابعة لألداة التي تدعم هذا المنهج‪.‬‬

‫البرمجة‬ ‫التعبئة تتم في معالج الحدث ‪ Load‬التابع للنموذج بحيث تظهر القائمة وقد ُملِئت‬ ‫بأسماء جميع األشخاص الموجودين في الجدول ‪Users‬‬ ‫‪Private Sub FormDeleteContact_Load(ByVal sender As System.Object,‬‬ ‫)‪ByVal e As System.EventArgs‬‬ ‫‪Handles MyBase.Load‬‬ ‫)(‪FillComboBox‬‬ ‫‪End Sub‬‬ ‫)(‪Private Sub FillComboBox‬‬ ‫‪Try‬‬ ‫)(‪Dim obj As New ClassContacts‬‬ ‫هنا يتم انشاء كائن من الفئة ‪ ClassContacts‬ثم استدعاء‬ ‫"" = ‪Dim strRet As String‬‬ ‫العملية ‪ GetAll‬بواسطة هذا الكائن والحصول على جدول‬ ‫‪Dim dt As DataTable‬‬ ‫النتيجة داخل الكائن ‪.dt‬‬ ‫)‪dt = obj.GetAll(strRet‬‬ ‫‪If strRet <> "" Then‬‬ ‫)‪MessageBox.Show(strRet‬‬ ‫توفر األداة ‪ ComboBox‬الخاصيتين‬ ‫‪Return‬‬ ‫‪ DisplayMember‬و‪ .ValueMember‬تتلقى‬ ‫‪End If‬‬ ‫الخاصية ‪ DisplayMember‬اسم الحقل الذي على‬ ‫"‪ComboBoxNames.DisplayMember = "MyName‬‬ ‫األداة أن تعرض قيمه‪ .‬أما الخاصية ‪ValueMember‬‬ ‫"‪ComboBoxNames.ValueMember = "ContactID‬‬ ‫فانها تتلقى كقيمة اسم الحقل الذي يشكل مفتا ًحا رئيسيا في‬ ‫‪ComboBoxNames.DataSource = dt‬‬ ‫الجدول‪ .‬الهدف من ذلك أن ال ُمستخدم يُفضل التعامل مع‬ ‫‪Catch ex As Exception‬‬ ‫األسماء التي يعرفها وليس مع قيم ُمجردة كقيم المفاتيح‬ ‫)‪MessageBox.Show("Error: " + ex.Message‬‬ ‫خاصً ة إذا كانت قيما لحقل من نوع رقم تلقائي فانها ال‬ ‫‪End Try‬‬ ‫معنى لها بالنسبة لل ُمستخدم‪ .‬هنا نريد اظهار قيم الحقل‬ ‫اعطاء الكائن ‪ dt‬للخاصية ‪DataSource‬‬ ‫‪End Sub‬‬ ‫‪ MyName‬واخفاء قيم المفتاح ‪.ContactID‬‬ ‫(أي مصدر المعلومات) التابعة لألداة‬ ‫‪ComboBoxNames‬‬ ‫‪197‬‬


Delete ‫ التابع للزر‬Click ‫برمجة معالج الحدث‬ Private Sub ButtonDelete_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonDelete.Click Try If ComboBoxNames.Items.Count = 0 Then ‫نرجع إذا كانت أو أصبحت القائمة ال ُمنسدلة‬ Return .‫فارغة‬ End If Dim Answer As DialogResult Answer = MessageBox.Show("Are You Sure?", "Confirm Delete", MessageBoxButtons.YesNo, MessageBoxIcon.Question) If Answer = Windows.Forms.DialogResult.No Then Return End If Dim obj As New ClassContacts(ComboBoxNames.SelectedValue.ToString) Dim strRet As String ClassContacts ‫هنا يتم انشاء كائن من الفئة‬ strRet = obj.Delete() ‫واعطاؤه قيمة المفتاح أي قيمة الـ‬ If strRet <> "" Then ‫يتم‬ ‫الحذف‬ ‫ألن‬ ‫ختار‬ ‫ للنص ال ُم‬ValueMember MessageBox.Show(strRet) . Delete ‫ ثم نستدعي العملية‬.‫بواسطته‬ Return End If MessageBox.Show("Deleted Successfully.") FillComboBox() ‫نقوم بتعبئة القائمة من جديد من أجل أن يتم‬ Catch ex As Exception .‫حذف االسم الذي حُذف من القاعدة‬ MessageBox.Show(ex.Message) End Try End Sub

198


‫األمر ‪FileContactsUpdate‬‬ ‫نقترح لبرمجة عنصر القائمة ‪ Update‬النموذج التالي‬

‫• عند ظهور النموذج تكون القائمة ال ُمنسدلة معبأةً بأسماء جميع األشخاص الموجودين في‬ ‫الجدول ‪Users‬‬ ‫• لتحديث تفاصيل شخص ما‪ ،‬يقوم ال ُمستخدم باختيار اسم الشخص من القائمة‪ .‬حينها يقوم‬ ‫النموذج بتعبئة صناديق النص المتوفرة في النموذج بتفاصيل الشخص ال ُمتار في القائمة‪.‬‬ ‫• معالج الحدث ‪ Click‬للزر ‪ Update‬يتأكد من خالل سؤال ال ُمستخدم ان كان حقُا يريد‬ ‫تحديث تفاصيل الشخص ال ُمختار‬ ‫• بعد التأكد يقوم معالج الحدث بتحديث التفاصيل في الجدول وتحديث محتوى القائمة‬ ‫• تعبئة القائمة ال ُمنسدلة بأسماء جميع األشخاص الموجودين في الجدول ‪ Users‬تتم بنفس‬ ‫الطريقة التي شرحناها عند األمر ‪ Delete‬وال حاجة العادة الشرح مرة أخرى‪.‬‬

‫‪199‬‬


Private Sub ComboBoxNames_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ComboBoxNames.SelectedIndexChanged FindContactByID(ComboBoxNames.SelectedValue) End Sub Private Sub FindContactByID(ByVal ContactID) Try Dim obj As New ClassContacts(ContactID) Dim strRet As String strRet = obj.GetByContactID() If strRet <> "" Then MessageBox.Show(strRet) Return End If TextBoxName.Text = obj.MyName TextBoxAddress.Text = obj.MyAddress TextBoxPhoneNr.Text = obj.PhoneNr TextBoxDOB.Text = obj.DateOfBirth TextBoxMobileNr.Text = obj.MobileNr OldMobileNr = obj.MobileNr OldPhoneNr = obj.PhoneNr Catch ex As Exception MessageBox.Show("Error: " + ex.Message) End Try End Sub

200

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


Save ‫ التابع للزر‬Click ‫برمجة معالج الحدث‬ Private Sub ButtonSave_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonSave.Click Try If Not ValidateData() Then Return End If Dim db As New Dbase Dim obj As New ClassContacts(TextBoxName.Text, TextBoxMobileNr.Text, TextBoxPhoneNr.Text, TextBoxAddress.Text, TextBoxDOB.Text) Dim strRet As String If OldMobileNr <> TextBoxMobileNr.Text Or OldPhoneNr <> TextBoxPhoneNr.Text Then strRet = obj.Exists() If strRet <> "" Then MessageBox.Show(strRet) TextBoxMobileNr.Focus() Return End If End If obj.ContactID = ComboBoxNames.SelectedValue.ToString strRet = obj.Update() If strRet <> "" Then MessageBox.Show(strRet) Return End If MessageBox.Show("Updated Successfully") Me.Close() Catch ex As Exception MessageBox.Show(ex.Message) End Try End Sub

201


‫األمر ‪FileContactsNavigate‬‬ ‫نقترح لبرمجة عنصر القائمة ‪ Navigate‬النموذج التالي‬

‫الهدف من هذا النموذج هو التنقل بين سجالت دفتر التلفون‪.‬‬ ‫• عند ظهور النموذج نقرأ تفاصيل جميع األشخاص الموجودين في الجدول ‪ Users‬ونحظ جدول‬ ‫النتيجة في مصفوفة أشخاص وعلى مستوى النموذج حتى تكون متوفرة لمعالجات الحدث‬ ‫‪ Click‬للزرين ‪ Next‬و‪Previous‬‬ ‫• الضغط على الزر ‪ Next‬يُظهر تفاصيل الشخص التالي (ان ُوجد) كما هو في جدول النتيجة أو‬ ‫في مصفوفة األشخاص‬ ‫• الضغط على الزر ‪ Previous‬يُظهر تفاصيل الشخص السابق (ان ُوجد) كما هو في جدول‬ ‫النتيجة أو في مصفوفة األشخاص‬

‫‪202‬‬


‫البرمجة‬ Public Class FormNavigateThruContacts Private MyContactsArray() As ClassContacts Private CurrentRowIndex As Integer

‫هنا نُعرفُ على مستوى الفئة مصفوفة‬ MyContactsArray ‫األشخاص‬ CurrentRowIndex ‫واالندكس الحالي‬ .‫للشخص الذي يتم عرض تفاصيله‬

Private Sub FormNavigateThruContacts_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Try ‫نقوم خالل تحميل الصفحة بتعبئة‬ Dim obj As New ClassContacts() ‫ من‬MyContactsArray ‫المصفوفة‬ Dim strRet As String = "" ‫قاعدة البيانات بواسطة العملية‬ MyContactsArray = obj.GetAllAsArray(strRet) ‫ ثم نعرض بواسطة‬GetAllAsArray If MyContactsArray.Length >= 1 Then GetDataByRowIndex ‫العملية‬ GetDataByRowIndex(0) ‫تفاصيل الشخص األول في المصفوفة ان‬ Else ‫ خالف ذلك نُبلغ ال ُمستخدم بأنه ال‬.‫ُوجد‬ MessageBox.Show("No contacts available") .‫يوجد أشخاص في القاعدة‬ End If Catch ex As Exception MessageBox.Show(ex.Message) End Try End Sub Private Sub GetDataByRowIndex(ByVal RowIndex As Integer) Dim obj As New ClassContacts() obj = MyContactsArray(RowIndex) ‫تعرض هذه العملية تفاصيل الشخص الذي‬ CurrentRowIndex = RowIndex .RowIndex ‫رقمه في مصفوفة األشخاص‬ TextBoxName.Text = obj.MyName ‫أي تنقل القيم وتعرضها بواسطة الصناديق‬ TextBoxAddress.Text = obj.MyAddress ‫ضا االندكس‬ ً ‫ العملية تحتلن أي‬.‫ال ُمعدة لذلك‬ TextBoxPhoneNr.Text = obj.PhoneNr .‫الحالي‬ TextBoxDOB.Text = obj.DateOfBirth TextBoxMobileNr.Text = obj.MobileNr End Sub Private Sub ButtonNext_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonNext.Click ‫هنا يتم عرض تفاصيل الشخص التالي في‬ CurrentRowIndex = CurrentRowIndex + 1 ‫العملية‬ ‫ خالف ذلك تُبلغ‬.‫المصفوفة ان ُو ِجد‬ If CurrentRowIndex < MyContactsArray.Length Then ‫ال ُمستخدم بأن التفاصيل المعروضة حاليا هي‬ GetDataByRowIndex(CurrentRowIndex) .‫للشخص األخير في المصفوفة‬ Else CurrentRowIndex = CurrentRowIndex - 1 MessageBox.Show("End Reached: No more Contacts!") End If End Sub

203


Private Sub ButtonPrevious_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonPrevious.Click ‫هنا يتم عرض تفاصيل الشخص السابق في‬ CurrentRowIndex = CurrentRowIndex - 1 ‫ خالف ذلك تُبلغ العملية‬.‫المصفوفة ان ُو ِجد‬ If CurrentRowIndex >= 0 Then ‫هي‬ ‫ال ُمستخدم بأن التفاصيل المعروضة حاليا‬ GetDataByRowIndex(CurrentRowIndex) .‫للشخص األول في المصفوفة‬ Else CurrentRowIndex = CurrentRowIndex + 1 MessageBox.Show("Begin Reached: No more Contacts!") End If End Sub End Class

204


‫األمر ‪FileContactsSearch‬‬ ‫نقترح لبرمجة عنصر القائمة ‪ Search‬النموذج التالي‬

‫• للبحث عن تفاصيل شخص ما‪ ،‬على ال ُمستخدم أن يُدخل اسم الشخص أو جز ًء من االسم‬ ‫• البحث يتم بواسطة المعامل ‪ LIKE‬الذي تُوفره لغة ‪.SQL‬‬ ‫• بعد الضغط على الزر ‪ Find‬تُعرض نتيجة البحث بواسطة األداة ‪ ListView‬الظاهرة في‬ ‫وسط النموذج تحت العنوان ‪ .Search Result‬الحظ أن النتيجة قد تكون عبارة عن أكثر‬ ‫من سجل ألن ‪ LIKE‬قد يجد أكثر من سجل يحقق الشبه المطلوب‪.‬‬ ‫• يبقى الزر ‪ Find‬غير قابل لالختيار طالما أن الصندوق ‪ Name‬يكون فار ًغا‪ .‬أي أننا نتحكم‬ ‫بالزر ‪ Find‬في معالج الحدث ‪ TextChanged‬التابع لألداة ‪.TextBoxName‬‬

‫‪205‬‬


Find ‫ التابع للزر‬Click ‫برمجة معالج الحدث‬ Private Sub ButtonFind_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonFind.Click FindContact() End Sub GetByName ‫كما ُذ ِكر سابقًا فان العملية‬ ‫تبحث عن التفاصيل بحسب االسم ال ُمعطى‬ Private Sub FindContact() ‫للكائن أي بحسب االسم الذي أدخله ال ُمستخدم‬ Try ‫ البحث يتم‬.Name ‫الى صندوق التص‬ Dim strRet As String = "" ُ ‫ الحظ أن العملية تعيد‬.LIKE ‫بمساعدة األمر‬ Dim obj As New ClassContacts() ‫النتيجة في مصفوفة أشخاص أي من نوع‬ obj.MyName = TextBoxName.Text .ClassContacts Dim A() As ClassContacts A = obj.GetByName(strRet) If A Is Nothing Then MessageBox.Show(strRet) Return End If Dim Row(4) As String Dim i As Integer For i = 0 To A.Length - 1 obj = A(i) Row(0) = obj.MyName Row(1) = obj.MobileNr Row(2) = obj.PhoneNr Row(3) = obj.MyAddress Row(4) = obj.DateOfBirth

‫هنا نمشط مصفوفة األشخاص وننقل قيم كل‬ .Row ‫كائن منها الى مصفوفة نصوص باسم‬

Dim itm As ListViewItem itm = New ListViewItem(Row) ListViewSearchResult.Items.Add(itm)

‫ كسطر جديد‬Row ‫وأخي ًرا نضيف المصفوفة‬ ListViewSearchResult ‫في الـ‬

Next Catch ex As Exception MessageBox.Show("Error: " + ex.Message) End Try End Sub

FileContactsShow All ‫األمر‬ ‫ التي تُمكنُنا من عرض البيانات على شكل‬DataGridView ‫لبرمجة هذا األمر سوف نستعمل األداة‬ .‫فر ُد لهذه األداة فصًال خاصًا‬ ِ ُ‫ ولذلك سن‬.‫جدول مع امكانيات كاملة للتحرير‬

206


‫األداة ‪DataGridView‬‬ ‫تعتبر األداة ‪ DataGridView‬من أهم األدوات لعرض المعلومات على شكل جدول‪ .‬واألهم من‬ ‫ذلك أن هذه األداة تمكننا من تحرير المعلومات الموجودة في الجدول أي تمكننا من‬ ‫• حذف هذه المعلومات‬ ‫• اضافة سطر جديد الى الجدول‬ ‫• تحديث معلومات سطر من أسطر الجدول‬ ‫• ترتيب الجدول حسب عامود معين تصاعديا أو تنازليا‬ ‫بل وتمكننا من اضافة أدوات أخرى داخل خاليا الجدول وحسب الحاجة‪ .‬اضافة الى ذلك فان هذه‬ ‫األداة تدعم ما يسمى بربط األدوات بمصادر المعلومات (أي ‪.)DataBinding‬‬ ‫وكمثال على كل ذلك سوف نقوم هنا ببرمجة األمر األمر ‪.FileContactsShow All‬‬ ‫التصميم ال ُمقترح‬

‫‪207‬‬


‫• تعبئة النموذج بتفاصيل األشخاص الموجودة في الجدول ‪ Contacts‬تتم في معالج الحدث‬ ‫‪ Load‬التابع لهذا النموذج وبمساعدة طريقة الـ ‪DataBinding‬‬ ‫• لحذف سجالت‪ ،‬نقوم باختيارها ثم الضغط على الزر ‪Delete‬‬ ‫• ولحفظ أية تغييرات قمنا بها نقوم باختيارها ثم الضغط على الزر ‪Save‬‬ ‫الجدول قابل للتحرير بشكل كامل‪ .‬أي أنه بامكاننا‬ ‫• تغيير معطيات السجالت الموجودة بالضبط كما نفعل في مستند اكسل‬ ‫• وأيضا يمكننا اختيا ُر أسطر وطلبُ حذفِها من دفتر التلفونات‬ ‫• وأخيرا بامكاننا اضافة سجل جديد من خالل تعبئة تفاصيله في السطر األخير الذي توفره‬ ‫األداة دائما‪ .‬فكلما أدخلنا سجال جديدا وفرت األداة سطرا جديدا فارغا الستيعاب معطيات‬ ‫سجل جديد وهكذا‪.‬‬ ‫إذا هي أداة ذات قدرات كبيرة للتحرير‪ .‬للحصول على هذه العمليات كلها وتمكين األداة من توفيرها‬ ‫يجب أ نختار الـ ‪ CheckBoxes‬التي تظهر في الـ ‪ Design‬وبعد الضغط على السهم الصغير الذي‬ ‫يظهر في الزاوية اليمنى العليا من األداة كما تُبيّن ذلك الصورة التالية‬

‫‪ Enable Adding‬لتوفير السطر الفارغ في نهاية األسطر لتمكين ال ُمستخدم من اضافة سجل جديد‬ ‫‪ Enable Editing‬لتمكين ال ُمستخدم من تحرير محتوى الخاليا‬ ‫‪ Enable Deleting‬لتمكين ال ُمستخدم من حذف أسطر يختارها‬ ‫‪ Enable Column Rendering‬لدعم العمليات ‪ Update‬و ‪ Delete‬بمساعدة ‪.DataSource‬‬ ‫لسنا بحاجة لهذه االمكانية في هذا المثال‪.‬‬

‫‪208‬‬


‫ التابع للنموذج‬Load ‫برمجة معالج الحدث‬ ‫ بمساعدة طريقة‬Contacts ‫هنا تتم عملية تعبئة النموذج بتفاصيل األشخاص الموجودة في الجدول‬ DataBinding ‫الـ‬ Private Sub FormShowAll_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load FillGrid() End Sub Private Sub FillGrid() Dim strRet As String = "" Dim obj As New ClassContacts Dim dt As New DataTable dt = obj.GetAll(strRet) If dt Is Nothing Then MessageBox.Show(strRet) Return End If

‫ تفاصيل جميع‬GetAll ‫تعيد العملية‬ ‫ في‬Contacts ‫األشخاص من الجدول‬ .DataTable ‫كائن من نوع‬

‫ من خالل اعطاء‬Databinding ‫هنا تتم عملية الـ‬ DataGridView ‫ التابعة للـ‬DataSource ‫الخاصيّة‬ dt ‫الكائن‬

'Data Binding DataGridViewContacts.DataSource = dt DataGridViewContacts.Columns("ContactID").Visible = False LabelNumOfRecords.Text += dt.Rows.Count.ToString End Sub

209

‫بعد ذلك نقوم باخفاء العامود‬ ‫ ثم نعرض عدد السجالت‬ContactID ‫بواسطة األداة‬ LabelNumOfRecords


Save ‫ التابع للزر‬Click ‫برمجة معالج الحدث‬ Private Sub ButtonSave_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonSave.Click Try Dim row As Integer Dim strRet As String Dim obj As New ClassContacts() 'For each row For row = 0 To DataGridViewContacts.Rows.Count - 2

.‫نمر على كل سطر من أسطر األداة‬ ‫الحظ أننا ال نمر على السطر األخير‬ .‫ألنه سطر فارغ‬

' ValidateData will fill the object if the validation passed obj = ValidateData(row) ‫ بفحص‬ValidateData ‫تقوم العملية‬ ‫ال ُمعطيات وتعيد كائنًا من نوع‬ If obj Is Nothing Then ‫ محفوظة فيه‬ClassContacts Return .‫جميع القيم إذا نجحت عملية الفحص‬ End If .Nothing ‫خالف ذلك يُعاد‬ If obj.ContactID = Nothing Or obj.ContactID = "" Then 'Insert a new contact ‫كيف نعرف هل السطر الحالي‬ strRet = obj.Insert() ‫جديد أم موجود في القاعدة وتم‬ Else ‫تعديله؟ قيمة المفتاح الرئيسي لكل‬ 'Update existing contact Nothing ‫سطر جديد تكون‬ strRet = obj.Update() ‫ولذلك نضيفه بواسطة العملية‬ End If ‫ خالف ذلك نقوم بتحديثه‬.Insert .Update ‫بواسطة العملية‬ If strRet <> "" Then MessageBox.Show(strRet) DataGridViewContacts.Rows(row).Selected = True Return End If Next MessageBox.Show("Succesfully Saved") FillGrid()

.‫بعد التخزين الناجح لل ُمعطيات نعبئ األداة من جديد‬

Catch ex As Exception MessageBox.Show(ex.Message) End Try End Sub

210


Private Function ValidateData(ByVal RowIndex As Integer) As ClassContacts Dim strMyName, strPhoneNr, strMyAddress, strDateOfBirth As String Dim strContactID, strMobileNr As String strContactID = DataGridViewContacts.Rows(RowIndex).Cells("ContactID").Value.ToString() strMobileNr = DataGridViewContacts.Rows(RowIndex).Cells("MobileNr").Value.ToString() strMobileNr = strMobileNr.Trim() If Not IsMobileNr(strMobileNr) Then DataGridViewContacts.Rows(RowIndex).Cells("MobileNr").Selected = True MessageBox.Show("Invalid MobileNr") Return Nothing End If strMyName = DataGridViewContacts.Rows(RowIndex).Cells("MyName").Value.ToString() strMyName = strMyName.Trim() If strMyName = "" Then DataGridViewContacts.Rows(RowIndex).Cells("MyName").Selected = True MessageBox.Show("Invalid Name") Return Nothing End If strPhoneNr = DataGridViewContacts.Rows(RowIndex).Cells("PhoneNr").Value.ToString() strPhoneNr = strPhoneNr.Trim() If Not IsPhoneNr(strPhoneNr) Then DataGridViewContacts.Rows(RowIndex).Cells("PhoneNr").Selected = True MessageBox.Show("Invalid PhoneNr") Return Nothing End If strMyAddress = DataGridViewContacts.Rows(RowIndex).Cells("MyAddress").Value.ToString() strMyAddress = strMyAddress.Trim() If strMyAddress = "" Then DataGridViewContacts.Rows(RowIndex).Cells("MyAddress").Selected = True MessageBox.Show("Invalid MyAddress") Return Nothing End If strDateOfBirth = DataGridViewContacts.Rows(RowIndex).Cells("DateOfBirth").Value.ToString() strDateOfBirth = strDateOfBirth.Trim() If Not IsDate(strDateOfBirth) Then DataGridViewContacts.Rows(RowIndex).Cells("DateOfBirth").Selected = True MessageBox.Show("Invalid DateOfBirth") Return Nothing End If

211


Dim obj As New ClassContacts() obj.ContactID = strContactID obj.MobileNr = strMobileNr obj.MyName = strMyName obj.MyAddress = strMyAddress obj.PhoneNr = strPhoneNr obj.DateOfBirth = strDateOfBirth Return obj End Function

Delete ‫ التابع للزر‬Click ‫برمجة معالج الحدث‬ Private Sub ButtonDelete_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonDelete.Click Try ‫ تُعيد‬DataGridViewContacts.SelectedRows.Count ‫الخاصيّة‬ .‫عدد األسطر ال ُمختارة‬ If DataGridViewContacts.SelectedRows.Count = 0 Then MessageBox.Show("No Contacts are selected!") Return End If Dim res As DialogResult res = MessageBox.Show("R U Sure?", "Confirmation", MessageBoxButtons.YesNo, MessageBoxIcon.Question) If res = Windows.Forms.DialogResult.No Then Return End If Dim row As Integer Dim ContactID, strRet As String Dim obj As New ClassContacts() For row = 0 To DataGridViewContacts.SelectedRows.Count - 1 ContactID = DataGridViewContacts.SelectedRows(row).Cells("ContactID").Value.ToString() If IsNumeric(ContactID) Then ‫ال حاجة لحذف األسطر التي تم تحريرها لكنها لم تُحفظ‬ obj.ContactID = ContactID ‫ التابعة لها‬ContactID ‫ أي أن قيمة‬.‫في القاعدة بعد‬ strRet = obj.Delete() ‫ هذه األسطر إذا‬.Nothing ‫ليست عددًا ألنها تكون‬ If strRet <> "" Then ‫كانت ُمختارة للحذف فانها ستختفي بعد القيام بتعبئة‬ MessageBox.Show(strRet) .FillGrid ‫األداة من جديد من خالل استدعاء‬ Return End If End If Next MessageBox.Show("Deleted successfully") FillGrid() Catch ex As Exception MessageBox.Show(ex.Message)

212


‫‪End Try‬‬ ‫‪End Sub‬‬

‫برمجة معالج الحدث ‪ KeyDown‬التابع لألداة ‪DataGridView‬‬ ‫ماذا سيحصل لو اخترنا أسطرًا ُمعينة في الـ ‪ DataGridView‬ثم ضغطنا على المفتاح ‪Delete‬‬ ‫الموجود على لوحة المفاتيح؟ ستالحظ أن األسطر اختفت من األداة لكنها لم تُحذف من القاعدة‪ .‬وذلك‬ ‫ألننا لم نقم ببرمجة عملية الحذف كرد فعل على ضغط هذا المفتاح‪ .‬اختفاء األسطر تم انجازه من قبل‬ ‫األداة ألننا اخترنا ‪ Enable Deleting‬لتمكين ال ُمستخدم من حذف أسطر يختارها‪ .‬ماذا علينا أن‬ ‫نجز حذف السجالت ال ُمختارة أيضًا من القاعدة؟ علينا أن نكتب معالجًا للحدث‬ ‫نفعل حتى نُ ِ‬ ‫‪ KeyDown‬التابع لألداة ‪ .DataGridView‬هذا الحدث عبارة عن حدث من األحداث ال ُمتعلقة‬ ‫بلوحة المفاتيح‪ .‬إذا ضغط ال ُمستخدم على أي مفتاح من لوحة المفاتيح‪ ،‬واألداة التي تملك الـ ‪Focus‬‬ ‫هي األداة ‪ ،DataGridView‬حينها تُرسل األداة هذا الحدث وبالتالي بامكاننا كتابة معالج لهذا‬ ‫الحدث يقوم بالمطلوب وهو حذف السجالت من القاعدة‪.‬‬ ‫البرمجة‬ ‫الحظ أن البارمتر ‪ e‬يحتوي في الخاصيّة ‪ KeyCode‬على كود المفتاح الذي تم الضغط عليه من قبل ال ُمستخدم‪.‬‬ ‫إذا كان هذا الكود للمفتاح ‪( Keys.Delete‬قيمة ثابتة ُمعرفة ضمن ‪ )VB.NET‬حينها نقوم باستدعاء المعالج‬ ‫‪ ButtonDelete_Click‬المشروح أعاله ليقوم بحذف السجالت ال ُمختارة بعد القيام بالفحوصات الالزمة‪ .‬القيم‬ ‫ال ُممرة لهذا االستدعاء هي ‪ sender‬و ‪ Nothing‬وكان بامكاننا تمرير ‪ Nothing‬للبارامترين ألننا ال نستعملهم‬ ‫في المعالج ‪.ButtonDelete_Click‬‬

‫‪Private Sub DataGridViewContacts_KeyDown(sender As System.Object, e As‬‬ ‫‪System.Windows.Forms.KeyEventArgs) Handles DataGridViewContacts.KeyDown‬‬ ‫‪If e.KeyCode = Keys.Delete Then‬‬ ‫)‪ButtonDelete_Click(sender, Nothing‬‬ ‫‪End If‬‬ ‫‪End Sub‬‬

‫‪213‬‬


FileGroupsAdd ‫األمر‬ ‫ اقتصرنا في التصميم التالي على ادخال االسم‬.‫نستعمل هذا األمر الضافة مجموعة أشخاص جديدة‬ .‫ونترك توسيع النموذج الدخال باقي خصائص المجموعة كتمرين للقارئ‬

.‫ قابال للضغط عليه‬Save ‫ يُصبح الزر‬Name ‫بعد ادخال اسم المجموعة الى الصندوق‬

Save ‫ للزر‬Click ‫برمجة معالج الحدث‬ Private Sub ButtonSave_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonSave.Click Try Dim obj As New ClassGroups() ‫ تُعيد تاريخ‬DateTime.Now obj.GroupName = TextBoxGroupName.Text .‫وساعة انشاء المجموعة الجديدة‬ obj.CreationDate = DateTime.Now.ToString() Dim strRet As String ‫ال يُسمح ادخال أكثر من مجموعة‬ strRet = obj.Exists() .‫بنفس االسم‬ If strRet <> "" Then MessageBox.Show(strRet) Return End If ‫هنا يتم ادخال المجموعة الجديدة‬ strRet = obj.Insert() .‫الى القاعدة‬ If strRet <> "" Then MessageBox.Show(strRet) Return End If MessageBox.Show("Successfully Saved") Catch ex As Exception MessageBox.Show(ex.Message) End Try End Sub

214


ClassGroups ‫برمجة الفئة‬ Public Class ClassGroups Private m_GroupID, m_GroupName As String Private m_Description, m_CreationDate As String Public Sub New() 'The Default Constructor Me.m_GroupID = "" Me.m_GroupName = "" Me.m_Description = "" Me.m_CreationDate = "" End Sub Public Sub New(GroupID As String) Me.m_GroupID = GroupID Me.m_GroupName = "" Me.m_Description = "" Me.m_CreationDate = "" End Sub Public Sub New(GroupName As String, Description As String, CreationDate As String) Me.m_GroupName = GroupName Me.m_Description = Description Me.m_CreationDate = CreationDate End Sub Public Property GroupID() As String Get Return m_GroupID End Get Set(ByVal value As String) m_GroupID = value End Set End Property Public Property GroupName() As String Get Return m_GroupName End Get Set(ByVal value As String) m_GroupName = value End Set End Property Public Property Description() As String Get Return m_Description End Get Set(ByVal value As String) m_Description = value End Set End Property 215


Public Property CreationDate() As String Get Return m_CreationDate End Get Set(ByVal value As String) m_CreationDate = value End Set End Property Public Function Exists() As String Dim strRet As String strRet = "" Try Dim strSQL As String Dim Db As New Dbase Dim dt As New DataTable strSQL = "SELECT * FROM Groups WHERE GroupName='{0}'" strSQL = String.Format(strSQL, m_GroupName) dt = Db.SelectFromTable(strSQL) If dt.Rows.Count = 1 Then strRet = "A Group with this Name already exists" End If Catch ex As Exception strRet = "Error in ClassGroups.Exists(): " + ex.Message End Try Return strRet End Function Public Function GetByGroupID() As String Dim strRet As String strRet = "" Try Dim strSQL As String Dim Db As New Dbase Dim dt As New DataTable strSQL = "SELECT * FROM Groups WHERE GroupID={0}" strSQL = String.Format(strSQL, m_GroupID) dt = Db.SelectFromTable(strSQL) If dt.Rows.Count = 1 Then Dim dr As DataRow dr = dt.Rows(0) m_GroupID = dr("GroupID").ToString() m_GroupName = dr("GroupName").ToString() m_Description = dr("Description").ToString() m_CreationDate = dr("CreationDate").ToString() strRet = "" End If Catch ex As Exception

216


strRet = "Error in ClassGroups.GetByGroupID(): " + ex.Message End Try Return strRet End Function Public Function GetByName(ByRef strRet As String) As ClassGroups() strRet = "" Dim A() As ClassGroups Try Dim strSQL As String Dim Db As New Dbase Dim dt As New DataTable strSQL = "SELECT * FROM Groups WHERE GroupName LIKE '%{0}%'" strSQL = String.Format(strSQL, m_GroupName) dt = Db.SelectFromTable(strSQL) A = New ClassGroups(dt.Rows.Count - 1) {} Dim i As Integer For i = 0 To dt.Rows.Count - 1 Dim dr As DataRow Dim obj As New ClassGroups() dr = dt.Rows(i) obj.GroupID = dr("GroupID").ToString() obj.GroupName = dr("GroupName").ToString() obj.Description = dr("Description").ToString() obj.CreationDate = dr("CreationDate").ToString() A(i) = obj Next Return A Catch ex As Exception strRet = "Error in ClassGroups.GetByName(): " + ex.Message End Try Return Nothing End Function Public Function GetAll(ByRef strRet As String) As DataTable strRet = "" Try Dim strSQL As String Dim Db As New Dbase Dim dt As New DataTable strSQL = "SELECT * FROM Groups ORDER BY [GroupName] ASC" dt = Db.SelectFromTable(strSQL) Return dt Catch ex As Exception strRet = "Error in ClassGroups.GetAll(): " + ex.Message End Try Return Nothing End Function

217


Public Function Insert() As String Dim strRet As String strRet = "" Try Dim strSQL As String Dim Db As New Dbase Dim nAffectedRows As Integer strSQL = "INSERT INTO Groups ([GroupName], [Description], [CreationDate])" strSQL += " VALUES ('{0}','{1}','{2}')" strSQL = String.Format(strSQL, m_GroupName, m_Description, m_CreationDate) nAffectedRows = Db.ChangeTable(strSQL) If nAffectedRows = 0 Then strRet = "Failed to save Group!" End If Catch ex As Exception strRet = "Error in ClassGroups.Insert(): " + ex.Message End Try Return strRet End Function Public Function Delete() As String Dim strRet As String strRet = "" Try Dim strSQL As String Dim Db As New Dbase Dim nAffectedRows As Integer strSQL = "DELETE FROM Groups WHERE [GroupID]={0}" strSQL = String.Format(strSQL, m_GroupID) nAffectedRows = Db.ChangeTable(strSQL) If nAffectedRows = 0 Then strRet = "Failed to delete Group!" End If Catch ex As Exception strRet = "Error in ClassGroups.Delete(): " + ex.Message End Try Return strRet End Function

218


Public Function Update() As String Dim strRet As String strRet = "" Try Dim strSQL As String Dim Db As New Dbase Dim nAffectedRows As Integer strSQL = "UPDATE [Groups] SET [GroupName]='{0}', [Description]='{1}', [CreationDate]='{2}'" strSQL += " WHERE [GroupID]={3}" strSQL = String.Format(strSQL, m_GroupName, m_Description, m_CreationDate, m_GroupID) nAffectedRows = Db.ChangeTable(strSQL) If nAffectedRows = 0 Then strRet = "Failed to update Group!" End If Catch ex As Exception strRet = "Error in ClassGroups.Update(): " + ex.Message End Try Return strRet End Function End Class

219


‫تمارين‬ ‫المطلوب برمجة األمر ‪ FileGroupsShow All‬بحسب التصميم التالي‬

‫• تعبئة النموذج بتفاصيل المجموعات الموجودة في الجدول ‪ Groups‬تتم في معالج الحدث‬ ‫‪ Load‬التابع لهذا النموذج وبمساعدة طريقة الـ ‪DataBinding‬‬ ‫• على الجدول أن يكون قابال للتحرير بشكل كامل‬ ‫‪Enable Adding o‬‬ ‫‪Enable Editing o‬‬ ‫‪Enable Deleting o‬‬ ‫• لحذف سجالت‪ ،‬نقوم باختيارها ثم الضغط على الزر ‪ Delete‬أو ال ُمفتاح ‪Delete‬‬ ‫• ولحفظ أية تغييرات قمنا بها‪ ،‬نقوم باختيارها ثم الضغط على الزر ‪Save‬‬ ‫• يجب اخفاء العامود ‪GroupID‬‬ ‫• يجب التأكد من صحة االدخال قبل الحفظ‪ .‬أي‬ ‫‪ o‬ال يجوز للقيم أن تكون فارغة‬ ‫‪ o‬التاريخ ال ُمدخل يجب أن يكون من الحيث المبنى صحيحًا (‪.)IsDate‬‬

‫‪220‬‬


‫برمجة األمر ‪FileGroupsAssign‬‬ ‫يُمكنُنا هذا األمر من تكوين مجموعات خاصة من األشخاص‪ .‬أي أنه يُمكنُنا من اضافة تفاصيل‬ ‫أشخاص معينين الى مجموعات خاصة‪ .‬هذه المجموعات يتم انشاؤها بمساعدة النماذج التي ُش ِرحت‬ ‫سابقًا‪ .‬مهمة هذا األمر هي فقط ادخال أشخاص الى المجموعات أو اخراجهم منها‪ .‬الحظ أننا أمام‬ ‫عالقة كثير لكثير بين الجدولين ‪ Contacts‬و‪ .Groups‬ألن الشخص الواحد قد يُضاف الى أكثر من‬ ‫مجموعة‪ ،‬والمجموعة الواحدة قد تحتوي بطبيعة الحال أكثر من شخص‪.‬‬ ‫التصميم ال ُمقترح‬

‫• تعبئة األداة ‪ ComboBox‬بأسماء المجموعات الموجودة في الجدول ‪ Groups‬تتم في‬ ‫معالج الحدث ‪ Load‬التابع لهذا النموذج وبمساعدة طريقة الـ ‪ .DataBinding‬العامود‬ ‫الخفي سوف يحتوي على الـ ‪ .GroupID‬أما العامود الظاهر فسوف يعرض اسم المجموعة‪.‬‬ ‫• لدينا في النموذج أداتا ‪ListBox‬‬ ‫‪ o‬واحدة مكتوب فوقها ‪ .All Contacts‬تعرض أسماء األشخاص غير الموجودين‬ ‫في المجموعة ال ُمختارة في الـ ‪ComboBox‬‬ ‫‪ o‬وأخرى مكتوب فوقها ‪ .Contacts in the group‬تعرض أسماء األشخاص‬ ‫الموجودين في المجموعة ال ُمختارة في الـ ‪ComboBox‬‬

‫‪221‬‬


‫ نقوم باختيار المجموعة ثم اختيار األشخاص ثم الضغط‬،‫• الدخال أشخاص الى مجموعة ما‬ Add  ‫على الزر‬ ‫ نقوم باختيار المجموعة ثم اختيار األشخاص ثم الضغط‬،‫• الخراج أشخاص من مجموعة ما‬  Remove ‫على الزر‬ ClassGroups ‫برمجة الفئة‬ Public Class ClassContactsGroups Private m_ID, m_GroupID, m_ContactID As String Public Sub New() End Sub Public Property ID() As String Get Return m_ID End Get Set(ByVal value As String) m_ID = value End Set End Property Public Property GroupID() As String Get Return m_GroupID End Get Set(ByVal value As String) m_GroupID = value End Set End Property Public Property ContactID() As String Get Return m_ContactID End Get Set(ByVal value As String) m_ContactID = value End Set End Property

222


Public Function GetAllNotInGroup(ByRef strRet As String) As DataTable strRet = "" Try ‫ ألننا نريد األشخاص‬NOT ‫ مع النفي‬IN ‫الحظ استعمال المعامل‬ Dim strSQL As String ‫( المجموعة ال ُمعطاة من خالل‬NOT IN) ‫الذين ليسوا في‬ Dim Db As New Dbase ContactID Dim dt As New DataTable strSQL = "SELECT ContactID, MyName FROM Contacts WHERE ContactID NOT IN " strSQL += " (SELECT ContactID FROM ContactsGroups WHERE GroupID=" + m_GroupID.ToString strSQL += " ) " dt = Db.SelectFromTable(strSQL) Return dt Catch ex As Exception strRet = "Error in ClassContactsGroups.GetAllNotInGroup(): " + ex.Message End Try Return Nothing End Function Public Function GetAllInGroup(ByRef strRet As String) As DataTable strRet = "" Try Dim strSQL As String ‫( المجموعة‬IN) ‫هنا نُريد أن نحصل على األشخاص الذين في‬ Dim Db As New Dbase ContactID ‫ال ُمعطاة من خالل‬ Dim dt As New DataTable strSQL = "SELECT ContactID, MyName FROM Contacts WHERE ContactID IN " strSQL += " (SELECT ContactID FROM ContactsGroups WHERE GroupID=" + m_GroupID.ToString strSQL += " ) " dt = Db.SelectFromTable(strSQL) Return dt Catch ex As Exception strRet = "Error in ClassContactsGroups.GetAllNotInGroup(): " + ex.Message End Try Return Nothing End Function

223


Public Function Insert() As String Dim strRet As String strRet = "" ‫ التفاصيل يجب أن تكون‬.‫عملية الدخال تفاصيل مجموعة جديدة‬ Try .‫ُمعطاة للكائن عبر خصائصه‬ Dim strSQL As String Dim Db As New Dbase Dim nAffectedRows As Integer strSQL = "INSERT INTO ContactsGroups ([GroupID], [ContactID])" strSQL += " VALUES ({0},{1})" strSQL = String.Format(strSQL, m_GroupID, m_ContactID) nAffectedRows = Db.ChangeTable(strSQL) If nAffectedRows = 0 Then strRet = "Failed to save Group Assignment!" End If Catch ex As Exception strRet = "Error in ContactsGroups.Insert(): " + ex.Message End Try Return strRet End Function Public Function Delete() As String Dim strRet As String ‫عملية لحذف تفاصيل المجموعة من الجدول التي رقمها معطى‬ strRet = "" .ID ‫للخاصيّة‬ Try Dim strSQL As String Dim Db As New Dbase Dim nAffectedRows As Integer strSQL = "DELETE FROM ContactsGroups WHERE [ID]={0}" strSQL = String.Format(strSQL, m_ID) nAffectedRows = Db.ChangeTable(strSQL) If nAffectedRows = 0 Then strRet = "Failed to delete Group Assignment!" End If Catch ex As Exception strRet = "Error in ContactsGroups.Delete(): " + ex.Message End Try Return strRet End Function End Class

224


‫البرمجة‬ Private Sub FormAssignContactsToGroups_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load FillComboBoxGroups() End Sub Private Sub FillComboBoxGroups() Try Dim obj As New ClassGroups() Dim strRet As String = "" ‫ بأسماء المجموعات الموجودة في‬ComboBox ‫عملية لتعبئة األداة‬ Dim dt As DataTable ‫ سوف يحتوي‬ValueMember ‫ العامود الخفي‬.Groups ‫الجدول‬ dt = obj.GetAll(strRet) ‫فسوف‬ DisplayMember ‫ أما العامود الظاهر‬.GroupID ‫على الـ‬ If dt Is Nothing Then .GroupName ‫يعرض اسم المجموعة أي‬ MessageBox.Show(strRet) Return End If ComboBoxGroups.DisplayMember = "GroupName" ComboBoxGroups.ValueMember = "GroupID" ComboBoxGroups.DataSource = dt Catch ex As Exception MessageBox.Show(ex.Message) End Try End Sub Private Sub ComboBoxGroups_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ComboBoxGroups.SelectedIndexChanged GetAllContactsNotInGroup() GetAllContactsInGroup() End Sub

225


Private Sub GetAllContactsNotInGroup() Try

(NOT ‫عملية لعرض جميع األشخاص الذين ليسوا في‬ ContactID ‫ المجموعة ال ُمعطاة من خالل‬IN)

If ComboBoxGroups.Items.Count = 0 Then Return End If ‫ والغاء مصدر‬ListBoxLeft ‫هنا يتم تفريغ القائمة‬ ListBoxLeft.DataSource = Nothing ‫معلوماتها أي‬

ListBoxLeft.DataSource = Nothing ListBoxLeft.Items.Clear()

Dim obj As New ClassContactsGroups() obj.GroupID = ComboBoxGroups.SelectedValue.ToString Dim dt As New DataTable Dim strRet As String = "" dt = obj.GetAllNotInGroup(strRet) If dt Is Nothing Then MessageBox.Show(strRet) Return End If ‫ سوف يحتوي على‬ValueMember ‫العامود الخفي‬ ListBoxLeft.DisplayMember = "MyName" ‫ أما العامود الظاهر‬.ContactID ‫الـ‬ ListBoxLeft.ValueMember = "ContactID" ‫ فسوف يعرض اسم الشخص أي‬DisplayMember ListBoxLeft.DataSource = dt .MyName Catch ex As Exception MessageBox.Show(ex.Message) End Try End Sub

226


Private Sub GetAllContactsInGroup()

‫( المجموعة‬IN) ‫عملية لعرض جميع األشخاص الذين في‬ ContactID ‫ال ُمعطاة من خالل‬

Try If ComboBoxGroups.Items.Count = 0 Then Return End If ListBoxRight.DataSource = Nothing ListBoxRight.Items.Clear() Dim obj As New ClassContactsGroups() obj.GroupID = ComboBoxGroups.SelectedValue.ToString Dim dt As New DataTable Dim strRet As String = "" dt = obj.GetAllInGroup(strRet) If dt Is Nothing Then MessageBox.Show(strRet) Return End If ListBoxRight.DisplayMember = "MyName" ListBoxRight.ValueMember = "ContactID" ListBoxRight.DataSource = dt Catch ex As Exception MessageBox.Show(ex.Message) End Try End Sub

227


‫تمارين‬ ‫تمرين رقم ‪1‬‬ ‫المطلوب استبدال أداتي ‪ DataGridView‬في النموذج التابع لألمر ‪ Assign‬بأداتي الـ ‪ListBox‬‬ ‫الموجودتين في النموذج بحيث نظهر جميع تفاصيل األشخاص وليس فقط االسم كما هو األمر اآلن‪.‬‬

‫تمرين رقم ‪2‬‬ ‫‪English to Arabic Dictionary‬‬ ‫المطلوب‬ ‫عليكم برمجة جميع األجزاء المطلوبة إلدارة قاموس انجليزي عربي‬ ‫األجزاء المطلوبة‬ ‫• عرض محتوى القاموس في صفحة خاصة‬ ‫• حذف كلمات موجودة في القاموس‬ ‫• إضافة كلمات جديدة الى القاموس‬ ‫• تعديل أو تحديث كلمات موجودة في القاموس‬ ‫• مبنى القائمة الرئيسية‬ ‫‪ o‬العنصر ‪ Edit‬يعرض جميع الكلمات بواسطة ‪ DataGridView‬قابل للتحرير‬ ‫بشكل كامل (اضافة وخذف وتعديل)‪ .‬هذا العنصر ال يكون قابال لالختيار اال إذا كان‬ ‫ال ُمستخدم ‪.LoggedIn‬‬ ‫‪ o‬العنصر ‪ Search‬يوفر صندوق نص للبحث عن معاني كلمة ما‪ .‬البحث يتم بواسطة‬ ‫المعامل ‪ .LIKE‬عرض النتائج يتم بواسطة ‪ DataGridView‬غير قابل للتحرير‪.‬‬ ‫▪ ال يجوز البحث عن كلمات فارغ‪.‬‬ ‫▪ يتم ابالغ ال ُمستخدم بأن الكلمة غير موجودة في القاموس في حال لم يُعثر‬ ‫عليها أو على كلمات شبيهة بها‪.‬‬

‫‪228‬‬


‫‪ o‬العنصر ‪ About‬يُظهر نموذجًا فيه معلومات عن التطبيق بتصميم من اختياركم‪.‬‬ ‫‪ o‬العنصر ‪ Login‬كما تمت برمجته في األمثلة ال ُمختلفة‪.‬‬ ‫‪ o‬العنصر ‪ Train‬يُظهر نموذجًا فيه‬ ‫▪ زر ‪ Get Random Word‬يختار كلمة من الجدول ‪Dictionary‬‬ ‫بشكل عشوائي و‪ 3‬معان عشوائية خطأ‪ .‬تُعرض الكلمة بواسطة ‪Label‬‬ ‫مناسب‪ .‬ثم تُعرض المعاني بواسطة ‪ RadioButton‬لكل معنى‪.‬‬ ‫▪ زر ‪ Check My Answer‬يفحص االجابة ويُبلغ ال ُمستخدم بواسطة‬ ‫‪ MessageBox‬عن النتيجة‪.‬‬ ‫▪ يعُد ويعرض بواسطة ‪ Label‬مناسب كم سؤاال أجيب عليه بشكل صحيح‬ ‫من العدد االجمالي لألسئلة التي أُنشئت‪ .‬هذه االحصائية تُعرض دائ ًما في‬ ‫النموذج‪.‬‬ ‫▪ من ال ُمفضل أن يتم في معالج الحدث ‪ Load‬التابع للنموذج اختيار مثال‬ ‫‪ 100‬كلمة مع تفاصيلها بشكل عشوائي وحفظ النتيجة بمصفوفة كائنات من‬ ‫نوع ‪ ClassWords‬ثم اختيار الكلمات من هذه المصفوفة كلما ضغط‬ ‫ال ُمستخدم على الزر ‪( Get Random Word‬كمثال على ذلك راجع‬ ‫كيفية برمجة األمر ‪ FileContactsNavigate‬المشروح أعاله)‪.‬‬ ‫الختيار سجالت بشكل عشوائي بامكانكم االستعانة باألمر التالي‬

‫*‪SELECT TOP N TableName.‬‬ ‫]‪FROM [TableName‬‬ ‫)]‪ORDER BY RND([PKFiledName‬‬ ‫أي اختر أول )‪( N (TOP‬عدد طبيعي) سجل (كل الحقول) من الجدول ‪ TableName‬ورتبهم‬ ‫بشكل عشوائي )‪ (Random‬بحسب حقل ال ُمفتاح الرئيسي‪ .‬هذا األمر سيعيد لنا ‪ N‬سجال مختارا‬ ‫بشكل عشوائي‪.‬‬

‫‪229‬‬


‫*‪SELECT TOP 3 Contacts.‬‬ ‫‪FROM Contacts‬‬ ‫)]‪ORDER BY RND([ContactID‬‬ ‫هذا األمر سيعيد لنا من الجدول ‪ 3 Contacts‬سجالت مختارة بشكل عشوائي بحسب المفتاح‬ ‫‪.ContactID‬‬ ‫*‪SELECT TOP 1 Words.‬‬ ‫‪FROM Words‬‬ ‫)]‪ORDER BY RND([WordID‬‬ ‫هذا األمر سيعيد لنا من الجدول ‪ Words‬كلمة واحدة مختارة بشكل عشوائي بحسب المفتاح‬ ‫‪.WordID‬‬ ‫قاعدة البيانات‬ ‫يجب إضافة الجدول ‪ Users‬من األمثلة السابقة إلى القاعدة‬ ‫يجب إضافة الجدول ‪ Words‬إلى القاعدة وفيه الحقول التالية‪:‬‬ ‫اسم الحقل‬ ‫‪WordID‬‬

‫شرح‬

‫نوع الحقل‬

‫‪ Auto Number PK‬رقم أوحد لكل كلمة‪ :‬مفتاح رئيسي‬

‫‪ String, Index (No duplicates) Word‬الكلمة‬ ‫‪Meanings‬‬

‫‪ String‬معاني الكلمة‬

‫‪230‬‬


‫تمرين رقم ‪3‬‬ ‫المطلوب‬ ‫برمجة امكانيات لتحرير ال ُمستخدمين الموجودين في الجدول ‪ Users‬بواسطة ‪.DataGridView‬‬ ‫نضيف لهذا الغرض الى القائمة الرئيسية األمر ‪FileUsers‬‬ ‫عند اختيار هذا األمر تظهر النافذة التالية‬

‫الحظ أننا أضفنا حقال جديدًا الى الجدول باسم ‪ IsAmin‬من نوع ‪ Yes/No‬وسنعرضه على شكل‬ ‫‪ CheckBox‬في الـ ‪ .DataGridView‬األداة ‪ DataGridView‬تقوم خالل عملية الـ‬ ‫‪ DataBinding‬بتجهيز كل سطر بأداة عرض مناسبة بنا ًء على نوع الحقل كما هو ُمخزن في كائن‬ ‫الـ ‪ DataTable‬الذي أعطي للخاصية ‪ DataSource‬التابعة لألداة ‪ .DataGridView‬فمثال‬ ‫األنواع الرقمية والنصوص والتواريخ تُعرض كما رأينا بواسطة األداة ‪ TextBox‬وأما النوع‬ ‫‪ Yes/No‬فانه يُعرض بواسطة ‪ .CheckBox‬كل هذا بدون أي تدخل من قبل المبرمج‪.‬‬ ‫عند اختيار األمر ‪ FileUsers‬تظهر النافذة التالية‬

‫‪231‬‬


‫على األداة ‪ DataGridView‬أن تكون قابلة للتحرير بشكل كامل وبمساعدة الزرين ‪ Save‬و‬ ‫‪.Delete‬‬ ‫الدخال قيمة لحقل من نوع ‪ Yes/No‬نُدخل القيمة ‪ True‬للقيمة ‪ Yes‬والقيمة ‪ False‬للقيمة ‪.No‬‬

‫أمثلة‬ ‫‪UPDATE [Users] SET [UserName]='Khalil', [UserPW]='01123',‬‬ ‫‪[IsAdmin]=True WHERE [UserID]=1‬‬

‫تمرين رقم ‪4‬‬ ‫المطلوب‬ ‫عليكم برمجة جميع األجزاء المطلوبة إلدارة مركز استكماالت بسيط وفق ال ُمعطيات التالية‪:‬‬ ‫قاعدة البيانات‬ ‫الجداول التالية تم استعمالها في الفصل الذي تحدثنا فيه عن لغة ‪( SQL‬أمثلة على العالقة ‪)M-N‬‬

‫العالقات هي كالتالي‪:‬‬

‫‪232‬‬


‫األجزاء المطلوبة‬ ‫• تحرير جدول الكورسات ‪Lessons‬‬ ‫• تحرير جدول الطالب ‪Students‬‬ ‫• تسجيل طالب لكورسات ُمعينة‬ ‫• حذف طالب من كورسات ُمعينة‬ ‫• عرض الكورسات التي يتعلمها طالب ما‬ ‫• عرض الطالب الذين يتعلمون كورس ما‬ ‫• مبنى القائمة الرئيسية (جميع العناصر ما عدا ‪ Login‬ال تكون قابلة لالختيار اال إذا كان‬ ‫ال ُمستخدم ‪)LoggedIn‬‬ ‫‪ o‬العنصر ‪ EditStudents‬يعرض جميع الطالب بواسطة ‪DataGridView‬‬ ‫قابل للتحرير بشكل كامل (اضافة وخذف وتعديل)‪.‬‬ ‫‪ o‬العنصر ‪ EditLessons‬يعرض جميع الكورسات بواسطة ‪DataGridView‬‬ ‫قابل للتحرير بشكل كامل (اضافة وخذف وتعديل)‪.‬‬ ‫‪ o‬العنصر ‪ EditMarks‬يوفر امكانية الدخال عالمات الطالب في كورس ما‬ ‫بواسطة ‪ DataGridView‬فيه أعمدة لتفاصيل الطالب وهي غير قابلة للتغيير‪.‬‬ ‫وعامود باسم ‪ Mark‬الدخال العالمة لكل طالب‪.‬‬ ‫▪‬

‫يجب اضافة حقل جديد باسم ‪ Mark‬الى الجدول ‪ LessonsStudents‬من‬ ‫نوع ‪ Number‬مجاله من ‪ 0‬الى ‪( 100‬يشمل)‪.‬‬

‫▪ لجعل عامود ما غير قابل للتغيير نجعله ‪ ReadOnly‬على النحو التالي –‬ ‫مباشرة بعد القيام بعملية الـ ‪DataBinding‬‬ ‫•‬

‫‪DataGridView1.Columns("ColName").ReadOnly = True‬‬

‫‪ o‬العنصر ‪ Register‬يوفر امكانية لتسجيل طالب ما لكورس ما أو حذفه (شبيه‬ ‫باألمر ‪.)FileGroupsAssign‬‬ ‫‪ o‬العنصر ‪ SearchStudent‬لعرض الكورسات التي يتعلمها طالب ما‪ .‬عرض‬ ‫النتائج يتم بواسطة ‪ DataGridView‬غير قابل للتحرير‪.‬‬

‫‪233‬‬


‫‪ o‬العنصر ‪ SearchLesson‬لعرض الطالب الذين يتعلمون كورس ما‪ .‬عرض‬ ‫النتائج يتم بواسطة ‪ DataGridView‬غير قابل للتحرير‪.‬‬ ‫‪ o‬العنصر ‪ About‬يُظهر نموذجًا فيه معلومات عن التطبيق بتصميم من اختياركم‪.‬‬ ‫‪ o‬العنصر ‪ Login‬كما تمت برمجته في األمثلة ال ُمختلفة‪.‬‬

‫تمرين رقم ‪5‬‬ ‫الهدف‪ :‬استعمال ‪ DropDownList‬داخل الـ ‪.DataGridView‬‬ ‫نريد تغيير صفحة تحرير المستخدمين بحيث نفرّق بين ثالثة مجموعات من المستخدمين‪:‬‬ ‫• مدراء للموقع ‪Admin‬‬ ‫• معلمين ‪Teacher‬‬ ‫• طالب ‪Student‬‬

‫من أجل هذا الغرض تم تغيير الجدول ‪ Users‬في قاعدة البيانات ليصبح كالتالي‪:‬‬

‫حتى اآلن وفي جميع األمثلة تركنا أمر انشاء األدوات الالزمة لعرض وتحرير المعلومات لألداة‬ ‫‪ DataGridView‬ورأينا كيف أنها زودتنا بأداة مناسبة لكل حقل بحسب نوعه‪ .‬لكن ماذا لو أردنا أن‬ ‫يختار ال ُمستخدم قيمة واحدة فقط من مجموعة قيم ممكنة بحيث ال تُقبل أية قيمة أخرى من خارج‬ ‫مجموعة القيم هذه؟ الحل األمثل يكون في عرض هذه القيم داخل ‪.ComboBox‬‬ ‫‪ DataGridView‬ال تقوم بذلك من تلقاء نفسها وانما سنقوم بتحديد األدوات بشكل يدوي خالل‬ ‫عملية تصميم الـ ‪.DataGridView‬‬

‫‪234‬‬


‫اضغط في عرض الـ ‪ Design‬على السهم الصغير الذي يظهر في الجهة اليمنى العليا من األداة‬ ‫‪ .DataGridView‬حينها ستظهر قائمة فيها األمر ‪ Edit Columns‬أي تحرير األعمدة‪.‬‬

‫حينها ستظهر النافذة التالية لتحرير األعمدة‬

‫نضغط على الزر …‪ Add‬لنبدأ باضافة العامود األول في النافذة التي تظهر‬

‫‪235‬‬


‫‪ .1‬اسم العامود‬ ‫‪ .2‬نوع األداة‬ ‫‪ .3‬عنوان العامود‬ ‫‪ .4‬تحديد بعض‬ ‫خصائص‬ ‫العامود‪ :‬مثال‬ ‫مرئي وللقراءة‬ ‫فقط‬

‫بعدها نضغط على الزر ‪ Add‬لحفظ التغييرات‪.‬‬ ‫واآلن نضغط على الزر …‪ Add‬لنضيف باقي األعمدة‪ .‬اخترنا لجميع األعمدة ‪ TextBox‬باستثناء‬ ‫العامود ‪ Group‬الذي سيحتوي على ‪ ComboBox‬لعرض األنواع ال ُممكنة لل ُمستخدمين‪:‬‬

‫‪236‬‬


‫بعد االنتهاء من اضافة جميع األعمدة نُغلق النافذة بالضغط على ‪ .Close‬النافذة التالية تُلخص جميع‬ ‫األعمدة الجديدة التي أضفناها الى الـ ‪DataGridView‬‬

‫‪237‬‬


‫ من جديد على النحو التالي‬DataGridView ‫واآلن سنكتب عملية تعبئة الـ‬ Private Sub FillGrid() Dim strRet As String = "" Dim obj As New ClassUsers ‫نحصل على جميع ال ُمستخدمين كمصفوفة‬ Dim A() As ClassUsers GetAllAsArray ‫بمساعدة العملية‬ A = obj.GetAllAsArray(strRet) If A Is Nothing Then MessageBox.Show(strRet) Return ‫هنا نحصل على مؤشر على‬ End If ‫العامود الذي يحوي القائمة ال ُمنسدلة‬ Dim ComboBoxColumn As DataGridViewComboBoxColumn ComboBoxColumn = CType(DataGridViewUsers.Columns("Group"), DataGridViewComboBoxColumn) ComboBoxColumn.Items.Add("Administrator") ComboBoxColumn.Items.Add("Teacher") ComboBoxColumn.Items.Add("Student")

‫هنا نضيف جميع أنواع ال ُمستخدمين الى‬ ‫القائمة ال ُمنسدلة التي في العامود‬ ComboBoxColumn

‫ الحظ أننا نمرر قيم‬.‫هنا نقوم بتعبئة األداة بشكل يدوي‬ String ‫ كمصفوفة أحادية من نوع‬Add ‫السطر الى العملية‬

For i As Integer = 0 To A.Length - 1 obj = A(i) DataGridViewUsers.Rows.Add({obj.UserID, obj.UserName, obj.UserPW, obj.Group}) Next LabelNumOfRecords.Text = "Num Of Records: " + A.Length.ToString End Sub

‫الصورة التالية تُبين النتيجة‬

238


‫تمرين رقم ‪6‬‬

‫األداة ‪TabControl‬‬ ‫هذه األداة ‪ TabControl‬عبارة عن نموذج يحتوي على عدة تبويبات أو ما يُسمى باالنجليزية ‪Tabs‬‬ ‫وهي عبارة عن نماذج فرعيّة أو أجزاء ضمن نفس النموذج‪ .‬األداة متوفرة ضمن الـ ‪ .Toolbox‬في‬ ‫التطبيق التالي سوف نبني نموذجًا فيه ‪ 3‬تبويبات لفحص الفئة ‪ .Dbase.vb‬التطبيق يُمكنُنا من كتابة‬ ‫أوامر ‪ SQL‬وتنفيذها على قاعدة بيانات ُمعينة ومن ثم عرض النتائج وهو ما يُسمة بمحرر ‪SQL‬‬ ‫أي ‪.SQL Editor‬‬ ‫• التبويب األول وعنوانه ‪ Select From Table‬لتنفيذ أوامر ‪ SELECT‬تعيد جدوال يتم‬ ‫عرضه بواسطة األداة ‪.DataGridView‬‬ ‫• التبويب الثاني وعنوانه ‪ Change Table‬لتنفيذ أوامر ‪UPDATE, DELETE,‬‬ ‫‪ INSERT INTO‬تعيد عدد السجالت التي تأثرت بتنفيذ األمر ويتم عرض النتيجة بواسطة‬ ‫‪.MessageBox‬‬ ‫• التبويب الثالث وعنوانه ‪ Execute Scalar‬لتنفيذ أوامر تحتوي عمليات احصائية تعيد قيمة‬ ‫واحدة‪.‬‬ ‫اختر قاعدة بيانات مناسبة فيها على األقل جدوالن‪.‬‬

‫هذه هي التبويبات الثالثة‬

‫التصميم ال ُمقترح‬

‫هنا نكتب األمر‪ .‬األداة عبارة‬ ‫عن ‪ TextBox‬متعددة األسطر‬ ‫أي ‪MultiLine = True‬‬

‫هنا نعرض نتيجة تنفيذ األمر‪ .‬األداة‬ ‫عبارة عن ‪DataGridView‬‬ ‫بدون امكانيات تحرير‬

‫‪239‬‬


‫لتنفيذ األمر نضغط على الزر ‪.Execute‬‬ ‫التبويب الثاني‬

‫هنا نكتب األمر‪ .‬األداة عبارة‬ ‫عن ‪ TextBox‬متعددة‬ ‫األسطر أي = ‪MultiLine‬‬ ‫‪ .True‬نتيجة التنفيذ تُعرض‬ ‫بواسطة ‪MessageBox‬‬

‫مبنى التبويب الثالث كمبنى التبويب األول‪.‬‬ ‫اضافة األداة تتم من خالل سحبها من الـ ‪ Toolbox‬ورميها على النموذج ومن ثم تحديد بعض‬ ‫الخصائص‪ .‬عدد التبويبات االفتراضي ‪ .2‬الضافة تبويبات نضغط على السهم الصغير الذي يظهر‬ ‫في الزاوية اليمنى العليا ومن ثم اختيار األمر ‪Add Tab‬‬

‫‪240‬‬


‫احرص على اعطاء األدوات أسماء ال تتكرر مثل‬ ‫ و‬ButtonExecuteTab3 ‫ و‬ButtonExecuteTab2 ‫ و‬ButtonExecuteTab1 ‫ و‬TextBoxSQLStatementTab2 ‫ و‬TextBoxSQLStatementTab1 .TextBoxSQLStatementTab3

241


‫الملفات‬ ‫تعتبر الملفات الهياكل األساسية لتخزين المعلومات بشكل دائم على القرص الصلب للحاسوب‪ .‬يوجد‬ ‫أنواع عدة من الملفات تبعا لألنواع المختلفة من التطبيقات‪ .‬فهنالك على سبيل المثال ملفات األوفيس‬ ‫مثل ملفات الورد واإلكسيل والبوربوينت وما شابه ذلك‪ .‬وملفات الـ ‪ PDF‬وغيرها‪ .‬وال يمكن تصور‬ ‫العمل مع الحواسيب بدون استعمال هذه الهياكل لحفظ المعلومات‪.‬‬ ‫الملف )‪ (File‬عبارة عن مجموعة من المعلومات ال ُمخزنة في مجلد ما )‪(Folder or Directory‬‬ ‫في القرص الصلب للحاسوب )‪ .(Hard Disk‬بعد فتح الملف من قبل ال ُمبرمج (أي بآليات برمجية)‬ ‫يُسمى الملف حينها ‪ Stream‬أي انسياب أو تدفق أي تدفق مجموعة من البيانات من مكان الى آخر‬ ‫عبر قناة اتصال‪ .‬يُمكن النظر الى الـ ‪ Stream‬على أنه عبارة عن سلسلة البايتات ‪(A Sequence‬‬ ‫)‪ Of Bytes‬التي نحصل عليها بعد فتح الملف‪ .‬هنالك نوعان من الـ ‪Streams‬‬ ‫‪ Input Stream‬يُستعمل لقراءة معلومات من الملف )‪(Reading Data from a File‬‬ ‫‪ Output Stream‬يُستعمل لكتابة معلومات في الملف )‪(Writing Data into a File‬‬ ‫هنالك نوعان أساسيان من الملفات‬ ‫• ملفات نصوص )‪ (Text Files‬عبارة عن عبارة عن أسطر غير مشفرة ويمكن فتحها بأي‬ ‫ُمحرر نصوص بسيط مثل ‪ Note Pad‬أو ُمتقدم مثل ‪.MS Word‬‬ ‫• ملفات بنارية ُمشفرة )‪ (Binary Files‬فتحها وفهم ال ُمحتوى يحتاج الى معرفة كيفية‬ ‫تخزينها‪.‬‬ ‫في هذا الفصل سنشرح فقط كيفية التعامل مع ملفات النصوص‪.‬‬

‫‪VB.Net I/O Classes‬‬ ‫توفر ‪ VB.NET‬ضمن فضاء األسماء ‪( System.IO‬أي ‪ )System Input Outpt‬مجموعة‬ ‫من الفئات التي تُمكن ال ُمستخدم من التعامل مع الملفات‪ .‬والمقصود بالتعامل مع الملفات‬ ‫• انشاء مفات جديدة‬ ‫• حذف ملفات موجودة‬ ‫‪242‬‬


‫• فتح ملفات للقراءة أو للكتابة‬ ‫• الكتابة داخل ملفات ما‬ ‫• اغالق ملفات مفتوحة‬ ‫• وما الى ذلك‬ ‫الجدول التالي يُلخص بعض الفئات ال ُمهمة ضمن ‪System.IO‬‬ ‫الشرح‬

‫الفئة‬ ‫‪BinaryReader‬‬

‫لقراءة المعلومات من ملفات بينارية (أي مشفرة)‬

‫‪BinaryWriter‬‬

‫لكتابة المعلومات في ملفات بينارية‬

‫‪BufferedStream‬‬

‫ذاكرة مؤقتة من البايتات لحفظ ‪Stream‬‬

‫‪Directory / DirectoryInfo‬‬

‫للتعامل مع المجلدات‬

‫‪File / FileInfo‬‬

‫للتعامل مع الملفات‬

‫‪FileStream / MemoryStream‬‬

‫لقراءة وكتابة معلومات من والى أي مكان في الملف‬

‫‪Path‬‬

‫للتعامل مع المسارات‬

‫‪StreamReader‬‬

‫لقراءة رموز )‪ (characters‬من ‪Stream‬‬

‫‪StreamWriter‬‬

‫لكتابة رموز )‪ (characters‬الى ‪Stream‬‬

‫‪StringReader‬‬

‫للقراءة من ‪String Buffer‬‬

‫‪StringWriter‬‬

‫للكتابة في ‪String Buffer‬‬

‫الفئة ‪FileStream‬‬ ‫قلنا بأن هذه الفئة تُمكننا من قراءة وكتابة معلومات من والى أي مكان في ملف ما‪ .‬هذه الفئة ُمشتقة‬ ‫من الفئة ‪ Stream‬التي هي عبارة عن فئة مجردة وبالتالي ال يمكن التعامل معها بشكل مباشر وانما‬ ‫فقط من خالل فئات مشتقة منها‪ .‬من أجل فتح ملف موجود أو انشاء ملف جديد سوف ننشئ كائنًا من‬ ‫الفئة ‪.FileStream‬‬

‫‪243‬‬


‫مثال‬ ‫األمر التالي ينشئ كائنًا لفتح الملف ‪( Data.txt‬البارامتر األول) للقراءة والكتابة (البارمتر األخير)‬ ‫ان كان موجودًا‪ .‬خالف ذلك يتم انشاء الملف (البارامتر الثاني)‪.‬‬ ‫‪Dim fs As FileStream = New FileStream("Data.txt",‬‬ ‫‪FileMode.OpenOrCreate,‬‬ ‫)‪FileAccess.ReadWrite‬‬ ‫وبشكل عام تتلقى العملية البنائية ‪ 3‬بارمترات‬ ‫الشرح‬

‫البارمتر‬ ‫األول ‪FileName‬‬

‫يُحدد اسم الملف‬

‫الثاني من نوع ‪FileMode‬‬

‫نوع الفتح مثال فتح ان كان موجودًا أو انشاء ان لم يكن‬ ‫موجودًا‪ .‬ممكن أن يكون واحدا من القيم التالية‪:‬‬ ‫‪ :FileMode.Append‬يفتح الملف بحيث تتم اضافة‬ ‫المعلومات الى نهاية الملف‪.‬‬ ‫‪ :FileMode.Create‬انشاء ملف جديد‪.‬‬ ‫‪ :FileMode.Open‬فتح ملف موجود‪.‬‬ ‫‪ :FileMode. OpenOrCreate‬فتح الملف ان كان‬ ‫موجودًا أو انشاؤه ان لم يكن موجودًا‪.‬‬ ‫‪ :FileMode. Truncate‬فتح ملف موجود وتفريغه‬ ‫من محتواه‪.‬‬

‫الثالث الحقوق من نوع ‪FileAccess‬‬

‫هل قراءة فقط أم كتابة وقراءة وما الى ذلك‪ .‬ممكن أن‬ ‫يكون واحدا من القيم التالية‪:‬‬ ‫‪ :FileAccess.Read‬للقراءة فقط‬ ‫‪ :FileAccess.ReadWrite‬للقراءة والكتابة‬ ‫‪ :FileAccess.Write‬للكتابة فقط‬

‫‪244‬‬


‫الستعمال هذه الفئات نريد كتابة تطبيق يفتح ملفات نصوص عادية ويعرض محتواها بواسطة األداة‬ ‫‪ RichTextBox‬ويوفر امكانية لل ُمستخدم لحفظ أية تغييرات قام بها‪ .‬سوف نتعرف أيضًا على نافذة‬ ‫الحوار الخاصة بفتح الملفات من مكان ُمعين في القرص الصلب وأيضًا على نافذة الحوار لحفظ ملف‬ ‫ما في مكان ما في القرص الصلب للحاسوب‪.‬‬ ‫التصميم ال ُمقترح‬ ‫الضغط على الزر …‪ Browse‬يُظهر نافذة الحوار ‪ OpenFileDialog‬المتوفرة في الـ‬ ‫‪ .Toolbox‬هذه النافذة تُمكن ال ُمستخدم من اختيار الملف الذي يريد فتحه من أي مكان في القرص‬ ‫الصلب للحاسوب‪ .‬الثالث نقاط بعد االسم تعني أن األمر ال يُنفذ مباشرة وانما ستظهر نافذة حوار قبل‬ ‫ذلك‪.‬‬

‫• لى الزر ‪ Open File‬يفتح الملف الذي اختاره ال ُمستخدم ويعرض ُمحتواه بواسطة األداة‬ ‫‪RichTextBox‬‬ ‫• الضغط على الزر ‪ Save File‬يحفظ التغييرات التي أُجريت على محتوى الملف المفتوح‪.‬‬ ‫• الضغط على الزر …‪ Save As‬يُظهر نافذة الحوار ‪ SaveFileDialog‬المتوفرة في الـ‬ ‫‪ .Toolbox‬هذه النافذة تُمكن ال ُمستخدم من اختيار اسم للملف ومجلد في القرص الصلب‪.‬‬ ‫التطبيق يقوم بعدها بحفظ نسخة من الملف المفتوح تحت االسم الذي أدخله ال ُمستخدم وفي‬ ‫المجلد الذي اختاره‪.‬‬ ‫‪245‬‬


‫اضافة نافذة الحوار ‪OpenFileDialog‬‬ ‫علينا سحب هذه األداة من الـ ‪ Toolbox‬ورميها على النموذج‪ .‬ال بأس بأن نبقي االسم‬ ‫‪ OpenFileDialog1‬ألننا سوف نستعمل أداة واحدة فقط في النموذج‪ .‬الحظ أن هذه األداة تظهر‬ ‫أسفل النموذج بالضبط مثل القائمة الرئيسية ‪ .MenuStrip‬بامكاننا تحديد قيم للخصائص التالية‬ ‫التابعة لألداة ‪ OpenFileDialog1‬وهي‬ ‫‪ :Filter‬تُحدد نوع الملفات التي‬ ‫ستظهرها النافذة‪ .‬الفلتر عبارة‬ ‫سلسلة من األزواج التي يفصل بينها‬ ‫الرمز |‪ .‬كل زوج مكون من نصين‬ ‫يفصل بينهم أيضا الرمز |‪ .‬النص‬ ‫األول يظهر لل ُمستخدم في جزء‬ ‫خاص‪ .‬مثال‪ .Txt Files :‬والنص‬ ‫الثاني عبارة عن عادة الرمز *‬ ‫متبوعة بنقطة ثم ملحق الملفات التي‬ ‫نريد اظهارها مثال ‪ .*.txt‬السلسلة‬ ‫تعني أنه بامكاننا فلترة واظهار أكثر‬ ‫من نوع من الملفات‪ .‬الظهار كل‬ ‫الملفات نكتب *‪ .All Files|*.‬هذه‬ ‫األجزاء ستظهر بداخل‬ ‫‪ ComboBox‬كما هو ظاهر‬ ‫بالصورة التالية‪.‬‬ ‫‪ :FileName‬النص االبتدائي الذي‬ ‫سيظهر في الصندوق الذي يظهر‬ ‫فيه اسم الملف ال ُمختار‪ .‬هنا سيظهر‬ ‫النص ‪.Select your file‬‬

‫‪246‬‬


Browse… ‫ للزر‬Click ‫برمجة معالج الحدث‬ Private Sub ButtonBrowse_Click(sender As System.Object, e As System.EventArgs) Handles ButtonBrowse.Click ‫ لنافذة الحوار‬ShowDialog() ‫نستدعي العملية‬ OpenFileDialog1.ShowDialog() OpenFileDialog1 End Sub

‫هذا األمر يُظهر النافذة التالية‬

Filter

‫كيف نعرف هل قام ال ُمستخدم باختيار ملف مناسب أم ال؟‬ ‫ في المعالج سوف نظهر المسار الكامل‬.OpenFileDialog ‫ التابع للـ‬FileOK ‫من خالل الحدث‬ ‫ الحظ أن هذا المسار سيكون ُمخزنًا في الخاصية‬.‫للملف الذي اختاره ال ُمستخدم بمساعدة النافذة‬ OpenFileDialog1.FileName ‫ التابعة لألداة أي‬FileName Private Sub OpenFileDialog1_FileOk(sender As System.Object, e As System.ComponentModel.CancelEventArgs) Handles OpenFileDialog1.FileOk TextBoxFileName.Text = OpenFileDialog1.FileName.ToString End Sub

247


Open File ‫ للزر‬Click ‫برمجة معالج الحدث‬ ‫ الحظ أنه علينا‬.RichTextBoxContent ‫يقوم هذا ال ُمعالج بفتح الملف واظهار محتواه في األداة‬ ‫ في بداية ملف البرمجة‬Imports System.IO ‫اضافة فضاء األسماء‬

Public Function Exists(ByVal Path As String) As Boolean .‫( لملف ما يشمل اسم الملف مع الملحق‬Full Path) ‫تتلقى كبارامتر المسار الكامل‬

‫ادعاء الدخول‬

‫ خالف ذلك تعيد العملية‬.‫ إذا وجدت أن الملف حقًا موجود في المكان ال ُممرَّر كبارامتر‬true ‫تعيد‬

‫ادعاء الخروج‬

:‫ العملية موجودة ضمن الفئة‬.false System.IO.File

Private Sub ButtonOpenFile_Click(sender As System.Object, e As System.EventArgs) Handles ButtonOpenFile.Click Try

‫ ثم نتأكد من أن الملف حقًا‬.‫أوال نحذف أي فراغ موجود في بداية أو في نهاية المسار‬ .‫ التي تتلقى المسار الكامل للملف‬File.Exists ‫موجود بمساعدة العملية‬

TextBoxFileName.Text = TextBoxFileName.Text.Trim() If TextBoxFileName.Text = "" Or Not File.Exists(TextBoxFileName.Text) Then MessageBox.Show("Error: No file selected!") Return End If .‫ للملف الذي اختاره ال ُمستخدم ويتم فتحه للقراءة والكتابة‬FileStream ‫هنا نقوم بانشاء كائن‬ Dim fs As FileStream = New FileStream(TextBoxFileName.Text, FileMode.Open, FileAccess.ReadWrite) Dim sr As New StreamReader(fs) RichTextBoxContent.Text = sr.ReadToEnd() sr.Close() fs.Close()

‫في النهاية نُغلق الـكائنين‬

Catch ex As Exception MessageBox.Show(ex.Message) End Try End Sub

248

‫ يُمكننا‬StreamReader ‫ثم نقوم بانشاء كائن‬ ‫من قراءة محتوى الملف بالكامل بمساعدة‬ ReadToEnd ‫العملية‬


‫بعد ذلك سيظهر محتوى الملف كالتالي‬

‫ مثال لسنا بحاجة الى‬.‫ ونحن نناقش هنا أبسطها‬.‫طبعًا هنالك عدة امكانيات لفتح الملفات والقراءة منها‬ ‫ على النحو‬StreamReader ‫ وانما يكفي استعمال كائن من نوع‬FileStream ‫انشاء كائن من الفئة‬ ‫التالي‬ Private Sub ButtonOpenFile_Click(sender As System.Object, e As System.EventArgs) Handles ButtonOpenFile.Click Try TextBoxFileName.Text = TextBoxFileName.Text.Trim() If TextBoxFileName.Text = "" Or Not File.Exists(TextBoxFileName.Text) Then MessageBox.Show("Error: No file selected!") Return End If StreamReader ‫ثم نقوم بانشاء كائن‬ Dim sr As New StreamReader(TextBoxFileName.Text) ‫يُمكننا من قراءة محتوى الملف بالكامل‬ RichTextBoxContent.Text = sr.ReadToEnd() ReadToEnd ‫بمساعدة العملية‬ sr.Close()

Stream ‫في النهاية نُغلق الـ‬

Catch ex As Exception MessageBox.Show(ex.Message) End Try End Sub

249


‫ عمليات بنائية وبالتالي امكانيات ُمختلفة للتعامل مع‬10 ‫ لديها أكثر من‬StreamReader ‫الفئة‬ .‫الملفات‬ Save ‫ للزر‬Click ‫برمجة معالج الحدث‬ .‫ في الملف ال ُمختار‬RichTextBoxContent ‫يقوم هذا ال ُمعالج بحفظ محتوى األداة‬ Private Sub ButtonSaveFile_Click(sender As System.Object, e As System.EventArgs) Handles ButtonSaveFile.Click Try TextBoxFileName.Text = TextBoxFileName.Text.Trim() If TextBoxFileName.Text = "" Or Not File.Exists(TextBoxFileName.Text) Then MessageBox.Show("Error: No file selected!") Return End If RichTextBoxContent.Text = RichTextBoxContent.Text.Trim() If RichTextBoxContent.Text = "" Then MessageBox.Show("Empty Text!") Return End If ‫ للملف الذي اختاره ال ُمستخدم ويتم فتحه للكتابة‬FileStream ‫هنا نقوم بانشاء كائن‬ Truncate ‫وتفريغ محتواه األصلي‬ Dim fs As FileStream = New FileStream(TextBoxFileName.Text, FileMode.Truncate, FileAccess.Write) Dim sw As New StreamWriter(fs) sw.WriteLine(RichTextBoxContent.Text) ' Apply the update to the file sw.Flush() ' Close the stream writer sw.Close()

‫ننشئ كائنًا من نوع‬ ‫ ثم‬StreamWriter ‫نستدعي بمساعدته العملية‬ ‫ ونُمرر لها‬WriteLine ‫محتوى األداة‬ RichTextBoxContent sw.Flush() ‫االستدعاء‬ ‫يقوم بالحفظ الحقيقي لما‬ ‫كتبته العملية‬ sw.WriteLine()

' Close the file stream object fs.Close()

Catch ex As Exception MessageBox.Show(ex.Message) End Try End Sub

250


Save As… ‫ للزر‬Click ‫برمجة معالج الحدث‬ ‫ اختيار المجلد‬.‫ في الملف ال ُمختار‬RichTextBoxContent ‫يقوم هذا ال ُمعالج بحفظ محتوى األداة‬ ‫ وما علينا اال سحبها‬Toolbox ‫ ال ُمتوفرة في الـ‬SaveFileDialog ‫واسم الملف سيتم بمساعدة األداة‬ .‫ورميها على النموذج‬ ‫البرمجة‬ Private Sub ButtonSaveAs_Click(sender As System.Object, e As System.EventArgs) Handles ButtonSaveAs.Click Dim Res As DialogResult Res = SaveFileDialog1.ShowDialog() If Res = Windows.Forms.DialogResult.OK Then MessageBox.Show("Saved Successfully") End If End Sub Private Sub SaveFileDialog1_FileOk(sender As System.Object, e As System.ComponentModel.CancelEventArgs) Handles SaveFileDialog1.FileOk Try TextBoxFileName.Text = SaveFileDialog1.FileName TextBoxFileName.Text = TextBoxFileName.Text.Trim() RichTextBoxContent.Text = RichTextBoxContent.Text.Trim() If RichTextBoxContent.Text = "" Then MessageBox.Show("Empty Text!") Return End If Dim sw As New StreamWriter(TextBoxFileName.Text) sw.WriteLine(RichTextBoxContent.Text) sw.Close() Me.DialogResult = DialogResult.OK Catch ex As Exception MessageBox.Show(ex.Message) End Try End Sub

251


‫األداة ‪RichTextBox‬‬ ‫حتى اآلن استعملنا هذه األداة وكأنها ‪ .TextBox‬الحقيقة أن هذه األداة لها قدرات عالية جدا لتحرير‬ ‫وتنسيق النصوص‪ .‬من هنا جاء اسمها بأنها غنية (أي ‪ .)Rich‬في المثال التالي سنتعرف على بعض‬ ‫امكانيات التحرير والتنسيق التي تُوفرها هذه األداة‪.‬‬ ‫التطبيق التالي يحتوي على قائمة رئيسية واألداة ‪.RichTextBox‬‬

‫العنصر ‪ EditUndo‬يتراجع عن تنفيذ العملية األخيرة‬ ‫العنصر ‪ EditRedo‬يتراجع عن التراجع األخير‬ ‫العنصر ‪ EditCopy‬ينسخ النص ال ُمختار في األداة‬ ‫العنصر ‪ EditPaste‬يلصق النص المنسوخ في األداة في المكان الذي تتواجد فيه عالمة الكتابة‬ ‫العنصر ‪ EditCut‬يقص النص ال ُمختار في األداة‬ ‫العنصر ‪ EditSelect All‬يختار كل محتوى األداة‬ ‫العنصر ‪ FormatSelected ForeColor‬يُظهر نافذة اختيار األلوان ثم يُلون النص ال ُمختار‬ ‫في األداة باللون الذي اختاره ال ُمستخدم‬ ‫الستخدام نافذة اختيار األلوان علينا سحب األداة من الـ ‪ Toolbox‬ورميها على النموذج‪.‬‬ ‫‪252‬‬


‫برمجة العناصر‬ Public Class FormMain Private Sub UndoToolStripMenuItem_Click(sender As System.Object, e As System.EventArgs) Handles UndoToolStripMenuItem.Click RichTextBox1.Undo() End Sub Private Sub RedoToolStripMenuItem_Click(sender As System.Object, e As System.EventArgs) Handles RedoToolStripMenuItem.Click RichTextBox1.Redo() End Sub Private Sub CopyToolStripMenuItem_Click(sender As System.Object, e As System.EventArgs) Handles CopyToolStripMenuItem.Click RichTextBox1.Copy() End Sub Private Sub PasteToolStripMenuItem_Click(sender As System.Object, e As System.EventArgs) Handles PasteToolStripMenuItem.Click RichTextBox1.Paste() End Sub Private Sub CutToolStripMenuItem_Click(sender As System.Object, e As System.EventArgs) Handles CutToolStripMenuItem.Click RichTextBox1.Cut() End Sub Private Sub SelectAllToolStripMenuItem_Click(sender As System.Object, e As System.EventArgs) Handles SelectAllToolStripMenuItem.Click RichTextBox1.SelectAll() End Sub Private Sub CloseToolStripMenuItem_Click(sender As System.Object, e As System.EventArgs) Handles CloseToolStripMenuItem.Click Me.Close() End Sub Private Sub SelectedForColorToolStripMenuItem_Click(sender As System.Object, e As System.EventArgs) Handles SelectedForColorToolStripMenuItem.Click ColorDialog1.ShowDialog() RichTextBox1.SelectionColor = ColorDialog1.Color End Sub End Class

253


‫تمارين‬ ‫تمرين رقم ‪1‬‬ ‫أضف الى التطبيق األخير عنصرًا جديدًا في القائمة الرئيسية ‪ FileSave As‬يُظهر‬ ‫‪ SaveFileDialog‬لحفظ محتوى الـ ‪ RichTextBox‬في ملف خاص‪.‬‬

‫تمرين رقم ‪2‬‬ ‫صمم تطبيقًا يفتح ملفات ‪( CSV‬أي ‪ُ .)Comma Seperated Values‬ملحق هذه الملفات هو ‪.csv‬‬ ‫األسطر في هذه الملفات تحتوي على نصوص مكونة من أجزاء يفصل بين هذه األجزاء الرمز ;‪.‬‬ ‫السطر األول عبارة عن عناوين لألجزاء‪.‬‬ ‫مثال‬ ‫‪StudentName;Year;Semester;Subject;Mark‬‬ ‫‪Sami Abu Sami;2014-2105;Sem A;VB.NET;95‬‬ ‫‪Ali Abu Ali;2014-2105;Sem A;VB.NET;93‬‬ ‫…‬ ‫على التطبيق أن يعرض هذا المحتوى بواسطة ‪ DataGridView‬قابل للتحرير بشكل كامل‪ .‬بامكان‬ ‫ال ُمستخدم حفظ التغييرات التي أجراها على محتوى الملف من خالل الضغط على زر خاص للحفظ‪.‬‬

‫‪254‬‬


Turn static files into dynamic content formats.

Create a flipbook
Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.