Building-applications-with-pygtk-and-sqlite

  • May 2020
  • PDF

This document was uploaded by user and they confirmed that they have the permission to share it. If you are author or own the copyright of this book, please report to us by using this DMCA report form. Report DMCA


Overview

Download & View Building-applications-with-pygtk-and-sqlite as PDF for free.

More details

  • Words: 14,980
  • Pages: 103
‫بناء التطبيقات مع ‪ Python‬بالعتماد على‬ ‫‪ GTK‬و‬ ‫تأليف ‪ :‬محمد قاسم حسين‬

‫‪SQLite‬‬

‫الفهرس‬ ‫إهداء ‪ ....................................................................................................................................................‬ص ‪4‬‬

‫مقدمه ‪ ...................................................................................................................................................‬ص ‪5‬‬

‫‪ . 1‬الفصل الول ‪ :‬مدخل إلى ‪ .............................................. GTK‬ص ‪7‬‬

‫‪ .1.1‬مقدمه ‪ .........................................................................................................................................‬ص ‪8‬‬

‫‪ .1.1.1‬ما هي ‪GTK‬؟ ‪ .................................................................................................................................‬ص ‪8‬‬

‫‪ .1.1.2‬نظره سريعه على ماضي ‪ ......................................................................................................... GTK‬ص ‪8‬‬ ‫‪ .1.1.3‬بعض الصور لتطبيقات تعمل على ‪ ......................................................................................... GTK‬ص ‪9‬‬

‫‪ .1.2‬قبل البدأ ‪ .................................................................................................................................‬ص ‪11‬‬ ‫‪ .1.3‬المثال الول ‪ :‬مرحباً بالعالم ‪ ..................................................................................................‬ص ‪12‬‬ ‫‪.1.4‬الدوات ‪ .............................................................................................................. Widget‬ص ‪13‬‬

‫‪.1.4.1‬ما هي الدوات ‪ ............................................................................................................ Widget‬ص ‪13‬‬

‫‪.1.4.2‬الدوات مع الـ ‪ ............................................................................................................. PyGTK‬ص ‪13‬‬

‫‪.1.4.2.1‬البدايه ‪.......................................................................................................................................................‬ص ‪13‬‬

‫‪ .1.4.2.2‬الصناديق ‪ ................................................................................................................................................‬ص ‪17‬‬ ‫‪ .1.4.2.2.1‬مقدمه ‪ ................................................................................................................................................................‬ص ‪17‬‬ ‫‪ HBox.1.4.2.2.2‬و ‪........................................................................................................................................... Vbox‬ص ‪17‬‬ ‫‪ .1.4.2.2.3‬إستخدام الصناديق عملياً ‪ .................................................................................................................................‬ص ‪18‬‬

‫‪2‬‬

‫‪ .1.5‬الشارات و الدوال ‪ ...................................................................................... Callback‬ص ‪21‬‬

‫‪ .1.5.1‬مقدمه ‪ .............................................................................................................................................‬ص ‪21‬‬ ‫‪ .1.5.2‬الشارات مع ‪ .............................................................................................................. PyGTK‬ص ‪21‬‬

‫‪ .1.6‬المثال الثاني ‪ :‬برنامج تحويل درجة الحراره ‪ ..........................................................................‬ص ‪26‬‬ ‫‪ .1.7‬المثال الثالث ‪ :‬آله حاسبه ‪ ....................................................................................................‬ص ‪32‬‬ ‫‪ .1.8‬مدخل إلى ‪ .......................................................................................................... Glade‬ص ‪39‬‬ ‫‪ .1.8.1‬مقدمه ‪ ....................................................................................................................................‬ص ‪39‬‬

‫‪ .1.8.2‬التصميم مع ‪ ................................................................................................................... Glade‬ص ‪40‬‬ ‫‪ .1.8.3‬استخدام ما تم تصميمه مع ‪ Glade‬في النص البرمجي ‪ ..............................................................‬ص ‪44‬‬

‫‪ .1.8.4‬استخدام الشارات مع ما تم تصميمه مع ‪ ...................................................................... Glade‬ص ‪47‬‬ ‫‪ .1.8.5‬نقل برنامج تحويل درجة الحراره إلى ‪ ............................................................................. Glade‬ص ‪52‬‬ ‫‪ .1.8.6‬نقل الله الحاسبه إلى ‪ ................................................................................................... Glade‬ص ‪57‬‬

‫‪ . 2‬الفصل الثاني ‪ :‬مدخل إلى ‪.................................... SQLite‬ص ‪63‬‬

‫‪ .2.1‬مقدمه ‪.....................................................................................................................................‬ص ‪64‬‬ ‫‪ .2.2‬الدوال الساسيه ‪ ..................................................................................................................‬ص ‪65‬‬ ‫‪ .2.3‬المثال الول ‪ :‬برنامج لتخزين السماء و عرضها ‪ .....................................................................‬ص ‪67‬‬

‫‪ . 3‬الفصل الثالث ‪:‬إنشاء مشروع ‪ ...............................................‬ص ‪81‬‬

‫‪ .3.1‬برنامج إدارة بيانات موظفين في شركه ما ‪ ................................................................................‬ص ‪82‬‬

‫ملحق أ ‪ :‬وصلت ‪ .........................................................................................................................‬ص ‪101‬‬

‫قائمة المصادر ‪ ...............................................................................................................................‬ص ‪103‬‬ ‫‪3‬‬

‫إهداء‬ ‫إلى والدّي‪.‬‬ ‫إلى اخواني حسين شبلي‪ ،‬عبدال العصمي و مازن مليباري و إلى من علّمني الكثير عبدال المهيري‪.‬‬

‫‪4‬‬

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

‫منذ فتره و انا افكر بكتاب ينتفع به من يريد التعلم‪ ،‬و بدأت اقلّب بالمواضيع حتى وصلت إلى لغة البايثون‪ ،‬دققت‬ ‫النظر في المجتمع العربي على النترنت فوجدت أنّ هناكَ كتابان باللغةِ العربية يتحدثان عن هذه اللغه للمبتدئين‪،‬‬

‫فقررت أنْ ل اكتب عن نفس الموضوع الذي سبقوني به‪ ،‬لنه إن حصل ذلك لن يحققَ الكتابُ هدفه‪ ،‬و في‬

‫الحقيقه مللنا من كثرة الكتب التي تتحدث عن الساسيات فقط خصوصاً بالبرمجه‪ ،‬فما اكثر الكتب التي تشرح‬

‫اساسيات العديد من لغات البرمجه متغاضية عن المواضيع المتقدمه فيها‪ ،‬لذا و بعد كل هذا قررت التحدث عن‬ ‫لغة البايثون و لكن في مواضيع متقدمه فيها‪ ،‬فأخترت الكتابه عن ‪ GTK‬و ‪ SQLite‬مع البايثون‪ ،‬حتى يتمكن‬

‫من ينتهي من قراءه هذا الكتاب بناء تطبيقات متكامله ذات واجهات رسوميه بالعتماد على قواعد البيانات من اجل‬ ‫ادارة البيانات‪.‬‬

‫بالنسبه للمصطلحات‪ ،‬فحاولت ترجمتها بقدر المكان مع البقاء على المعنى الصحيح و ان كان هذا المعنى ينافي‬ ‫معنى الكلمه حرفياً‪ ،‬و ارجو أنْ ل يلومني البعض على ترجمتي لهذه المصطلحات كما حدث لي من قبل ‪،(-:‬‬ ‫كما إنّي وضحتُ مع كل مصطلح قمتُ بترجمته الكلمه الصليه باللغه النجليزيه‪ ،‬حتى اسهّل على من اراد‬ ‫التبحّر و البحث اكثر و اقرّب الصوره لمن لم يتقبل ترجمتي للمصطلح‪.‬‬

‫هناك نقطه هامه جداً ل بد من ذكرها‪ ،‬و هي أنّ هذا الكتاب يتطلب معرفة سابقه في لغة بايثون‪ ،‬لن يعلمَك‬

‫الكتاب ما هي البرمجه او ما هي بايثون و كيفية التعامل معها‪ ،‬من الفضل مراجعة الكتب المتخصصه للمبتدئين في‬ ‫هذا المجال‪ ،‬كذلك يفترض هذا الكتاب أنّ لديك إلمام في لغةِ ‪ SQL‬من اجل التعامل مع قواعد البيانات‪.‬‬

‫هذا الكتاب مجاني حُر يقع تحت رخصة ‪ ،GNU FDL‬و تم استخدام البرامج الحرّه من اجل انجازه ‪-‬‬ ‫‪5‬‬

‫محرر ‪ LeafPad‬لتحريره‪ ،‬برنامج ‪ WikkaWiki‬لتخزينه و التعامل معه اثناء كتابته‪ ،‬برنامج‬

‫‪ OpenOffice Writer‬من اجل تنسيقه و وضعه في صورته النهائيه من اجل نشره‪ ،‬الخطوط المُقدمه من‬

‫مشروع ‪ Arabeyes‬و ‪ Proggy Fonts‬لتنسيقه‪ ،‬و كلها تعمل تحت مظلّة نظام التشغيل‬

‫‪ GNU/Linux‬توزيعة ‪ ،OpenSuSE‬اسمحولي برفع القبعه لمجتمع المصادر الحرّه ‪.(-:‬‬

‫لي سؤال حول الكتاب‪ ،‬او حول احد مواضيع الكتاب و شيفراته‪ ،‬او تصحيح مهما كان نوعه يمكنك التوجه إلى‬ ‫مدونتي على العنوان التالي ‪ http://www.maastaar.com‬ثم اذهب إلى صفحة "راسلني" و‬

‫اكتب استفسارك او اقتراحك او تصحيحك و سوف احاول الرد بأسرع وقت ممكن ان شاء ال‪ ،‬يسعدني أنْ‬

‫تراسلوني بأسئله حول مواضيع الكتاب لنها حتماً ستزيد من خبرتي و ستساعدني في الطبعه الثانيه من هذا‬ ‫الكتاب الذي افكّر بوضع ملحق لسئله القُراء و اجوبتها ان شاء ال ‪.(-:‬‬

‫جميع الشيفرات البرمجيه في هذا الكتاب مُجرّبه على الصدار ‪ 2.6‬من بايثون‪ ،‬و جميعها تخضع للرخصه الحرّه‬ ‫‪.GNU LGPL‬‬

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

‫‪/http://wiki.arabeyes.org :‬خطوط‬ ‫‪/http://www.proggyfonts.com‬‬

‫هذا و نرجوا من ال سبحانه و تعالى ان يتقبل منّا هذا العمل البسيط و الحمدل رب العالمين‪.‬‬

‫‪6‬‬

‫الفصل الول‬ ‫مدخل إلى ‪GTK‬‬

‫‪7‬‬

‫‪ .1.1‬مقدمه‬ ‫‪ .1.1.1‬ما هي ‪GTK‬؟‬ ‫‪ GTK‬عباره عن مكتبه برمجيه لتصميم واجهات مستخدم رسوميه ‪ ،GUI‬فبدلً من بناء برامجنا على شكل‬

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

‫واجهات البرامج ووضع الزرار و مربعات النص و غيرها من المور مع ما يناسب برنامجنا‪ ،‬كلمة ‪GTK‬‬

‫اختصار للجمله ‪ ،GIMP Toolkit‬تقع هذه المكتبة تحت رخصة ‪ GNU LGPL‬و تتميز بكفاءتها مع‬

‫اللغه العربيه‪ ،‬تتوفر مكتبة ‪ GTK‬مع مجموعه كبيره من لغات البرمجه مثل سي و سي‪ + +‬و جافا و ‪ PHP‬و‬

‫بالطبع بايثون و التي سوف نتعامل مع الـ ‪ GTK‬من خللها ‪ ،(-:‬تُسمى المكتبه التي تدعم ‪ GTK‬في البايثون بـ‬ ‫‪ ،PyGTK‬الجدير بالذكر ان مكتبة ‪ GTK‬هي المكتبه الساسيه التي يستخدمها سطح مكتب ‪GNOME‬‬

‫لبناء تطبيقاته وواجهته‪ ،‬بينما يستخدم سطح المكتب ‪ KDE‬مكتبة ‪ Qt‬لبناء الواجهات الرسوميه‪ ،‬و من ابرز‬

‫البرامج التي تم تصميمها بإستخدام الـ ‪ GTK‬هو برنامج ‪ GIMP‬برنامج الرسم المشهور‪ ،‬و ‪AbiWord‬‬

‫معالج النصوص و مجموعه ل يستهان بها من البرامج )راجع الملحق أ للحصول على وصلت لمواقع بهذا‬ ‫الخصوص(‪ ،‬ول بد من الملحظه ان ‪ GTK‬تعمل على نظام التشغيل غنو\لينكس و آبل ماكنتوش و‬

‫مايكروسوفت وندوز‪ ،‬هذا يعني امكانية كتابة برنامج واحد ليعمل على النظمه الثلث‪.‬‬

‫‪ .1.1.2‬نظره سريعه على ماضي ‪GTK‬‬ ‫بدأت ‪ GTK‬اساساً في عام ‪ 1996‬من اجل برنامج الرسم ‪ GIMP‬على يد ‪Spencer Kimball‬‬ ‫و ‪ Peter Mattis‬و ‪ Josh MacDonald‬عندما قرروا الستغناء عن ‪) Motif‬وهي مكتبة اخرى‬

‫لبناء واجهات مستخدم رسوميه( و هذا هو سبب تسمية ‪ GTK‬بـ ‪ ،GIMP Toolkit‬تعتبر مكتبة ‪GTK‬‬

‫احد اجزاء مشروع ‪ GNU‬و تُستخدم الن بشكل اساسي في نُظم يونكس )مثل غنو\لينكس و ‪FreeBSD‬‬ ‫‪8‬‬

‫و غيرها‪ ،‬و كما ذكرنا مسبقاً انه يعمل على نظم التشغيل الخرى مثل مايكروسوفت وندوز(‪.‬‬

‫‪ .1.1.3‬بعض الصور لتطبيقات تعمل على ‪GTK‬‬

‫‪9‬‬

10

‫‪ .1.2‬قبل البدأ‬ ‫اولً ‪ :‬قبل ان نبدأ بأي شئ ل بد من تثبيت مكتبة ‪ PyGTK‬على حاسوبنا‪ ،‬يمكنك الحصول على هذه المكتبه‬ ‫من موقعها الرسمي ‪.http://www.pygtk.org‬‬

‫ثانياً ‪ :‬في كل ملف ‪ Python‬نود استخدام ‪ PyGTK‬فيه‪ ،‬ل بد من كتابة الوامر التاليه ‪:‬‬ ‫‪import pygtk‬‬ ‫)'‪pygtk.require('2.0‬‬ ‫‪import gtk‬‬ ‫و كما ذكرْت في مقدمة الكتاب‪ ،‬إنّ من يقرأ هذا الكتاب ل بد أنْ يكون مُلماً بلغة ‪ ،Python‬و هذا يعني إنّ‬ ‫الشيفره المذكوره في العلى مفهومه و ما هي إل استدعاء لمكتبين‪ ،‬أما السطر الثاني فهو يُلزم مكتبة ‪pygtk‬‬ ‫على اختيار الصدار ‪ 2.0‬فما فوق‪.‬‬

‫‪11‬‬

‫ مرحباً بالعالم‬: ‫ المثال الول‬.1.3 ‫حتى نبدأ بالدراسه العمليه للمفاهيم الساسيه و التي سوف تساعدنا على بناء التطبيقات يجب أنْ نبدأ بمثال‬

‫ كالعاده سوف نبدأ‬،‫بسيط يستخدم هذه المفاهيم الساسيه ثم نَلجُ في شرح المفاهيم إستناداً إلى هذا المثال‬ .!Hello World ‫ببرنامج "مرحباً بالعالم!" او كما نعرفه بإسم‬

# -*- coding: utf-8 -*import pygtk; pygtk.require('2.0'); import gtk; def delete_event(widget,data): False; def destroy(widget,data=None): gtk.main_quit(); window = gtk.Window(gtk.WINDOW_TOPLEVEL); window.set_title("‫ً بالعالم‬ ‫;)"مرحبا‬ window.connect('delete_event',delete_event); window.connect('destroy',destroy); hello_world_button = gtk.Button("‫ً بالعالم‬ ‫;)"مرحبا‬ hello_world_button.show(); window.add(hello_world_button); window.show(); gtk.main(); .‫ إنتقل للجزء التالي من الكتاب و سوف يتم شرحها‬،(-: ً‫ل تدقق في الشيفره كثيرا‬

12

‫‪.1.4‬الدوات ‪Widget‬‬ ‫‪.1.4.1‬ما هي الدوات ‪Widget‬‬ ‫الدوات هي افضل ترجمه وجدتها من اجل مصطلح ‪ ،Widget‬تُعتبر الدوات الجزء الساسي من اي مكتبه‬

‫لبناء واجهات المستخدم الرسوميه‪ ،‬و بالطبع من ضمن هذه المكتبات مكتبة ‪ ،GTK‬الدوات هي كُل ما يُعرض‬ ‫بواجهة البرنامج‪ ،‬مثلً النافذه التي تحتوي على مربع ‪ X‬للغلق و مربع _ لنزال البرنامج إلى قائمة البرامج‬

‫المفتوحه تعتبر من الدوات‪ ،‬كذلك مربع النص الذي نقوم بتعبئة البيانات في داخله يعتبر من الدوات‪ ،‬و كل‬

‫شئ موجود داخل نافذة البرنامج يعتبر من الدوات مربع النص‪ ،‬الزرار‪ ،‬القوائم المنسدله‪ ،‬قائمة اختيار‬

‫الملفات و غيرها‪ ،‬في مثالنا السابق كان لدينا اداتين‪ ،‬النافذه الرئيسيه‪ ،‬و الزر المكتوب عليه "مرحباً بالعالم"‬

‫‪.1.4.2‬الدوات مع الـ ‪PyGTK‬‬ ‫‪.1.4.2.1‬البدايه‬ ‫في ‪ PyGTK‬لكل اداة من الدوات التي يقدمها صنف )‪ (Class‬خاص بها و من خلل إنشاء كائن )‬ ‫‪ (Object‬من هذا الصنف فإننا نقوم بإنشاء الداة و من خلل الكائن نتحكم في الداة التي قمنا بإنشاءها‪،‬‬

‫حسب مثالنا السابق قمنا بإنشاء نافذه و وضعنا داخل هذه النافذه زر‪ ،‬لنأخذ اولً السطر الذي قمنا بإنشاء النافذه‬ ‫من خلله و هو التالي ‪:‬‬

‫;)‪window = gtk.Window(gtk.WINDOW_TOPLEVEL‬‬ ‫حسناً كما تلحظ في الشيفره السابقه‪ ،‬قمنا بوضع متغير اسمه ‪ ،window‬و استخدمنا الصنف‬

‫‪ gtk.Window‬من اجل إنشاء النافذه الرئيسيه و كلفنا المتغير ‪ window‬بها و بالتالي أصبح كائناً )‬ ‫‪13‬‬

‫‪ (Object‬يمكننا من خلله التحكم بالنافذه )ل بد من الملحظه ان تكون قد درست الـ ‪ OOP‬مع الـ‬

‫‪ Python‬حتى تتمكن من استيعاب ما يُشرح(‪ ،‬و كما ذكرنا مسبقاً إنّ كل اداة في ‪ GTK‬يكون لها صنف‬

‫خاص بها‪ ،‬هذا يعني أنّ لدينا العديد من الصناف غير الصنف ‪ ،gtk.Window‬مثلً لدينا الصنف‬

‫‪ gtk.Button‬للزره و ‪ gtk.Entry‬لمربعات النصوص و عشرات الصناف غيرها التي تخدم مجموعه‬

‫كبيره من المجالت‪ ،‬بالطبع لن نتمكن من ذكر جميع هذه الصناف في هذا الكتاب و لكننا سنذكر الساسيه‬

‫منها حتى نتعلم طريقة الكتابه‪ ،‬و بعدها يمكنك التبحر عن طريق قراءة الدليل الرسمي الخاص بـ ‪ PyGTK‬و‬ ‫الذي يشرح جميع الصناف المتوفره‪.‬‬

‫على كل حال نعود لمثالنا‪ ،‬كما أسلفنا إنّ المتغير ‪ window‬أصبحَ كائناً )‪ ،(Object‬يمكننا من خلل‬

‫هذا الكائن التحكم بالنافذه التي أنشأناها من خلل مجموعه من الدوال التي يوفرها لنا الصنف‬

‫‪ ،gtk.Window‬بالطبع لكل اداة مجموعه من الدوال التي تخصها و التي تعطيك التحكم الكامل في الداة‬

‫التي تقوم بإنشاءها‪ ،‬ننتقل الن إلى السطر التالي في مثالنا و هو ‪:‬‬

‫ً بالعالم"(‪window.set_title‬‬ ‫;)"مرحبا‬ ‫الداله ‪ set_title‬هي أحد الدوال التي يُقدمها الصنف ‪ gtk.Window‬و التي تساعدك على التحكم في‬

‫الداة التي قمت بإنشاءها‪ ،‬تقوم هذه الداله بتغيير عنوان النافذه إلى "مرحباً بالعالم"‪ ،‬بالطبع هناك عشرات الدوال‬ ‫التي يقدمها الصنف ‪ gtk.Window‬يمكنك القراءه عنها في دليل ‪ PyGTK‬الرسمي‪ ،‬لنأخذ مثال سريع‬

‫على احد هذه الدوال‪ ،‬الداله ‪ resize‬تقوم بتغيير حجم النافذه‪ ،‬قم بإضافة السطر التالي اسفل السطر‬ ‫المدروس في العلى ‪:‬‬

‫;)‪window.resize(200,200‬‬ ‫لحظ أنّ حجم النافذه تغير عن المره السابقه و إنّهه أصبح اكبر‪ ،‬البارامتر الول لهذه الداله هو عرض النافذه‪ ،‬و‬ ‫البارامتر الثاني هو الرتفاع‪.‬‬

‫الن تجاهل السطرين التاليين لنّنا سندرسهما في موضع آخر و إذهب إلى السطر الذي يليهما‪ ،‬وهو‬ ‫‪14‬‬

‫ً بالعالم"(‪hello_world_button = gtk.Button‬‬ ‫;)"مرحبا‬ ‫وفقاً لما اسلفنا من شرح لبد و انك عرفت وظيفة هذا السطر‪ ،‬يقوم هذا السطر بإنشاء زر جديد و يجعل المتغير‬

‫‪ hello_world_button‬كائن لهذا الزر و كما تلحظ أنّ البارامتر هو النص الذي سيُطبع على الزر‪ ،‬و‬

‫كما هو الحال مع النافذه التي انشأناها هناك مجموعه من الدوال التي يقدمها الصنف ‪ gtk.Button‬و التي‬ ‫تعطينا التحكم في الزر الذي أنشأناه‪ ،‬لنأخذ مثلً الداله ‪ set_label‬و التي تقوم بتغيير النص الموجود على‬ ‫الزر‪ ،‬مثال ‪:‬‬

‫;)"تم تغيير النص"(‪hello_world_button.set_label‬‬ ‫يقوم هذا السطر بتغيير النص الموجود على الزر من "مرحباً بالعالم" إلى "تم تغيير النص"‬ ‫ننتقل إلى السطر التالي وهو ‪:‬‬

‫;)(‪hello_world_button.show‬‬

‫بعدما قمنا "بإنشاء" الزر‪ ،‬و قمنا بالتعديل عليه بما يناسب برنامجنا )مثل اختيار النص الذي يظهر على الزر و غيره‬ ‫من هذه المور( ل بد من "عرض" الزر و هذا يتم بإستخدام الداله ‪ ،show‬نستخدم الداله ‪ show‬مع‬ ‫جميع الدوات تقريباً حتى يتم عرض الداة بعد إنشاءها‪.‬‬ ‫ننتقل الن إلى السطر التالي ‪:‬‬ ‫;)‪window.add(hello_world_button‬‬ ‫بعدما اظهرنا الزر في السطر السابق ل بد من اضافته إلى النافذه الرئيسيه‪ ،‬و هذا ما نقوم به في السطر الذي نقوم‬

‫بشرحه الن حيث نستخدم الداله ‪ add‬لهذا الغرض‪ ،‬في الحقيقه ل يمكننا استخدام هذه الداله إل مره واحده‬

‫فقط في برنامجنا‪ ،‬اي اننا ل نستطيع إل اضافة اداة واحد فقط إلى النافذه الرئيسيه‪ ،‬قد تتسائل في هذه الحاله كيف‬

‫يمكننا وضع اكثر من اداة في نافذتنا الرئيسيه؟ لنفرض إننا نريد تصميم برنامج لتحويل القياسات‪ ،‬في هذه الحاله‬ ‫‪15‬‬

‫سوف نحتاج إلى مجموعه من العناصر‪ ،‬مثلً مربع نصوص‪ ،‬زر‪ ،‬سطر نصّي لطباعة النتائج‪ ،‬في هذه الحاله كيف‬ ‫يمكنني اضافة جميع هذه الدوات على نافذتي الرئيسيه و في الحقيقه ل يمكنني استدعاء دالة الضافه ‪ add‬إل‬ ‫مره واحده فقط‪ ،‬الجواب على هذا السؤال هو الداتين ‪ VBox‬و ‪ HBox‬او ما سوف نطلق عليهم اسم‬ ‫الصناديق‪ ،‬سوف نشرح كيفية استخدام الصناديق و فائدتها فيما بعد‪.‬‬ ‫السطر التالي ‪:‬‬ ‫;)(‪window.show‬‬ ‫كما ذكرنا سابقاً‪ ،‬الداله ‪ show‬تقوم بعرض الداة بعد إنشاءها و هذا فعلناه مع الزر الذي قمنا بإضافته‪ ،‬أنشأناه‬

‫اولً ثم عرضناه‪ ،‬و هذا الذي يجب ان يحصل مع اغلب الدوات‪ ،‬و كما نعلم ان النافذه الرئيسيه تعتبر من ضمن‬

‫الدوات و بالتالي لبد من عرضها بعد إنشاءها‪ ،‬و هذا ما يتم في السطر الذي ندرسه الن‪.‬‬ ‫ننتقل إلى السطر الخير وهو ‪:‬‬

‫;)(‪gtk.main‬‬ ‫و هذا السطر لبد من كتابته في جميع برامجنا في النهايه‪ ،‬لنه هو المسؤول عن عرض ما قمنا بتصميمه‪.‬‬

‫‪16‬‬

‫‪ .1.4.2.2‬الصناديق‬ ‫‪ .1.4.2.2.1‬مقدمه‬ ‫في اثناء شرحنا السابق لشيفرة "مرحباً بالعالم" ظهر لدينا إشكال‪ ،‬و هو عدم إمكانية استدعاء الداله ‪ add‬اكثر‬

‫من مره واحده‪ ،‬و كما نعلم هذه الداله تقوم بإضافة الدوات التي ننشؤها إلى النافذه الرئيسيه‪ ،‬و اذا عرفنا انه ل‬

‫يمكننا استدعاءها إل مره واحده هذا يعني عدم إمكانية إضافة اكثر من اداة واحد في برنامجنا‪ ،‬ذكرنا في ذاك‬ ‫الموضع إنّ الحلَ مع الصناديق‪ ،‬الصناديق ‪ HBox‬و ‪ VBox‬هي ادوات توفرها ‪ ،PyGTK‬تُعتبر‬

‫الصناديق من اهم الدوات التي سوف نستخدمها في جميع برامجنا التي تحتوي على أكثر من اداة‪ ،‬لِأُوضِّح‬

‫الفكرةَ أكثر ‪ :‬في ‪ PyGTK‬يجب أنْ تكون كل اداة في صندوق لوحده‪ ،‬مثلً لنفرض اننا نريدُ تصميم واجهه‬

‫تحتوي على مربع نص و زر واحد‪ ،‬افتراضياً في النافذه التي نُنشئها في ‪ PyGTK‬يمكننا إضافة اداة واحده فقط‬

‫هذا يعني اننا لن نتمكن من اضافة اداة اخرى‪ ،‬لحل هذه المشكله ل بد من اضافة صناديق جديده و وضع‬

‫الدوات فيها‪ ،‬هذا يعني اننا سوف ننشئ صندوقين اثنين نضع في واحد منهما مربع النص و نضع في الخر الزر‪.‬‬

‫‪ HBox.1.4.2.2.2‬و ‪VBox‬‬ ‫يوجد لدينا نوعين من الصناديق في ‪ ،PyGTK‬النوع الول هو ‪ HBox‬و هذا النوع يقوم بإنشاء الصناديق‬

‫بشكل افقي‪ ،‬اما النوع الثاني هو ‪ VBox‬و الذي يقوم بإنشاء الصناديق بشكل عمودي‪ ،‬حسناً الن اذا اردنا‬ ‫وضع الزر بجانب صندوق النص سوف نقوم بإستخدام ‪ ،HBox‬اما اذا اردنا وضع الزر في اسفل مربع‬ ‫النص )او العكس( سوف نستخدم ‪ ،VBox‬الجدير بالذكر انه يمكننا وضع صناديق داخل صناديق‪.‬‬

‫لنرى الن كيفية تعريف ‪: HBox‬‬

‫)‪gtk.HBox(homogeneous=False, spacing=0‬‬

‫اما تعريف ‪: VBox‬‬ ‫‪17‬‬

gtk.VBox(homogeneous=False, spacing=0) ‫ يعني اعطاء مساحات متساويه لما يقع داخل الصندوق اذا كانت‬homogeneous ‫البارامتر الول‬ .True

.‫ و هي المسافه بين ما يقع داخل الصندوق بالبيكسل‬spacing ‫البارامتر الثاني‬ ‫ حيث تقوم هذه الداله بوضع اداة معينه داخل‬،pack_start ‫ يوفران داله و هي‬HBox ‫ و‬VBox

.ً‫صندوق معين مُعرّف مسبقا‬

ً‫ إستخدام الصناديق عمليا‬.1.4.2.2.3 ‫ فعلً جوابك‬،‫ اذا اردنا الن اضافة زر آخر بجانب الزر القديم ما الذي يجب فعله‬،"‫نعود لمثالنا "مرحباً بالعالم‬ : ‫ الشيفره التاليه تحقق لنا ما أردنا‬،HBox ‫( سوف نستخدم‬-: ‫صحيح‬

# -*- coding: utf-8 -*import pygtk; pygtk.require('2.0'); import gtk; def delete_event(widget,data): False; def destroy(widget,data=None): gtk.main_quit(); window = gtk.Window(gtk.WINDOW_TOPLEVEL); window.set_title("‫ً بالعالم‬ ‫;)"مرحبا‬ window.connect('delete_event',delete_event); window.connect('destroy',destroy); box1 = gtk.HBox(False,0); # New line window.add(box1); # New line hello_world_button = gtk.Button("‫ً بالعالم‬ ‫;)"مرحبا‬ 18

‫‪box1.pack_start(hello_world_button,True,True,0); # New line‬‬ ‫;)(‪hello_world_button.show‬‬ ‫‪"); # New line‬الزر الثاني"(‪hello_world_button_2 = gtk.Button‬‬ ‫‪box1.pack_start(hello_world_button_2,True,True,0); # New line‬‬ ‫‪hello_world_button_2.show(); # New line‬‬ ‫‪box1.show(); # New line‬‬ ‫;)(‪window.show‬‬ ‫;)(‪gtk.main‬‬ ‫لحظ انني وضعت التعليق "‪ New line" #‬عند السطر الجديده التي قمت بإضافتها على مثالنا الول‪.‬‬ ‫لنبدأ بشرح السطر الجديده‪ ،‬اولً ‪:‬‬ ‫‪box1 = gtk.HBox(False,0); # New line‬‬ ‫‪window.add(box1); # New line‬‬ ‫في السطر الول أضفنا الصندوق الذي سنضع فيه الداتين‪ ،‬لحظ أنّ هذا الصندوق من النوع الفقي لننا نريد‬

‫وضع الزر الجديد بجانب الزر القديم‪ ،‬لو كنا نريد وضع الزر الجديد اسفل الزر القديم لستخدمنا صندوق من‬ ‫النوع ‪ ،VBox‬في السطر التالي قمنا بإضافة الصندوق الرئيسي إلى النافذه‪ ،‬لحظ اننا حذفنا هذا السطر من‬

‫اسفل الملف و اضفناه هنا‪.‬‬

‫ننتقل إلى الجزء الذي يليه من الشيفره ‪:‬‬ ‫ً بالعالم"(‪hello_world_button = gtk.Button‬‬ ‫;)"مرحبا‬ ‫‪box1.pack_start(hello_world_button,True,True,0); # New line‬‬ ‫;)(‪hello_world_button.show‬‬ ‫من خلل هذه السطر قمنا بإنشاء الزر و عرضه‪ ،‬هل تتذكر المثال السابق؟ هذه الشيفره من المثال السابق ‪،(-:‬‬

‫كل ما قمنا به هو إضافة السطر الجديد و هو السطر الثاني‪ ،‬من خلل هذا السطر أضافة الداة‬

‫‪ hello_world_button‬داخل الصندوق‪ ،‬سوف نستخدم الداله ‪ pack_start‬دائماً من اجل‬ ‫‪19‬‬

‫إضافة الدوات داخل الصناديق‪ ،‬و على اختلف نوع الصندوق سواء كان صندوق ‪ VBox‬او ‪ HBox‬فل‬ ‫يوجد فرق فالداله نفسها‪.‬‬

‫ننتقل إلى السطر التاليه ‪:‬‬ ‫‪"); # New line‬الزر الثاني"(‪hello_world_button_2 = gtk.Button‬‬ ‫‪box1.pack_start(hello_world_button_2,True,True,0); # New line‬‬ ‫‪hello_world_button_2.show(); # New line‬‬ ‫ل يوجد شئ جديد هنا لننا شرحنا معنى هذه السطر مسبقاً‪ ،‬هذه السطر تقوم بإضافة زر جديد بجانب الزر‬

‫القديم‪ ،‬السطر الول يقوم بإنشاء الزر‪ ،‬السطر الثاني يقوم بإضافة الزر إلى الصندوق‪ ،‬و السطر الخير يقوم بإظهار‬ ‫الزر‪.‬‬

‫ننتقل إلى آخر سطر جديد قمنا بإضافته ‪:‬‬ ‫‪box1.show(); # New line‬‬ ‫في هذا السطر أظهرنا الصندوق الذي وضعنا ادواتنا فيه‪ ،‬لحظ انه يمكننا إظهار الداة في اي مكان‪ ،‬مثلً ل يوجد‬

‫مشاكل لو قمنا بإظهار الصندوق بعد إنشاءه مباشره في مثالنا هذا‪ ،‬ببساطه يمكننا استدعاء الداله ‪ show‬و إظهار‬ ‫اداتنا في اي مكان‪ ،‬المهم ان ننشئ الداة اولً‪.‬‬

‫‪20‬‬

‫‪ .1.5‬الشارات و الدوال ‪Callback‬‬ ‫‪ .1.5.1‬مقدمه‬ ‫في بادئ المر درسنا مفهوم الدوات )‪ (Widget‬و كما تعلم إنّه مفهومٌ مهمٌ جداً‪ ،‬المفهوم الخر و الذي‬

‫يجب إستيعابه بشكلٍ جيّد هو "الشارات" )‪ ،(Signals‬تخيل معي ان برنامجنا يحتوي على زر مكتوب عليه‬

‫"اضغط هنا" عندما يضغطُ المستخدمُ على الزر لن يحدثَ اي شئ! لننا وضعنا الزر ضمن النافذه ل اكثر‪ ،‬اذا‬ ‫اردنا من الزر أنْ يقومَ بعملٍ مفيدٍ سوف نستخدم شيئين هما الشارات )‪ (Signals‬و الدوال )‬

‫‪ ،(Callback‬عندما يضغط المستخدم على الزر تُعتبر هذه الضغطه اشاره و تؤدي إلى تنفيذ داله )‬ ‫‪ (Callback‬تؤدي هذه الداله وظيفه معينه‪ ،‬مثلً اغلق البرنامج‪.‬‬

‫‪ .1.5.2‬الشارات مع ‪PyGTK‬‬ ‫هل تتذكر السطرين الذين تجاهلناهما عندما بدأنا بشرح مثالنا الول "مرحباً بالعالم"؟ نعم ل بد و إنّك‬ ‫تتذكرهما ‪(-:‬‬

‫;)‪window.connect('delete_event',delete_event‬‬ ‫;)‪window.connect('destroy',destroy‬‬ ‫هذان السطران تطبيقٌ للشارات‪ ،‬مع اي اداة ننشؤها يمكننا استخدام الداله ‪ connect‬حتى نجعل الداة‬

‫تقوم بعمل مفيد‪ ،‬في مثالنا الحالي قمنا بربط النافذه بحدثين‪ ،‬الحدث الول يُسمى ‪ delete_event‬و الثاني‬ ‫يُسمى ‪ ،destroy‬نستخدم هذين الحدثين مع النافذه الرئيسيه فقط لنهما يساعدان على إغلق البرنامج عندما‬

‫يطلب المستخدم ذلك‪ ،‬عندما يتم تنفيذ الحدث الول تُستدعى الداله ‪ delete_event‬و التي عرّفناها‬ ‫مسبقاً‪ ،‬و عندما يتم تنفيذ الحدث الثاني تُستدعى الداله ‪ ،destroy‬الدالتان ‪ delete_event‬و‬ ‫‪ destroy‬هما دالتان من نوع ‪.callback‬‬

‫‪21‬‬

def delete_event(widget,data): False; def destroy(widget,data=None): gtk.main_quit(); ‫ حتى تتضح الصوره‬،‫هذا النوع من الدوال يستقبل على القل بارامترين كما تلحظ في تعريفنا لهاتين الدالتين‬

‫ بحيث اذا ضغطنا على زر "مرحباً بالعالم" تظهر لنا نافذه جديده‬،"‫بشكل اكبر سنطور مثال "مرحباً بالعالم‬ ."PyGTK ‫تحتوي على نص "هذا برنامجي الول مع‬ : ‫الشيفره التاليه ستقوم بالمطلوب‬

# -*- coding: utf-8 -*import pygtk; pygtk.require('2.0'); import gtk; def delete_event(widget,data): False; def destroy(widget,data=None): gtk.main_quit(); def the_new_window(widget,data=None): new = gtk.Window(gtk.WINDOW_TOPLEVEL); new.set_title("‫;)"نافذتنا الجديده‬ msg = gtk.Label("‫ هذا برنامجي الول مع‬PyGTK"); msg.show(); new.add(msg); new.show(); window = gtk.Window(gtk.WINDOW_TOPLEVEL); window.set_title("‫ً بالعالم‬ ‫;)"مرحبا‬ window.connect('delete_event',delete_event); window.connect('destroy',destroy); 22

box1 = gtk.HBox(False,0); window.add(box1); hello_world_button = gtk.Button("‫ً بالعالم‬ ‫;)"مرحبا‬ hello_world_button.connect('clicked',the_new_window); # New line box1.pack_start(hello_world_button,True,True,0); hello_world_button.show(); hello_world_button_2 = gtk.Button("‫;)"الزر الثاني‬ box1.pack_start(hello_world_button_2,True,True,0); hello_world_button_2.show(); box1.show(); window.show(); gtk.main(); .‫ مع داله جديده‬،‫لحظ اننا قمنا بإضافة سطر واحد جديد‬ hello_world_button.connect('clicked',the_new_window); ‫ عندما يقوم المستخدم بالحدث‬،clicked ‫في هذا السطر قمنا بـ "ربط" الزر الول بـ "حدث" يُسمى‬ ‫ لبد و انك خمنت إنّ الحدث‬،the_new_window ‫ يتم استدعاء داله اسمها‬clicked

‫ لنرى‬،the_new_window ‫ هذا يعني عندما يُضغط الزرُ قمْ بإستدعاء الداله‬،‫ يعني الضغط‬clicked

: ‫ما هي هذه الداله التي عرفناها‬

def the_new_window(widget,data=None): new = gtk.Window(gtk.WINDOW_TOPLEVEL); new.set_title("‫;)"نافذتنا الجديده‬ msg = gtk.Label("‫ هذا برنامجي الول مع‬PyGTK"); msg.show(); new.add(msg); new.show(); ‫ كل ما قمنا به هو إنشاء نافذه جديده و وضعنا لها عنوان‬،‫من المفترض إنّه ل شئ جديد عليك في هذه الداله‬ 23

‫"نافذتنا الجديده" و اضفنا إليها نص للقراءه "هذا برنامجي الول مع ‪ ،"PyGTK‬الشئ الجديد في هذه الداله‬

‫هي الداة ‪ Label‬والتي لم نتعامل معها مسبقاً‪ ،‬تقوم هذه الداله بطباعة النص الذي تقوم بوضعه كنص للقراءه‪.‬‬

‫هناك شئ هام ذكرناه مسبقاً و سوف نعيد ذكره هنا بشئ من السهاب‪ ،‬جميع الدوال التي صنفناها من النوع‬ ‫‪ callback‬يجب أنْ تستقبلَ بارامترين على القل‪ ،‬و هذا الذي تلحظه عندما عرّفنا الداله‬

‫‪ ،the_new_window‬البارامتر الول و الذي سميناه ‪ widget‬يُمثل الداة التي استدعت الداله‬

‫‪ ،the_new_window‬و في مثالنا هذا الداة التي قامت بإستدعاء الداله ‪the_new_window‬‬

‫هي ‪) hello_world_button‬الزر المكتوب عليه مرحباً بالعالم(‪ ،‬في هذه الحاله يكون البارامتر‬

‫‪ widget‬هو نفسه ‪ ،hello_world_button‬و بالتالي يمكنك استخدام جميع الدوال التي يقدمها‬ ‫الصنف ‪ gtk.Button‬داخل الداله ‪ the_new_window‬عن طريق البارامتر ‪.widget‬‬

‫ننتقل إلى البارامتر الثاني وهو ‪ ،data‬تخيل معي اننا نريد تمرير بعض البيانات إلى الداله‬

‫‪ ،the_new_window‬كيف يمكننا ذلك؟ نعود لسطرنا الجديد الذي أضفناه مؤخراً ‪:‬‬ ‫;)‪hello_world_button.connect('clicked',the_new_window‬‬

‫حتى نقوم بتمرير بعض البيانات إلى الداله ‪ the_new_window‬نقوم بتمرير بارامتر ثالث إلى الداله‬ ‫‪ ،connect‬مثلً نريد تمرير كلمة "‪ "test‬إلى ‪ ،the_new_window‬يتم ذلك كالتالي ‪:‬‬

‫;)"‪hello_world_button.connect('clicked',the_new_window,"test‬‬ ‫بالطبع يمكننا تمرير انواع بيانات اخرى‪ ،‬مثلً ‪:‬‬ ‫;]'‪info = ['One','Two','Three‬‬ ‫;)‪hello_world_button.connect('clicked',the_new_window,info‬‬ ‫الن كيف يمكننا استقبال البيانات التي قمنا بإرسالها؟ يتم ذلك من خلل البارامتر ‪ ،data‬اذهب إلى الداله‬ ‫‪ the_new_window‬و قم بطباعة محتوى البارامتر ‪ data‬في نهايتها‪ ،‬و جرّب المثالين السابقين‪ ،‬في‬ ‫‪24‬‬

‫اول مثال سوف تطبع كلمة ‪ test‬و في المثال الثاني سوف تطبع السطر ]'‪،['One','Two','Three‬‬

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

‫هكذا نكون قد انتهينا بفضل ال من شرح المفاهيم الساسيه‪ ،‬ننتقل الن إلى المثال الخر حتى نتدرب اكثر‪.‬‬

‫‪25‬‬

‫‪ .1.6‬المثال الثاني ‪ :‬برنامج تحويل درجة الحراره‬ ‫سوف نقوم الن بإستخدام ما تعلمناه و نبني برنامجاً جديداً‪ ،‬يأخذ هذا البرنامج درجة الحراره بالسيليزي و‬

‫يحولُها إلى الفهرنهايتي‪ ،‬هذا يعني إنّ برنامجنا يحتوي على مربع نص لخذ القيمه السيليزيه من المستخدم‪ ،‬و‬

‫كذلك سوف نحتاج إلى زر يضغط المستخدم عليه عند النتهاء من وضع القيمه المُراد تحويلها‪ ،‬و اخيراً نحتاج‬ ‫إلى نص )‪ (Label‬لطباعة الناتج‪ ،‬لنبدأ اولً بكتابة السطر التي اتفقنا على كتابتها في بادئ الكتاب ‪:‬‬

‫*‪# -*- coding: utf-8 -‬‬‫;‪import pygtk‬‬ ‫;)'‪pygtk.require('2.0‬‬ ‫;‪import gtk‬‬ ‫نبني الن النافذه ونضع عنواناً لها‪ ،‬و نكتب الدالتين اللتان تساعدان على الخروج من البرنامج ‪:‬‬ ‫‪def delete_event(widget,data):‬‬ ‫;‪False‬‬ ‫‪def destroy(widget,data=None):‬‬ ‫;)(‪gtk.main_quit‬‬ ‫;)‪window = gtk.Window(gtk.WINDOW_TOPLEVEL‬‬ ‫;)"برنامج التحويل"(‪window.set_title‬‬ ‫;)‪window.connect('delete_event',delete_event‬‬ ‫;)‪window.connect('destroy',destroy‬‬ ‫كما اتفقنا في البدايه‪ ،‬سوف نحتاج إلى مربع نص‪ ،‬زر و نص مقروء )‪ ،(Label‬سنضعهم اسفل بعضهم‬

‫البعض‪ ،‬و بالتالي سنستخدم صندوق من نوع ‪ ،VBox‬سنقوم بإنشاء هذا الصندوق ثم نضيفه إلى النافذه كما‬

‫تعلمنا من المثال السابق‪.‬‬

‫;)‪main_box = gtk.VBox(False,0‬‬ ‫;)‪window.add(main_box‬‬ ‫لنبدأ بإضافة مربع النص اولً‪ ،‬لحظ اننا و للمره الولى نستخدم هذه الداة‪ ،‬نقوم بإنشاءها اولً عن طريق إنشاء‬ ‫‪26‬‬

‫كائن لها ثم نضيفها داخل صندوقنا و اخيراً نقوم بإظهارها ‪:‬‬ ‫;)(‪text_entry = gtk.Entry‬‬ ‫;)‪main_box.pack_start(text_entry,True,True,0‬‬ ‫;)(‪text_entry.show‬‬ ‫الن نضيف اداة النص و التي تعرفنا عليها مسبقاً و كانت بإسم ‪ ،Label‬تكون في البدايه فارغه‪ ،‬و سوف يتم‬ ‫تغييرها فيما بعد ‪:‬‬

‫;)""(‪status_label = gtk.Label‬‬ ‫;)‪main_box.pack_start(status_label,True,True,0‬‬ ‫;)(‪status_label.show‬‬

‫لننشئ زر و نضع فوقه كلمة "موافق"‪ ،‬ثم نضيفه إلى صندوقنا و اخيراً نظهره ‪:‬‬ ‫;)"موافق"(‪ok_button = gtk.Button‬‬ ‫;)‪main_box.pack_start(ok_button,True,True,0‬‬ ‫;)(‪ok_button.show‬‬ ‫و اخيراً سوف نُظهر الصندوق و النافذه الرئيسيه و نستدعي الداله الساسيه ‪: gtk_main‬‬ ‫;)(‪main_box.show‬‬ ‫;)(‪window.show‬‬ ‫;)(‪gtk.main‬‬ ‫صممنا الن واجهه بسيطه لبرنامجنا‪ ،‬لحظ إنّ البرنامج لحد الن ل يقوم بأي عمل مفيد‪ ،‬حتى يقوم البرنامج‬

‫بعمل مفيد سنقوم بربط الزر بحدث‪ ،‬بحيث عندما يتم الضغط على الزر تُستدعى داله معينه تقوم بالعمليه‬ ‫الحسابيه و تطبع الناتج‪ ،‬نتوجه إلى السطرين اللذين قمنا بكتابتهما ‪:‬‬

‫;)"موافق"(‪ok_button = gtk.Button‬‬ ‫‪27‬‬

‫;)‪main_box.pack_start(ok_button,True,True,0‬‬ ‫و نضيف في اسفلهما دالة الربط‪ ،‬لبد و انك تعرفها ‪(-:‬‬ ‫;]‪widgets = [status_label,text_entry‬‬ ‫;)‪ok_button.connect('clicked',ClickEvent,widgets‬‬ ‫لنتوقف هنا قليلً‪ ،‬كما تعلم إنّ البارامتر الول هو الحدث‪ ،‬و ‪ clicked‬بمعنى الضغط‪.‬‬

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

‫‪ ClickEvent‬التي سوف نكتبها بعد قليل‪ ،‬و سوف تستقبل ‪ ClickEvent‬هذا البارامتر بإسم‬

‫‪ ،data‬لبد و انك تعرف هذه المعلومات و لكن وجب التذكير‪ ،‬قد تتسائل لماذا مررنا هذه المصفوفه؟ سيأتيك‬

‫الجواب عند تعريف الداله ‪.ClickEvent‬‬

‫لنصعد قليلً‪ ،‬و بالضبط اسفل الداله ‪ destroy‬سوف نعرّف دالتنا ‪ ،ClickEvent‬تقوم هذه الداله‬

‫بأخذ القيمه الموجوده في مربع النص تضربها في ‪ 1.8‬ثم تضيف عليه ‪ 32‬و بالتالي يكون الناتج درجة الحراره‬

‫بالفهرنهايت‪ ،‬نكتب اولً رأس الداله و التي تستقبل بارامترين كما شرحنا مسبقاً ‪:‬‬

‫‪def ClickEvent(widget,data=None):‬‬ ‫يُعتبر البارامتر ‪ data‬الن مصفوفه تحتوي على عنصرين‪ ،‬العنصر الول هو الكائن ‪ status_label‬و الذي‬

‫يتيح لنا التحكم بأداة النص )‪ ،(Label‬اما العنصر الثاني هو الكائن ‪ text_entry‬و الذي يتيح لنا التحكم‬

‫في اداة مربع النص‪ ،‬و بالطبع البارامتر ‪ widget‬يتيح لنا التحكم بالزر‪ ،‬مررنا الكائن ‪ status_label‬على‬ ‫الداله ‪ ClickEvent‬حتى نتمكن من تغيير النص الموجود في اداة النص )‪ (Label‬من داخل الداله‪،‬‬

‫هذا يعني إنّنا نريد الوصول إلى هذه الدوات من داخل الداله‪ ،‬و بالتالي مررنا كائنات هذه الدوات كبارامتر‬ ‫للداله‪ ،‬الن تحتوي ‪ [data[0‬على الكائن ‪ status_label‬و تحتوي ‪ [data[1‬على الكائن‬ ‫‪ text_entry‬و حتى نقوم بالتسهيل نخزّن القيم في متغيرات جديده ذات اسم اوضح ‪:‬‬ ‫‪28‬‬

‫;]‪status_label = data[0‬‬ ‫;]‪text_entry = data[1‬‬ ‫نأخذ الن القيمه الموجوده في داخل مربع النص بإستخدام الداله ‪ get_text‬و التي يوفرها الصنف‬ ‫‪: gtk.Entry‬‬

‫;)(‪val = text_entry.get_text‬‬ ‫نحوّل هذه القيمه من نوع ‪ string‬إلى نوع ‪: float‬‬ ‫;)‪val = float(val‬‬ ‫نُجري عمليتنا الحسابيه ‪:‬‬ ‫;‪result = (val * 1.8) + 32‬‬ ‫نحول الناتج من نوع ‪ float‬إلى ‪ string‬مره اخرى من اجل كتابته داخل اداة النص ‪:‬‬ ‫;)‪result = str(result‬‬ ‫اخيراً نغير النص الموجود في اداة النص بإستخدام الداله ‪ set_text‬و التي يوفرها الصنف‬ ‫‪: gtk.Label‬‬

‫;)‪status_label.set_text(result‬‬ ‫بهذا الشكل تكون شيفرة الداله كامله كالتالي ‪:‬‬ ‫‪def ClickEvent(widget,data=None):‬‬ ‫;]‪status_label = data[0‬‬ ‫;]‪text_entry = data[1‬‬ ‫;)(‪val = text_entry.get_text‬‬ ‫‪29‬‬

‫;)‪val = float(val‬‬ ‫;‪result = (val * 1.8) + 32‬‬ ‫;)‪result = str(result‬‬ ‫;)‪status_label.set_text(result‬‬ ‫نعود ثانية لنقطة البارامتر ‪ ،data‬هناك طريقه اخرى بدلً من تمرير الدوات التي نريد التحكم بها من داخل‬

‫الداله فبدلً من تمريرها كبارامترات للداله ‪ ClickEvent‬يمكننا استخدام الكلمه ‪ global‬للوصول إلى‬

‫كائنات هذه الدوات بدون الحاجه إلى تمريرها كبارامترات‪ ،‬و بالتالي تكون دالتنا بهذا الشكل ‪:‬‬

‫‪def ClickEvent(widget,data=None):‬‬ ‫;‪global text_entry,status_label‬‬ ‫;)(‪val = text_entry.get_text‬‬ ‫;)‪val = float(val‬‬ ‫;‪result = (val * 1.8) + 32‬‬ ‫;)‪result = str(result‬‬ ‫;)‪status_label.set_text(result‬‬ ‫و السطران ‪:‬‬ ‫;]‪widgets = [status_label,text_entry‬‬ ‫;)‪ok_button.connect('clicked',ClickEvent,widgets‬‬ ‫يصبحان بهذا الشكل ‪:‬‬ ‫;)‪ok_button.connect('clicked',ClickEvent‬‬ ‫بدون تمرير اي شئ‪ ،‬ما رأيك أليست اسهل و اكثرا اختصاراً؟ ‪ (-:‬سنستخدم ‪ global‬من الن فصاعداً‪ ،‬الن‬ ‫الشيفره النهائيه لبرنامج التحويل كالتالي ‪:‬‬

‫*‪# -*- coding: utf-8 -‬‬‫‪30‬‬

import pygtk; pygtk.require('2.0'); import gtk; def delete_event(widget,data): False; def destroy(widget,data=None): gtk.main_quit(); def ClickEvent(widget,data=None): global text_entry,status_label; val = text_entry.get_text(); val = float(val); result = (val * 1.8) + 32; result = str(result); status_label.set_text(result); window = gtk.Window(gtk.WINDOW_TOPLEVEL); window.set_title("‫;)"برنامج التحويل‬ window.connect('delete_event',delete_event); window.connect('destroy',destroy); main_box = gtk.VBox(False,0); window.add(main_box); text_entry = gtk.Entry(); main_box.pack_start(text_entry,True,True,0); text_entry.show(); status_label = gtk.Label(""); main_box.pack_start(status_label,True,True,0); status_label.show(); ok_button = gtk.Button("‫;)"موافق‬ main_box.pack_start(ok_button,True,True,0); ok_button.connect('clicked',ClickEvent); ok_button.show(); main_box.show(); window.show(); gtk.main();

31

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

‫تُكتب العمليه المطلوب تنفيذها في المربع الثاني و اخيراً يُكتب الرقم الثاني في المربع الخير‪ ،‬بالضافه إلى‬ ‫ذلك يكون هناك زراً لظهار الناتج و يكون هناك نصاً )‪ (Label‬يظهر فيه الناتج بعد الضغط على الزر‪.‬‬

‫كما تعودنا نكتب اولً الشيفرات الساسيه و التي دائماً ما نستخدمها في بداية برامجنا ‪:‬‬ ‫*‪# -*- coding: utf-8 -‬‬‫;‪import pygtk‬‬ ‫;)'‪pygtk.require('2.0‬‬ ‫;‪import gtk‬‬ ‫نبني الن نافذه البرنامج مع الدالتين اللتين تعودنا دائماً ربط النوافذ بهما ‪:‬‬ ‫‪def delete(widget,data):‬‬ ‫;‪False‬‬ ‫‪def des(widget,data=None):‬‬ ‫;)(‪gtk.main_quit‬‬ ‫;)‪win = gtk.Window(gtk.WINDOW_TOPLEVEL‬‬ ‫;)"آله حاسبه"(‪win.set_title‬‬ ‫;)‪win.connect('delete_event',delete‬‬ ‫;)‪win.connect('destroy',des‬‬ ‫لنأخذ وقتنا بالتفكير بعدما بنينا النافذه‪ ،‬الصندوق الرئيسي الذي سنضعه هل يكون من نوع ‪ HBox‬ام ‪،VBox‬‬

‫كما اتفقنا سيكون هنالك ثلث مربعات نص‪ ،‬و جميعها بجانب بعضها البعض‪ ،‬و في اسفلها جميعها يكون هناك‬

‫زر و اسفل الزر هناك نص تظهر فيه النتائج‪ ،‬في هذه الحاله نحتاج إلى النوعين‪ ،‬نحتاج الصندوق ‪ HBox‬من‬

‫اجل مربعات النص الثلثه بجانب بعضهم‪ ،‬و نحتاج إلى صندوق ‪ VBox‬حتى نضع الزر اسفل هذه الدوات و‬ ‫‪32‬‬

‫نضع النص اسفل المربع‪ ،‬الصندوق الرئيسي سيكون من نوع ‪ ،VBox‬نقسم هذا الصندوق إلى ثلث خانات‬

‫عموديه‪ ،‬الخانه الولى تحتوي على مربعات النص‪ ،‬الخانه الثانيه تحتوي على الزر و الخانه الثالثه تحتوي على‬ ‫النص )‪ ،(Label‬المشكله هنا أنّ الخانه الواحده ل تستوعب إل اداة واحده‪ ،‬و بما أنّ نوع الصندوق‬

‫‪ VBox‬اذاً سيتم وضع كل اداة جديده يتم اضافتها إلى الصندوق في اسفل الداة التي تسبقها‪ ،‬اذاً لدينا‬

‫مشكله في الخانه الولى و هي كيف نضع الثلث ادوات بجانب بعضهن البعض؟ سنقوم بإنشاء صندوق جديد‬

‫من نوع ‪ HBox‬غير الصندوق الرئيسي‪ ،‬بعدها نضيف مربعات النص إلى الصندوق الثاني ‪ HBox‬و اخيراً‬

‫نضيف الصندوق ‪ HBox‬إلى الصندوق الرئيسي من نوع ‪ VBox‬في الخانه الولى‪ ،‬هذه الطريقه هي الطريقه‬

‫المُستخدمه دائماً لحل مثل هذه المشاكل‪ ،‬عندما يكون لدينا واجهه معقده و تحتوي على ادوات بجانب بعضها و‬ ‫ادوات اخرى اسفلها نستخدم الحل المشروح و الذي نضع عليه مثال عملي الن‪.‬‬

‫حسناً لنبدأ‪ ،‬نضيف الن الصندوق الرئيسي و الذي كما اتفقنا سيكون من نوع ‪: VBox‬‬ ‫;)‪main_box = gtk.VBox(False,0‬‬ ‫;)‪win.add(main_box‬‬ ‫كما اتفقنا‪ ،‬في الخانه الولى سنضع مربعات النص الثلثه بجانب بعضهن‪ ،‬ووفقاً لما شرحناه بالعلى سننشئ‬ ‫صندوقاً جديداً من نوع ‪ HBox‬من اجل تنفيذ هذا الغرض ‪:‬‬

‫;)‪box1 = gtk.HBox(False,0‬‬ ‫نضيف الن مربع النص الول بشكل عادي و كما تعلمنا في الصفحات السابقه‪ ،‬و لكننا بدلً من اضافته إلى‬

‫الصندوق الرئيسي ‪ main_box‬نضيفه إلى الصندوق الثاني ‪ ،box1‬يُستخدم مربع النص هذا من اجل كتابة‬ ‫الرقم الول ‪:‬‬

‫;)(‪first_number = gtk.Entry‬‬ ‫;)‪box1.pack_start(first_number,True,True,0‬‬ ‫;)(‪first_number.show‬‬ ‫نضيف بعدها المربع الثاني‪ ،‬و الذي يُستخدم من اجل كتابة نوع العمليه المطلوبه ‪ +‬او ‪ -‬او * او \‬

‫‪33‬‬

‫;)(‪operation = gtk.Entry‬‬ ‫;)‪box1.pack_start(operation,True,True,0‬‬ ‫;)(‪operation.show‬‬ ‫و اخيرا نضيف المربع الثالث و الذي يُستخدم لكتابة الرقم الثاني ‪:‬‬ ‫;)(‪second_number = gtk.Entry‬‬ ‫;)‪box1.pack_start(second_number,True,True,0‬‬ ‫;)(‪second_number.show‬‬ ‫الن و بعد اضافة جميع مربعات النص إلى الصندوق الثاني‪ ،‬نضيف الصندوق إلى الصندوق الرئيسي ثم نُظهره ‪:‬‬ ‫;)‪main_box.pack_start(box1,True,True,0‬‬ ‫;)(‪box1.show‬‬ ‫نضيف الن بقية الدوات بشكل عادي طالما انها سوف تكون تحت بعضها البعض‪ ،‬بالطبع ل داعي ان اقول لك‬ ‫اننا سوف نضيفها إلى الصندوق الرئيسي ‪ ، (-:‬نضيف اولً الزر ‪:‬‬

‫;)"أظهر الناتج"(‪button = gtk.Button‬‬ ‫;)‪main_box.pack_start(button,True,True,0‬‬ ‫;)(‪button.show‬‬ ‫بعد الزر نضيف النص ‪:‬‬ ‫;)(‪result = gtk.Label‬‬ ‫;)‪main_box.pack_start(result,True,True,0‬‬ ‫;)(‪result.show‬‬

‫و اخيراً نُظهر الصندوق الرئيسي‪ ،‬النافذه‪ ،‬و ننادي الداله الساسيه ‪:‬‬ ‫;)(‪main_box.show‬‬ ‫‪34‬‬

‫;)(‪win.show‬‬ ‫;)(‪gtk.main‬‬ ‫انتهينا الن من تصميم الواجهه فحسب‪ ،‬يجب ان يكون برنامجنا اكثر من مجرد واجهه ‪ ،(-:‬يبدأ عمل البرنامج‬

‫عندما يضغط المستخدم على الزر‪ ،‬يستدعي الزرُ داله معينه تقوم بالعمليه الرياضيه ثم تطبع الناتج على النص )‬ ‫‪ (Label‬هذا كل شئ‪.‬‬

‫اذاً نبدأ مع الزر‪ ،‬نربط الزر بالحدث ‪ clicked‬و نستدعي داله اسمها ‪ DoMath‬عن طريق السطر التالي‬

‫و الذي سوفه نضيفه فوق وضع الزر في الصندوق الرئيسي ‪:‬‬

‫;)‪button.connect('clicked',DoMath‬‬ ‫نُعرّف الن الداله ‪ DoMath‬في اسفل الدوال التي عرفناها مسبقاً ‪:‬‬ ‫‪def DoMath(widget,data=None):‬‬ ‫نستخدم ‪ global‬كما شرحنا مسبقاً حتى نتمكن من التحكم بالدوات من داخل الداله ‪:‬‬ ‫;‪global result,first_number,second_number,operation‬‬ ‫نبدأ اولً في التحقق اذا كان المستخدم ترك مربعات النص فارغه ام ل‪ ،‬في حال ترك احدها فارغه نُظهر له‬ ‫رسالة خطأ ‪:‬‬

‫;)(‪f = first_number.get_text‬‬ ‫;)(‪s = second_number.get_text‬‬ ‫;)(‪o = operation.get_text‬‬ ‫‪if f == "" or s == "" or o == "":‬‬ ‫;)"يرجى تعبئة المعلومات المطلوبه"(‪result.set_text‬‬ ‫‪35‬‬

‫اذا كان كل شئ يعمل حسب الصول و جميع المعلومات المطلوبه متوفره‪ ،‬نبدأ بالعمليه الحسابيه‪ ،‬في بادئ‬ ‫المر نحوّا نوع كل من المتغيرين ‪ f‬و ‪ s‬إلى ‪ integer‬حتى يكون ناتج العمليه الحسابيه صحيحاً ‪:‬‬ ‫;)‪f = int(f‬‬ ‫;)‪s = int(s‬‬ ‫بعدها نتحقق من النص الذي ادخله المستخدم في المربع الثاني‪ ،‬هل هو ‪ +‬او ‪ -‬او * او \ ثم نقوم بالعمليه‬

‫المطلوبه وفقاً لمحتوى المربع الثاني‪ ،‬اذا كان محتوى المربع الثاني ل يساوي اياً من القيم المذكوره سنطبع‬ ‫رساله خطأ للمستخدم و نخرج من دالة ‪: DoMath‬‬

‫‪if o == "+":‬‬ ‫;‪r = f + s‬‬ ‫‪elif o == "-":‬‬ ‫;‪r = f - s‬‬ ‫‪elif o == "*":‬‬ ‫;‪r = f * s‬‬ ‫‪elif o == "/":‬‬ ‫;‪r = f / s‬‬ ‫‪else:‬‬ ‫العمليه التي قمت بإختيارها"(‪result.set_text‬‬ ‫;)"غير صحيحه‬ ‫;‪return False‬‬ ‫و اخيراً نطبع الناتج للمستخدم بعد تحويله إلى نص ‪:‬‬ ‫;))‪result.set_text(str(r‬‬ ‫هذا كل شئ‪ ،‬ما رأيك هل المور سهله؟ ‪(-:‬‬ ‫النص الكامل للبرنامج ‪:‬‬

‫*‪# -*- coding: utf-8 -‬‬‫;‪import pygtk‬‬ ‫;)'‪pygtk.require('2.0‬‬ ‫;‪import gtk‬‬ ‫‪36‬‬

def delete(widget,data): False; def des(widget,data=None): gtk.main_quit(); def DoMath(widget,data=None): global result,first_number,second_number,operation; f = first_number.get_text(); s = second_number.get_text(); o = operation.get_text(); if f == "" or s == "" or o == "": result.set_text("‫;)"يرجى تعبئة المعلومات المطلوبه‬ else: f = int(f); s = int(s); if o == "+": r = f + s; elif o == "-": r = f - s; elif o == "*": r = f * s; elif o == "/": r = f / s; else: result.set_text("‫العمليه التي قمت بإختيارها‬ ‫;)"غير صحيحه‬ return False; result.set_text(str(r)); win = gtk.Window(gtk.WINDOW_TOPLEVEL); win.set_title("‫;)"آله حاسبه‬ win.connect('delete_event',delete); win.connect('destroy',des); main_box = gtk.VBox(False,0); win.add(main_box); box1 = gtk.HBox(False,0); first_number = gtk.Entry(); box1.pack_start(first_number,True,True,0); first_number.show(); operation = gtk.Entry(); 37

box1.pack_start(operation,True,True,0); operation.show(); second_number = gtk.Entry(); box1.pack_start(second_number,True,True,0); second_number.show(); main_box.pack_start(box1,True,True,0); box1.show(); button = gtk.Button("‫;)"أظهر الناتج‬ button.connect('clicked',DoMath); main_box.pack_start(button,True,True,0); button.show(); result = gtk.Label(); main_box.pack_start(result,True,True,0); result.show(); main_box.show(); win.show(); gtk.main();

38

‫‪ .1.8‬مدخل إلى ‪Glade‬‬ ‫‪ .1.8.1‬مقدمه‬ ‫قد يعتبر البعض كتابة الشيفره المصدريه الخاصه بواجهة البرنامج عمليه ممله و على العكس قد يكون هناك‬

‫اشخاص يتمتعون عندما يكتبون شيفرة واجهة البرنامج‪ ،‬و لكن لنفكر بالموضوع قليلً‪ ،‬اذا قررنا كتابة برنامج‬ ‫ضخم بإستخدام ‪ PyGTK‬فإننا سنستغرق الكثير من الوقت من اجل كتابة الشيفره المصدريه الخاصه‬

‫بالواجهه‪ ،‬و قد تكون عملية الضافه على الواجهه في ما بعد عمليه متعبه و طويله‪ ،‬لحسن الحظ هناك حل لهذه‬ ‫المشكله و هو برنامج ‪.Glade‬‬

‫يسهّل عليك برنامج ‪ Glade‬تصميم واجهات برنامجك‪ ،‬فبدلً من كتابة شيفرة الواجهه تقوم بتصميم الواجهه‬

‫بشكل مرئي عن طريق برنامج ‪ ،Glade‬سوف يفهم مبرمجي ‪ Gambas‬و ‪ Delphi‬و ‪Visual‬‬

‫‪ Basic‬قصدي‪ ،‬يقوم برنامج ‪ Glade‬بعدها بتوليد ملفات من نوع ‪ xml‬تستخدمها فيما بعد داخل شيفرة‬

‫برنامجك حتى تتمكن من التحكم في واجهتك الرسوميه‪.‬‬

‫‪ Glade‬ليس برنامجاً فحسب‪ ،‬بل يأتي معه مكتبه برمجيه تحتوي على مجموعه من الدوال التي تساعدك على‬

‫التعامل مع ملفات ‪ xml‬التي يولدها ‪ ،Glade‬إلى وقت تأليف هذا الكتاب فإن النسخه النهائيه من ‪Glade‬‬ ‫هي النسخ ‪ ،3.4‬الجيل الثالث من ‪ Glade‬كان اعادة كتابه من الصفر‪ ،‬من وجهة نظري ان واجهة الجيل‬

‫الثالث افضل بكثير من واجهة الجيل الثاني‬

‫سوف نتعلم في الصفحات القادمه إن شاء ال كيفية استخدام ‪ Glade‬و استخدام مكتبته لنشاء تطبيقاتنا‪.‬‬

‫‪39‬‬

‫‪ .1.8.2‬التصميم مع ‪Glade‬‬ ‫لقد تعلمنا في القسام السابقه كيف نكتب شيفرة واجهة المستخدم‪ ،‬عملية تصميم واجهة المستخدم مع‬

‫‪ Glade‬اسهل بكثير‪ ،‬بمجرد رؤيتك لواجهة البرنامج سوف ترى إنّ العمليةَ بسيطةٌ‪ ،‬لنلقي نظره على الصوره‬

‫التاليه ‪:‬‬

‫هذا هو برنامج ‪ Glade‬الذي سنستخدمه لتصميم واجهاتنا من الن فصاعداً‪ ،‬حسناً لنرى الن كيف يمكننا‬

‫استخدام هذا البرنامج في تصميم واجهتنا‪ ،‬نلحظ على الجانب اليسر قائمه تحتوي على الدوات مثل النافذه و‬

‫الصناديق و مربعات النص و غيرها الكثير من الدوات التي لم نستخدمها مسبقاً‪ ،‬هذه هي جميع الدوات التي‬ ‫‪40‬‬

‫تقدمها ‪ ،GTK‬كما تعودنا دائماً في البدايه نحن بحاجه إلى نافذه حتى نضيف عليها ادوات البرنامج‪ ،‬ستجد‬

‫النافذه في قائمة ‪ Toplevels‬و اسمها ‪ ،Window‬الصوره التاليه توضح لك اننا اضفنا نافذه إلى واجهتنا‬ ‫التي نبنيها ‪:‬‬

‫لحظ الفرق بعد اضافة النافذه‪ ،‬في المنتصف ظهرت النافذه التي اضفناها و التي سوف نضيف فوقها الدوات‪،‬‬

‫اذاً الجزء الذي يقع في المنتصف هو مكان العمل‪ ،‬اما جهة اليمين نلحظ ان هناك قائمه في العلى‪ ،‬هذه القائمه‬

‫تحتوي على جميع الدوات التي اضفناها في مشروعنا هذا‪ ،‬اما اسفل هذه القائمه نجد صندوقاً يحتوي على‬

‫مجموعه من مربعات النص و القوائم و التبويبات‪ ،‬من خلل هذا الصندوق يمكننا التحكم بخصائص اي اداة‪ ،‬و‬ ‫في هذه الصوره بالذات فإننا نتحكم بخصائص النافذه التي اضفناها‪ ،‬الصوره التاليه توضح شرحنا هذا بشكل‬ ‫اوضح ‪:‬‬

‫‪41‬‬

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

‫هيا لنبدأ نضيف اولً النافذه تجدها كما ذكرنا تحت القسم ‪ Toplevels‬بإسم ‪ ،Window‬لننا سنضيف‬

‫اداة واحده فقط و بالتالي لسنا بحاجه إلى استخدام الصناديق‪ ،‬نضيف الزر إلى النافذه مباشره‪ ،‬بعد إضافة الزر‬

‫نذهب إلى خصائصه لنغيرها )يمين الشاشه في السفل(‪ ،‬يجب ان يكون التبويت المُختار هو ‪ General‬نجد‬ ‫حقل اسمه ‪ label‬و بجانبه مربع نص كبير‪ ،‬نغيّر النص في هذا المربع إلى "مرحباً بالعالم"‪ ،‬يجب ان يظهر‬

‫لك شئ مشابه للصوره التاليه )بالمناسبه ل تقلق بشأن حجم النافذه( ‪:‬‬

‫‪42‬‬

‫نخزّن الن واجهتنا البسيطه‪.‬‬ ‫من اجل الترتيب من الفضل إنشاء مجلد خاص ببرنامجنا لنخزّن فيه الملف‪ ،‬لنسمي ملفنا بإسم ‪ ،gui‬بعد‬

‫التخزين يجب ان يكون لدينا في المجلد ملف بإسم ‪ ،gui.glade‬هذا الملف هو الواجهه التي صممناها و‬

‫التي سوف نستخدمها في النص البرمجي لظهار الواجهه‪ ،‬ننتقل إلى القسم التالي حتى نرى كيف نتعامل مع‬ ‫ملفات ‪ Glade‬في النص البرمجي‪.‬‬

‫‪43‬‬

‫‪ .1.8.3‬استخدام ما تم تصميمه مع ‪ Glade‬في النص البرمجي‬ ‫نبدأ برنامجنا كما تعودنا دائماً بإرفاق المكتبات التي سوف نستخدمها ‪:‬‬ ‫*‪# -*- coding: utf-8 -‬‬‫;‪import pygtk‬‬ ‫;)'‪pygtk.require('2.0‬‬ ‫;‪import gtk‬‬ ‫لننا الن سوف نتعامل مع ملفات من نوع ‪ glade.‬فإننا بحاجه إلى ارفاق مكتبة ‪ Glade‬حتى نتكمن من‬ ‫التعامل مع الملف الذي ولّده برنامج ‪: Glade‬‬

‫;‪import gtk.glade‬‬ ‫نضيف الدوال التي اعتدنا على اضافتها في كل برنامج ‪:‬‬ ‫‪def delete_event(widget,data):‬‬ ‫;‪False‬‬ ‫‪def destroy(widget,data=None):‬‬ ‫;)(‪gtk.main_quit‬‬ ‫نستخدم الن الداله ‪ XML‬التي تقدمها لنا مكتبة ‪ ،Glade‬بالطبع تحتوي مكتبة ‪ Glade‬على الكثير من‬

‫الدوال التي تقدم لنا وظائف مختلفه و لكننا سنستخدم الدوال الساسيه‪ ،‬يمكنك البحث اكثر من خلل قراءتك‬ ‫للدليل الرسمي‪ ،‬نعود للداله ‪ XML‬تأخذ هذه الداله اسم ملف ‪ glade.‬كبارامتر و تجعل المتغير ‪ -‬الذي‬ ‫يقوم المبرمج بوضعه للداله ‪ - XML‬هو المُتحكم في الواجهه‪ ،‬نقوم الن بإستخدام هذه الداله ‪:‬‬

‫;)'‪g = gtk.glade.XML('gui.glade‬‬ ‫وفقاً للسطر السابق فإن ‪ g‬هو المتغير الذي سوف نتحكم من خلله بواجهتنا‪ ،‬و ‪ gui.glade‬هو اسم الملف‬ ‫‪44‬‬

‫الذي ولّده برنامج ‪ ،Glade‬لبد و انك تتذكر اننا سمينا الملف بإسم ‪.gui‬‬ ‫تحتوي واجهتنا هذه على اداتين‪ ،‬الداة الولى هي النافذه الرئيسيه‪ ،‬الداة الثانيه هي الزر المكتوب فوقه "مرحباً‬ ‫بالعالم"‪.‬‬

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

‫‪ Glade‬و شغّل الملف ‪ ،gui.glade‬اختر النافذه و انظر في خصائصها‪ ،‬انظر الخاصيه ‪ Name‬سوف‬

‫تجد ان المكتوب في المربع الواقع بجانب ‪ Name‬هو ‪ window1‬هذا هو السم الذي سوف نمرره إلى‬ ‫الداله ‪ ،get_widget‬كذلك بالنسبه للزر سوف تجد ان اسمه ‪ ،button1‬بالطبع يمكنك تغيير هذه‬

‫السماء إلى اسماء انسب‪ ،‬من وجهة نظري جعل السماء الفتراضيه التي يضعها ‪ Glade‬من ‪ window1‬و‬ ‫‪ button1‬و ‪ button2‬عاده سيئه و سوف يظهر ذلك بوضوح عندما تصمم برنامج ذات واجهه معقده‪،‬‬

‫لذلك من الفضل وضع اسماء ذات معنى لكل اداة‪.‬‬

‫غيّر الن اسم النافذه إلى ‪ ،main_window‬و اسم الزر إلى ‪ hello_world_button‬و احفظ‬ ‫التعديلت‪ ،‬الن لنستخدم الداله ‪: get_widget‬‬

‫;)'‪window = g.get_widget('main_window‬‬ ‫;)'‪button = g.get_widget('hello_world_button‬‬ ‫ممتاز‪ ،‬الن يمكننا التحكم بالدوات‪ ،‬كما تعودنا نقوم بإظهار الدوات عن طريق الداله ‪: show‬‬ ‫;)(‪window.show‬‬ ‫;)(‪button.show‬‬ ‫نستدعي الداله الساسيه ‪:‬‬

‫‪45‬‬

‫;)(‪gtk.main‬‬ ‫حسناً ل بد و انك تعلم اننا الن يمكننا استخدام المتغيرين ‪ window‬و ‪ button‬من اجل التحكم‬

‫بالداتين و بالتالي يمكننا استخدام جميع الدوال التي يقدمها صنف ‪ gtk.Window‬او صنف‬

‫‪ ،gtk.Button‬مثلً اذا اردنا تغيير عنوان النافذه يمكننا استخدام الداله ‪ set_title‬و هكذا‪.‬‬

‫الن اصبح من الواضح كيفية استخدام الملفات التي يولّدها برنامج ‪ Glade‬في داخل برامجنا‪ ،‬سوف ننتقل‬ ‫إلى القسم التالي و نتعلم كيف يمكننا التعامل مع الشارات‪.‬‬ ‫الشيفره كامله ‪:‬‬ ‫*‪# -*- coding: utf-8 -‬‬‫;‪import pygtk‬‬ ‫;)'‪pygtk.require('2.0‬‬ ‫;‪import gtk‬‬ ‫;‪import gtk.glade‬‬ ‫‪def delete_event(widget,data):‬‬ ‫;‪False‬‬ ‫‪def destroy(widget,data=None):‬‬ ‫;)(‪gtk.main_quit‬‬ ‫;)'‪g = gtk.glade.XML('gui.glade‬‬ ‫;)'‪window = g.get_widget('main_window‬‬ ‫;)'‪button = g.get_widget('hello_world_button‬‬ ‫;)(‪window.show‬‬ ‫;)(‪button.show‬‬ ‫;)(‪gtk.main‬‬

‫‪46‬‬

‫‪ .1.8.4‬استخدام الشارات مع ما تم تصميمه مع ‪Glade‬‬ ‫هناك طريقتان يمكننا استخدام احدهما للتعامل مع الشارات عند استخدامنا لـ ‪ ،Glade‬الطريقه الولى هي‬

‫الطريق التي اعتدنا عليها و استخدمناها في السابق‪ ،‬درسنا قبل قليل الداله ‪ get_widget‬و التي تسمح لنا‬

‫باستخدام اي اداة بشكل عادي و كأننا اضفناها عن طريق شيفره برمجيه‪ ،‬و بالتالي يمكننا استخدام الطريقه‬

‫القديمه و هي الداله ‪ ،connect‬نعود لمثالنا السابق‪ ،‬نريد ربط الزر بحدث الضغط‪ ،‬عندما يضغط المستخدم‬

‫على الزر يتغير النص الموجود في اعلى الزر إلى "تم الضغط على الزر" و بالطبع ل ننسى ربط النافذه بدالة‬ ‫الغلق ‪:‬‬

‫;)'‪window = g.get_widget('main_window‬‬ ‫;)'‪button = g.get_widget('hello_world_button‬‬ ‫اولً نبدأ بدوال الغلق ‪:‬‬ ‫;)‪window.connect('delete_event',delete_event‬‬ ‫;)‪window.connect('destroy',destroy‬‬ ‫الن نعمل مع الزر‪ ،‬و نربطه بحدث الضغط كما تعلمنا مسبقاً ‪:‬‬ ‫;)‪button.connect('clicked',ButtonClicked‬‬ ‫نكتب الن الداله ‪ ButtonClicked‬اعلى الملف ‪:‬‬ ‫‪def ButtonClicked(widget,data=None):‬‬ ‫;)'تم الضغط على الزر'(‪widget.set_label‬‬ ‫هذا كل شئ!‬ ‫الشيفره كامله ‪:‬‬ ‫‪47‬‬

# -*- coding: utf-8 -*import pygtk; pygtk.require('2.0'); import gtk; import gtk.glade; def delete_event(widget,data): False; def destroy(widget,data=None): gtk.main_quit(); def ButtonClicked(widget,data=None): widget.set_label('‫;)'تم الضغط على الزر‬ g = gtk.glade.XML('gui.glade'); window = g.get_widget('main_window'); button = g.get_widget('hello_world_button'); window.connect('delete_event',delete_event); window.connect('destroy',destroy); button.connect('clicked',ButtonClicked); window.show(); button.show(); gtk.main(); ‫بالطبع ل داعي للسهاب عن ما قمنا به لننا تحدثنا بشكل مفصّل عنه بالقسام السابقه و يفترض بك أنْ تكون‬ .‫فهمته بشكل جيّد‬

‫ مع برنامج‬gui.glade ‫ شغّل الملف‬،Glade ‫ننتقل الن إلى الطريقه الثانيه و هذه الطريقه خاصه بـ‬

‫ و هذه المره بدلً من اختيار‬،‫ اذهب إلى الخصائص‬،‫ و اختر الزر من اجل تغيير خصائصه‬،‫ مره اخرى‬Glade

،‫ من خلل هذا التبويب يمكننا ربط الزر بأي حدث مطلوب‬،Signals ‫ اختر التبويب‬General ‫التبويت‬

‫ سوف نجد مربع نص يمكننا‬clicked ‫ بجانب الكلمه‬،clicked ‫في برنامجنا هذا الحدث المطلوب هو‬

‫ شخصياً افضّل‬،ً‫ نكتب دائماً في هذا المربع اسماً مميزا‬،Handler ‫ مكتوب اعلى هذا المربع‬،‫الكتابه فيه‬ 48

‫كتابة اسم الداله التي سوف تعالج الحدث‪ ،‬يمكننا تغيير السم إلى اي شئ آخر و لكن حتى ل نزيد السماء‬

‫في برنامجنا نستخدم اسم موحّد‪ ،‬سنستخدم هذا السم في النص البرمجي بحيث نضعه في مصفوفه )او قاموس(‬

‫و يكون السم مفتاح المُدخل و تكون قيمته هي الداله التي يجب استدعاءها‪ ،‬في حالتنا هذه الداله التي سوف‬ ‫تعالج الحدث هي ‪ ButtonClicked‬و التي كتبناها منذ قليل‪ ،‬اذاً قم بوضع ‪ButtonClicked‬‬ ‫في ‪ ،Handler‬احفظ المشروع و لننتقل إلى النص البرمجي‪ ،‬سوف نعدّل على المثال السابق و نحوّل‬

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

‫;)‪window.connect('delete_event',delete_event‬‬ ‫;)‪window.connect('destroy',destroy‬‬ ‫;)‪button.connect('clicked',ButtonClicked‬‬ ‫ننشئ الن المصفوفه التي اتفقنا على إنشائها‪ ،‬تحتوي هذه المصفوفه على مُدخل واحد فقط‪ ،‬له مفتاح بإسم‬ ‫‪ ،ButtonClicked‬و قيمة هذا المفتاح هي الداله ‪ ،ButtonClicked‬ل تخلط بين الثنين‪،‬‬

‫المفتاح هو السم الذي حددناه في ‪ Glade‬و ليس من الضروري ان يكون بنفس إسم الداله‪ ،‬اما السم‬

‫الثاني فهو اسم الداله نفسها‪ ،‬سوف نسمّي هذه المصفوفه بإسم ‪: signals‬‬

‫}‪signals = {"ButtonClicked" : ButtonClicked‬‬ ‫الن حتى تتم عملية الربط بنجاح نقوم بإستدعاء الداله ‪ signal_autoconnect‬و التي تقدّمها لنا مكتبة‬ ‫‪ Glade‬كالتالي ‪:‬‬

‫;)‪g.signal_autoconnect(signals‬‬ ‫الن ربطنا الزر فقط بطريقة ‪ ،Glade‬يمكنك تجربة البرنامج الن و سوف يعمل كما كان‪ ،‬نُكمل عملية الربط‬

‫الن و نربط النافذه بحدث الغلق حتى نتمكن من إغلق البرنامج بشكل صحيح‪ ،‬افتح الملف ‪gui.glade‬‬ ‫مع برنامج ‪ Glade‬مره اخرى‪ ،‬هذه المره اختر النافذه الرئيسيه‪ ،‬انتقل إلى التبويب ‪ ،Signals‬كما تعودنا‬

‫سوف نربط النافذه بالحدثين ‪ delete_event‬والذي تجده في ‪ GtkWidget‬كما اتفقنا سوف نضع‬ ‫‪49‬‬

‫ الحدث الثاني هو‬،delete_event ‫ بنفس اسم الداله و دالتنا هنا هي‬Handler ‫اسم الـ‬

‫ احفظ العمل‬،destroy ‫ هنا بإسم‬Handler ‫ سوف نسمي الـ‬،GtkObject ‫ تجده في‬destroy

.‫و انتقل إلى النص البرمجي‬

‫نضيف مُدخلين جديدين إلى مصفوفة الشارات و بالطبع هذان المُدخلن يخصّان الحدثين الذين اضفناهما قبل‬ : ‫ و بالتالي تصبح مصفوفتنا بعد التعديل كالتالي‬،‫قليل‬

signals = {

"ButtonClicked" : ButtonClicked, "destroy" : destroy, "delete_event" : delete_event}

g.signal_autoconnect(signals); (-: ‫جرّب البرنامج الن و ستجده يعمل وفقاً للصول‬ : ‫الشيفره كامله‬ # -*- coding: utf-8 -*import pygtk; pygtk.require('2.0'); import gtk; import gtk.glade; def delete_event(widget,data): False; def destroy(widget,data=None): gtk.main_quit(); def ButtonClicked(widget,data=None): widget.set_label('‫;)'تم الضغط على الزر‬ g = gtk.glade.XML('gui.glade'); window = g.get_widget('main_window'); button = g.get_widget('hello_world_button'); signals = {

"ButtonClicked" : ButtonClicked, 50

"destroy" : destroy, "delete_event" : delete_event} g.signal_autoconnect(signals); window.show(); button.show(); gtk.main();

51

Glade ‫ نقل برنامج تحويل درجة الحراره إلى‬.1.8.5 ‫ سوف‬،Glade ‫ و كما تعلم فإننا كتبنا واجهته برمجياً و لم نصممها مع‬،‫بالطبع تتذكر المثال الثاني الذي كتبناه‬

‫ النص البرمجي هو‬،‫ و بالطبع سوف نستند إلى نفس النص البرمجي‬،Glade ‫ننقل واجهة هذا البرنامج الن إلى‬ :

# -*- coding: utf-8 -*import pygtk; pygtk.require('2.0'); import gtk; def delete_event(widget,data): False; def destroy(widget,data=None): gtk.main_quit(); def ClickEvent(widget,data=None): global text_entry,status_label; val = text_entry.get_text(); val = float(val); result = (val * 1.8) + 32; result = str(result); status_label.set_text(result); window = gtk.Window(gtk.WINDOW_TOPLEVEL); window.set_title("‫;)"برنامج التحويل‬ window.connect('delete_event',delete_event); window.connect('destroy',destroy); main_box = gtk.VBox(False,0); window.add(main_box); text_entry = gtk.Entry(); main_box.pack_start(text_entry,True,True,0); text_entry.show(); status_label = gtk.Label(""); 52

main_box.pack_start(status_label,True,True,0); status_label.show(); ok_button = gtk.Button("‫;)"موافق‬ main_box.pack_start(ok_button,True,True,0); ok_button.connect('clicked',ClickEvent); ok_button.show(); main_box.show(); window.show(); gtk.main(); : ‫و بعد حذف شيفرة الواجهه الرسوميه يصبح كالتالي‬ # -*- coding: utf-8 -*import pygtk; pygtk.require('2.0'); import gtk; def delete_event(widget,data): False; def destroy(widget,data=None): gtk.main_quit(); def ClickEvent(widget,data=None): global text_entry,status_label; val = text_entry.get_text(); val = float(val); result = (val * 1.8) + 32; result = str(result); status_label.set_text(result); gtk.main(); ‫ و يستخدم صندوق من نوع‬،‫ برنامج تحويل الحراره يستخدم الصناديق‬،Glade ‫نبدأ الن بالتصميم بإستخدام‬ ،‫ إلى النافذه‬VBox ‫ و بالتالي اول شئ نفعله بعد اضافة النافذه الرئيسيه هو اضافة صندوق من نوع‬VBox 53

‫ستجد الصندوق ‪ VBox‬تحت التصنيف ‪ Containers‬تحت اسم ‪ ،Vertical Box‬عندما تضعه‬

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

‫اسفل الخرى‪ ،‬و بالتالي سوف نحتاج إلى ‪ 3‬عناصر‪ ،‬بعد اختيارك للعدد ‪ 3‬و الضغط على موافق تجد إنّ‬ ‫النافذه تقسمت إلى ‪ 3‬اقسام‪ ،‬في القسم الول نضيف مربع نص تجده بإسم ‪ Text Entry‬في القسم‬

‫‪ ،Control And Display‬القسم الثاني نضيف نص )‪ (Label‬والذي تجده بإسم ‪ Label‬في نفس‬

‫قسم مربع النص‪ ،‬و اخيراً نضيف الزر في القسم الثالث‪ ،‬نعدّل الن بعض الخصائص ‪:‬‬

‫نختار الزر و نذهب إلى خصائصه‪ ،‬و نغيّر قيمة الخاصيّه ‪ Label‬إلى "موافق"‪ ،‬بعدها نختار النص )‪(Label‬‬

‫و نذهب إلى خصائصه و نحذف قيمة الخاصيّه ‪ ،Label‬نختار الن النافذه الرئيسيه و نذهب إلى خصائصها و‬ ‫نضع قيمة الخاصيّه ‪ Window Title‬كالتالي ‪" :‬برنامج التحويل"‪.‬‬

‫نقوم الن بعمليات الربط‪ ،‬لنربط النافذه الرئيسيه بالحدثين الذين اعتدنا عليهما و هما ‪ delete-event‬و نضع‬ ‫اسم ‪ delete_event‬للـ ‪ Handler‬و الحدث ‪ destroy‬و نضع اسم ‪ destroy‬للـ‬

‫‪ ،Handler‬بعدها نضيف الحدث ‪ clicked‬للزر الذي اضفناه‪ ،‬و ليكن اسم ‪ Handler‬هذا الزر هو‬

‫‪ ClickEvent‬بنفس اسم الداله المكتوبه مسبقاً‪ ،‬هذا كل ما نحتاجه من ‪ ،Glade‬خزّن الملف و ليكن‬ ‫اسمه ‪gui.glade‬‬

‫ننتقل الن إلى النص البرمجي‪ ،‬قبل كل شئ نستدعي مكتبة ‪: Glade‬‬ ‫;‪import gtk.glade‬‬ ‫اسفل الداله ‪ ClickEvent‬مباشره نبدأ بإستدعاء ملف الواجهه ‪ glade.‬كما تعلمنا مسبقاً‪ ،‬كالتالي ‪:‬‬ ‫;)'‪g = gtk.glade.XML('gui.glade‬‬ ‫لو لحظنا نصنا البرمجي سنلحظ أنّنا بحاجه إلى اداتين فقط هما اللتان سنتحكم بهما‪ ،‬الداة الولى هي مربع‬ ‫النص‪ ،‬و الثانيه هي النص )‪ ،(Label‬و بالتالي سنستخدم الداله ‪ get_widget‬مع هاتين الداتين فقط‪،‬‬ ‫‪54‬‬

: ‫كالتالي‬ window = g.get_widget('window1'); text_entry = g.get_widget('entry1'); status_label = g.get_widget('label1'); (-: show ‫ فنحن نقوم بأخذ النافذه دائماً من اجل استدعاء الداله‬،‫ل تستغرب‬ : ‫ كالتالي‬،ً‫نربط الن الشارات كما تعلمنا مسبقا‬ signals = {

"ClickEvent" : ClickEvent, "destroy" : destroy, "delete_event" : delete_event}

g.signal_autoconnect(signals); : ‫نُظهر النافذه الرئيسيه‬ window.show(); : ‫و بالطبع ل ننسى الداله الرئيسيه التي لم نحذفها من الشيفره السابقه‬ gtk.main(); (-: !‫هذا كل شئ‬ : ‫الشيفره كامله‬ # -*- coding: utf-8 -*import pygtk; pygtk.require('2.0'); import gtk; 55

import gtk.glade; def delete_event(widget,data): False; def destroy(widget,data=None): gtk.main_quit(); def ClickEvent(widget,data=None): global text_entry,status_label; val = text_entry.get_text(); val = float(val); result = (val * 1.8) + 32; result = str(result); status_label.set_text(result); g = gtk.glade.XML('gui.glade'); window = g.get_widget('window1'); text_entry = g.get_widget('entry1'); status_label = g.get_widget('label1'); signals = {

"ClickEvent" : ClickEvent, "destroy" : destroy, "delete_event" : delete_event}

g.signal_autoconnect(signals); window.show(); gtk.main();

56

Glade ‫ نقل الله الحاسبه إلى‬.1.8.6 (-: ‫ أليس كذلك؟‬،ً‫ بسيطا‬Glade ‫كان نقل برنامج التحويل إلى‬ ‫ سوف‬،‫ الشيفره المصدريه هي نفسها السابقه‬،‫لننقل الن الله الحاسبه التي كتبناها في احد القسام السابقه‬ : Glade ‫نعدلها من اجل العمل مع‬

# -*- coding: utf-8 -*import pygtk; pygtk.require('2.0'); import gtk; def delete(widget,data): False; def des(widget,data=None): gtk.main_quit();

def DoMath(widget,data=None): global result,first_number,second_number,operation; f = first_number.get_text(); s = second_number.get_text(); o = operation.get_text(); if f == "" or s == "" or o == "": result.set_text("‫;)"يرجى تعبئة المعلومات المطلوبه‬ else: f = int(f); s = int(s); if o == "+": r = f + s; elif o == "-": r = f - s; elif o == "*": r = f * s; elif o == "/": r = f / s; else: result.set_text("‫العمليه التي قمت بإختيارها‬ ‫;)"غير صحيحه‬ return False; 57

result.set_text(str(r)); win = gtk.Window(gtk.WINDOW_TOPLEVEL); win.set_title("‫;)"آله حاسبه‬ win.connect('delete_event',delete); win.connect('destroy',des); main_box = gtk.VBox(False,0); win.add(main_box); box1 = gtk.HBox(False,0); first_number = gtk.Entry(); box1.pack_start(first_number,True,True,0); first_number.show(); operation = gtk.Entry(); box1.pack_start(operation,True,True,0); operation.show(); second_number = gtk.Entry(); box1.pack_start(second_number,True,True,0); second_number.show(); main_box.pack_start(box1,True,True,0); box1.show(); button = gtk.Button("‫;)"أظهر الناتج‬ button.connect('clicked',DoMath); main_box.pack_start(button,True,True,0); button.show(); result = gtk.Label(); main_box.pack_start(result,True,True,0); result.show(); main_box.show(); win.show(); gtk.main(); : ‫ و اذا حذفنا شيفرة الواجهه تكون الشيفره كالتالي‬،‫هذه هي الشيفره‬

58

# -*- coding: utf-8 -*import pygtk; pygtk.require('2.0'); import gtk; def delete(widget,data): False; def des(widget,data=None): gtk.main_quit(); def DoMath(widget,data=None): global result,first_number,second_number,operation; f = first_number.get_text(); s = second_number.get_text(); o = operation.get_text(); if f == "" or s == "" or o == "": result.set_text("‫;)"يرجى تعبئة المعلومات المطلوبه‬ else: f = int(f); s = int(s); if o == "+": r = f + s; elif o == "-": r = f - s; elif o == "*": r = f * s; elif o == "/": r = f / s; else: result.set_text("‫العمليه التي قمت بإختيارها‬ ‫;)"غير صحيحه‬ return False; result.set_text(str(r)); gtk.main(); ‫ القسم‬،‫ كانت تنقسم إلى ثلث اقسام‬،Glade ‫ كيف كانت واجهة الله الحاسبه حتى نصممها مع‬،‫لنتذكر الن‬

‫ و القسم الخير‬،"‫ القسم الثاني يحتوي على زر مكتوب عليه "اظهر الناتج‬،‫الول يحتوي على ثلث مربعات نص‬ .‫كان يحتوي على نص لظهار الناتج فيه‬

59

‫نبدأ مع ‪ ،Glade‬و كما تعودنا نضيف دائماً النافذه‪ ،‬و لنّ برنامجنا يحتوي على ‪ 3‬اقسام عموديه فإننا سوف‬

‫نستخدم الصندوق ‪ VBox‬و نحدد الرقم ‪ ،3‬القسم الول يحتوي على ثلث مربعات نص بجانب بعضهن‪ ،‬هذا‬

‫يعني إننا بحاجه إلى صندوق داخل هذا القسم و هذا الصندوق من نوع ‪ HBox‬تجده في القسم‬

‫‪ Containers‬بإسم ‪ ،Horizontal Box‬و نختار الرقم ‪ 3‬لننا بحاجه إلى ثلث اقسام افقيه‪ ،‬سوف‬

‫تجد ان القسم الول انقسم إلى ثلث اقسام افقيه عن طريق خطوط ظهرت‪ ،‬نضيف الن مربع نص في كل قسم‬

‫افقي جديد‪ ،‬نذهب الن إلى القسم العمودي الثاني و نضيف زراً جديداً‪ ،‬اخيراً نضيف النص )‪ (Label‬في‬ ‫آخر قسم‪.‬‬

‫نغيّر عنوان النافذه اولً إلى "آله حاسبه" و نربطها بالحدثين ‪ delete-event‬و ‪ destroy‬و لتكن اسماء‬ ‫الـ ‪ Handler‬نفس اسماء الدوال‪ delete ،‬و ‪.des‬‬

‫نغيّر النص في اعلى الزر إلى "اظهر الناتج" و نربط الزر بالحدث ‪ clicked‬و نسمي الـ ‪ Handler‬بإسم‬ ‫الداله ‪.DoMath‬‬

‫نحذف الن النص الموجود في اداة النص‪.‬‬ ‫هذا كل شئ!‪ ،‬خزّن العمل الن و سم الملف بالسم ‪ ،gui‬ننتقل الن إلى النص البرمجي‪ ،‬نستدعي المكتبه‬ ‫اولً ‪:‬‬

‫;‪import gtk.glade‬‬ ‫ثم ملف الواجهه ‪:‬‬ ‫;)'‪g = gtk.glade.XML('gui.glade‬‬ ‫نستخدم الداله ‪ get_widget‬مع مربعات النص الثلثه و نص اظهار النتائج بالضافه إلى النافذه الرئيسيه ‪:‬‬ ‫;)'‪window = g.get_widget('window1‬‬ ‫;)'‪first_number = g.get_widget('entry1‬‬ ‫;)'‪operation = g.get_widget('entry2‬‬ ‫;)'‪second_number = g.get_widget('entry3‬‬ ‫‪60‬‬

result = g.get_widget('label1'); : signal_autoconnect ‫نُنشئ مصفوفة الشارات و نربطها بإستخدام الداله‬ signals = {

"DoMath" : DoMath, "des" : des, "delete" : delete}

g.signal_autoconnect(signals); : ‫اخيراً ل ننسى اضافة السطرين‬ window.show(); gtk.main(); (-: ‫ المور بسيطه أليست كذلك؟‬،Glade ‫هذا كل شئ! تعمل الن الحاسبه الن مع‬ : ‫الشيفره كامله‬

# -*- coding: utf-8 -*import pygtk; pygtk.require('2.0'); import gtk; import gtk.glade; def delete(widget,data): False; def des(widget,data=None): gtk.main_quit(); def DoMath(widget,data=None): global result,first_number,second_number,operation; f = first_number.get_text(); s = second_number.get_text(); o = operation.get_text();

if f == "" or s == "" or o == "": result.set_text("‫;)"يرجى تعبئة المعلومات المطلوبه‬ else: 61

f = int(f); s = int(s); if o == "+": r = f + s; elif o == "-": r = f - s; elif o == "*": r = f * s; elif o == "/": r = f / s; else: result.set_text("‫العمليه التي قمت بإختيارها‬ ‫;)"غير صحيحه‬ return False; result.set_text(str(r)); g = gtk.glade.XML('gui.glade'); window = g.get_widget('window1'); first_number = g.get_widget('entry1'); operation = g.get_widget('entry2'); second_number = g.get_widget('entry3'); result = g.get_widget('label1'); signals = {

"DoMath" : DoMath, "des" : des, "delete" : delete}

g.signal_autoconnect(signals); window.show(); gtk.main(); .‫ مقارنه بالشيفره السابقه‬Glade ‫لحظ مدى بساطة شيفرة‬

62

‫الفصل الثاني‬ ‫مدخل إلى ‪SQLite‬‬

‫‪63‬‬

‫‪ .2.1‬مقدمه‬ ‫هناك الكثير من البرامج التي تقوم بإدارة البيانات‪ ،‬حيث تأخذ مدخلت من المستخدم و تخزنها من اجل‬

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

‫التي تعطي معاني الكلمات‪ ،‬تستخدم هذه البرامج مُحركات قواعد بيانات لتخزين البيانات و التعامل معها‪ ،‬تقدّم لغة‬ ‫‪ Python‬العديد من مُحرّكات قواعد البيانات‪ ،‬و لكننا سوف نستخدم المُحرّك ‪ SQLite‬نظراً لبساطته و‬

‫سهولته‪ ،‬يستخدم هذا المُحرّك لغة ‪ SQL‬من اجل التعامل مع البيانات‪ ،‬أفترض هنا ان لديك إلمام بلغة‬

‫‪ ،SQL‬اذا لم تكن تعرف هذه اللغه انصحك بمراجعة الكتب المُتخصصه او مواقع النترنت فهي مليئه بدروس‬ ‫‪ SQL‬التي تشرح التفاصيل او مراجعة مؤلفنا الخاص بلغة ‪ ،SQL‬استخدم اي محرّك بحث و سوف تجد‬

‫العديد من المواقع على الشبكه‪.‬‬

‫بالطبع قبل البدأ لبد من تثبيت مكتبة ‪ SQLite‬على حاسوبك‪ ،‬سوف تحتاج إلى المكتبه ‪PySQLite‬‬ ‫فراجع موقعها للحصول عليها و على كيفية تثبيتها‪.‬‬

‫‪64‬‬

‫‪ .2.2‬الدوال الساسيه‬ ‫تقدّم المكتبه ‪ PySQLite‬مجموعه من الدوال‪ ،‬و لكننا لن نحتاجها جميعها‪ ،‬سوف نستخدم بعض الدوال‬

‫الساسيه التي يحتاجها اي برنامج يعتمد على ‪ ،PySQLite‬يمكنك كالعاده القراءه فيما بعد اكثر حول الدوال‬ ‫التي تقدمها ‪ PySQLite‬و قد تجد دوال تهمك‪.‬‬

‫نبدأ بالدالتين ‪ connect‬و ‪ ،cursor‬و هما اهم دالتين‪ ،‬الداله الولى و هي ‪ connect‬و تُستخدم‬

‫للتصال بقاعدة البيانات‪ ،‬قاعدة البيانات عباره عن ملف يمكنك تخزينه في اي مكان تشاء‪ ،‬و تمرر مسار هذا الملف‬ ‫إلى الداله ‪ ،connect‬اذا لم تجد الداله ‪ connect‬ملف قاعدة البيانات في المسار المطلوب ستقوم‬

‫بإنشاء ملف قاعدة البيانات‪.‬‬

‫الداله الثانيه هي ‪ cursor‬وهي داله اساسيه جداً‪ ،‬حيث تأخذ مؤشر ‪ SQLite‬و تُعيده إلى متغير‪ ،‬سوف‬

‫نستخدم هذا المتغير فيما بعد في جميع العمليات الخرى‪ ،‬مثل عملية إنشاء الستعلمات او اخذ ناتج عملية‬ ‫الستعلمات‪ ،‬و هذا مثال لستخدام هاتين الدالتين ‪:‬‬

‫;‪from pysqlite2 import dbapi2 as sqlite‬‬ ‫;)"‪connect = sqlite.connect("DB‬‬ ‫;)(‪cur = connect.cursor‬‬ ‫اولً نستدعي مكتبة ‪ SQLite‬في السطر الول‪ ،‬في السطر الثاني نتصل بقاعدة البيانات التي اسمها ‪ ،DB‬بما‬

‫اننا لم نمرر مسار معين و قمنا بوضع اسم قاعدة البيانات فحسب هذا يعني ان قاعدة البيانات ‪ DB‬مُخزنه في‬ ‫نفس المجلد الذي يحتوي على ملف بايثون‪ ،‬السطر الخير يأخذ المؤشر و يخزنه في المتغير ‪ ،cur‬بعدها‬ ‫سنستخدم المتغير ‪ cur‬دائماً من اجل العمليات الخرى‪.‬‬

‫نعرّج على الدالتين ‪ execute‬و ‪ ،fetchall‬بالنسبه للداله الولى وهي ‪ execute‬نستخدمها لتنفيذ‬ ‫‪65‬‬

‫الستعلمات بلغة ‪ ،SQL‬نمرر نص الستعلم كبارامتر للداله‪ ،‬سنستخدم هذه الداله فيما بعد من اجل إنشاء‬

‫الجدوال و من اجل اخذ البيانات و التعديل عليها‪.‬‬

‫الداله الثانيه وهي ‪ fetchall‬نستخدمها دائماً بعد عمل استعلم من نوع ‪ ،SELECT‬بحيث نحصل على‬

‫مصفوفه تحتوي على النتائج من خلل الداله ‪.fetchall‬‬

‫اخيراً الداله ‪ commit‬و نستخدمها اذا قمنا بأي عملية تغيير في قاعدة البيانات‪ ،‬مثلً اضفنا بيانات او حدّثنا‬

‫بيانات او انشأنا جدول جديد‪ ،‬اذا أجرينا اي تغيير في قاعدة البيانات و لم نستخدم هذه الداله ستضيع جميع‬ ‫التعديلت بمجرد إغلق البرنامج‪.‬‬

‫سوف نرى امثله واقعيه لجميع هذه الدوال عندما نكتب مشروعنا في هذا الكتاب إن شاء ال ‪.(-:‬‬

‫‪66‬‬

‫‪ .2.3‬المثال الول ‪ :‬برنامج لتخزين السماء و‬ ‫عرضها‬ ‫اصبح لدينا الن إلمام بكتابة برامج ذات واجهه رسوميه بإستخدام ‪ ،GTK‬و لدينا إلمام مسبق بلغة ‪ ،SQL‬و‬

‫تعرفنا على الدوال الساسيه التي تخص مكتبة ‪ ،SQLite‬اذاً نحن الن جاهزون لكتابة برنامج رسومي يعتمد‬

‫على قواعد البيانات لتخزين معلوماته‪ ،‬سوف نبدأ في مثالنا الول هذا و سوف يكون بسيط جداً‪ ،‬وظيفته هي‬

‫تخزين مجموعه من السماء و عرضها في قائمه‪ ،‬هذا كل ما هنالك‪.‬‬

‫نبدأ اولً بتخطيط جداول قواعد البيانات‪ ،‬نحتاج إلى جدول واحد فحسب‪ ،‬نخزّن في هذا الجدول السماء و‬

‫اسم هذا الجدول هو ‪ ،names‬اما بالنسبه للحقول نحتاج إلى حقلين‪ ،‬الحقل الول هو ‪ id‬و الذي يخزّن‬

‫رقم تعريفي مميز‪ ،‬امّا الحقل الثاني هو ‪ name‬وهو السم الذي نود تخزينه‪.‬‬

‫الن لنتحدث عن واجهة البرنامج‪ ،‬لننا نريد البرنامج بسيطاً لن يكون هناك عدّة نوافذ‪ ،‬اعني اننا لن نستخدمَ نافذة‬

‫منفصلة من اجل إضافة اسم جديد‪ ،‬و لكن نستخدم النافذه الرئيسيه و نضع فيها قائمة السماء و في اسفلها نضع‬

‫الدوات اللزمه لضافة اسم جديد إلى قواعد البيانات‪ ،‬هذا يعني اننا سوف نقسّم واجهة البرنامج إلى خمس‬ ‫اقسام بإستخدام صندوق من نوع ‪ ،VBox‬القسم الول يحتوي على قائمه من نوع ‪ ،TreeView‬القسم‬

‫الثاني يحتوي على نص )‪ (Label‬و نغيره إلى "إضافة كلمة جديده"‪ ،‬الصندوق الثالث يحتوي على مربع نص‬

‫يتم كتابة السم فيه‪ ،‬اما الصندوق الرابع فيحتوي على زر مكتوب عليه "موافق"‪ ،‬و اخيراً الصندوق الخامس‬ ‫يحتوي على نص فارغ يعرض الحاله‪ ،‬مثلً اذا نجحت الضافه يتم عرض ذلك في هذا النص‪ ،‬تكون واجهة‬ ‫البرنامج كالتالي ‪:‬‬

‫‪67‬‬

‫صممها ثم قم بتخزين الملف بإسم ‪ ،gui‬ل ننسى الن ربط النافذه بالدالتين الساسيتين‪ ،‬للحدث‬

‫‪ destroy‬نستخدم داله بإسم ‪ des‬اما الحدث ‪ delete-event‬نستخدم داله بإسم ‪ ،delete‬بعدها‬

‫نربط الزر بالحدث ‪ clicked‬بالداله ‪ ،AddNewName‬نخزّن الواجهه الن ثم نعرّج على الملف‬

‫البرمجي‪ ،‬نكتب الساسيات التي اعتدنا دائماً على كتابتها ‪:‬‬

‫*‪# -*- coding: utf-8 -‬‬‫;‪import pygtk‬‬ ‫;)'‪pygtk.require('2.0‬‬ ‫;‪import gtk‬‬ ‫;‪import gtk.glade‬‬ ‫;‪from pysqlite2 import dbapi2 as sql‬‬ ‫‪def delete(widget,data):‬‬ ‫;‪False‬‬ ‫‪def des(widget,data=None):‬‬ ‫‪68‬‬

‫;)(‪gtk.main_quit‬‬ ‫;)'‪g = gtk.glade.XML('gui.glade‬‬ ‫مناداة المكتبات و كتابة الدالتين ‪ delete‬و ‪ des‬ثم إستدعاء ملف الواجهه و تكليف المتغير ‪ g‬به‪ ،‬نستدعي‬

‫الن الدوات التي سنستخدمها داخل النص البرمجي‪ ،‬سنحتاج إلى التعامل مع القائمه و مع مربع النص و مع‬ ‫النص الثاني الذي يبين الحاله‪ ،‬و بالتالي نستدعي هذه الدوات الثلثه‪.‬‬

‫;)'‪window = g.get_widget('window1‬‬ ‫;)'‪tree = g.get_widget('treeview1‬‬ ‫;)'‪entry = g.get_widget('entry1‬‬ ‫;)'‪status = g.get_widget('label2‬‬ ‫نربط الحداث ‪:‬‬ ‫‪"AddNewName" : AddNewName,‬‬ ‫‪"des" : des,‬‬ ‫}‪"delete" : delete‬‬

‫{ = ‪signals‬‬

‫;)‪g.signal_autoconnect(signals‬‬ ‫قبل كتابة الداله ‪ AddNewName‬لبد من عمل هام جداً‪ ،‬وهو إنشاء قاعدة البيانات و الجدول الذي‬

‫سوف نستخدمه‪ ،‬من الفضل إنشاء ملف برمجي جديد يحتوي على شيفرة إنشاء الجدول‪ ،‬نسمّي هذا الملف بإسم‬ ‫‪ database_create.py‬و يكون محتواه كالتالي‪ ،‬نستدعي اولً مكتبة ‪: SQLite‬‬

‫*‪# -*- coding: utf-8 -‬‬‫;‪from pysqlite2 import dbapi2 as sql‬‬ ‫ثم نتصل بقاعدة بيانات إسمها ‪ sqlite_db‬بإستخدام الداله ‪ connect‬المشروحه سلفاً ‪:‬‬ ‫;)'‪con = sql.connect('sqlite_db‬‬

‫‪69‬‬

‫نخزّن المؤشر في المتغير ‪: cur‬‬ ‫;)(‪cur = con.cursor‬‬ ‫ثم نمرر جملة ‪ SQL‬الخاصه بإنشاء جدولنا المطلوب إلى الداله ‪ execute‬و نستخدم ‪ print‬قبلها حتى‬ ‫نتعرف على حالة النشاء ‪:‬‬

‫;)'))‪print cur.execute('CREATE TABLE names (id int,name varchar(255‬‬ ‫هذا كل شئ‪ ،‬سوف يكون الملف كالتالي ‪:‬‬ ‫*‪# -*- coding: utf-8 -‬‬‫;‪from pysqlite2 import dbapi2 as sql‬‬ ‫;)'‪con = sql.connect('sqlite_db‬‬ ‫;)(‪cur = con.cursor‬‬ ‫;)'))‪print cur.execute('CREATE TABLE names (id int,name varchar(255‬‬ ‫نخزّن الملف بإسم ‪ database_create.py‬و نقوم بتشغيله‪ ،‬بعد تشغيل الملف بنجاح نلحظ أنّ هناك‬ ‫ملف جديد إسمه ‪ sqlite_db‬موجود في مجلد برنامجنا‪ ،‬هذه هي قاعدة البيانات التي تحتوي على الجدول‬ ‫الذي سوف نتعامل معه فيما بعد‪.‬‬

‫نعود الن إلى الملف الساسي للبرنامج وهو ‪ ،main.py‬قبل كتابة الداله ‪ AddNewName‬يجب أنْ‬

‫نتصلَ بقاعدة البيانات كما فعلنا تماماً في الملف ‪ ،database_create.py‬نذهب إلى الملف‬ ‫‪ main.py‬و قبل السطر ‪:‬‬

‫;)'‪g = gtk.glade.XML('gui.glade‬‬ ‫وهو السطر الخاص بإحضار واجهة البرنامج‪ ،‬نضيف السطرين الخاصّين بالتصال في قاعدة البيانات و اخذ مكان‬ ‫‪70‬‬

‫المؤشر ‪:‬‬ ‫;)'‪con = sql.connect('sqlite_db‬‬ ‫;)(‪cur = con.cursor‬‬ ‫لحظ ان اسم قاعدة البيانات هو نفسه ‪ ،sqlite_db‬نعود الن إلى الداله ‪ ،AddNewName‬تقوم هذه‬

‫الداله بأخذ المحتوى الموجود داخل مربع النص‪ ،‬و التحقق اذا كان المحتوى فارغاً اي ان مستخدم البرنامج‬

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

‫المعلومات‪ ،‬اما اذا كان السم مكتوباً سوف نقوم بإضافة السم إلى قاعدة البيانات‪ ،‬نكتب دالتنا في اسفل‬ ‫الداله ‪ ،des‬نبدأ كالتالي ‪:‬‬

‫‪def AddNewName(widget,data=None):‬‬ ‫في داخل الداله سنتعامل مع مربع النص الذي سنأخذ منه السم المطلوب تخزينه‪ ،‬وسنتعامل مع النص الذي‬

‫نعرض الحاله من خلله‪ ،‬كذلك نستخدم قواعد البيانات داخل الداله اذاً نحن بحاجه إلى المتغيرين الخاصّين‬ ‫بقواعد البيانات و هما ‪ con‬و ‪ ،cur‬و بالتالي سوف نستخدم ‪ global‬كما تعودنا مع المتغيرات الربعه‬ ‫‪ entry‬و ‪ status‬و ‪ con‬و ‪ cur‬كالتالي ‪:‬‬

‫;‪global entry,status,con,cur‬‬ ‫نستخدم الن الداله ‪ get_text‬من اجل اخذ المحتوى الموجود في صندوق النص و نخزّن القيمه في متغير‬ ‫نسميه ‪: name‬‬

‫;)(‪name = entry.get_text‬‬ ‫نتحقق الن‪ ،‬اذا كانت القيمه فارغه نطبع رساله للمستخدم ‪:‬‬ ‫‪if name == '':‬‬ ‫;)'يرجى كتابة السم المطلوب'(‪status.set_text‬‬ ‫‪71‬‬

‫اذا لم تكن فارغه نقوم بإضافة السم في قاعدة البيانات‪ ،‬اولً نستخدم الداله ‪ execute‬التي تأخذ منّا جملة‬ ‫‪ SQL‬الخاصه بإضافة البيانات إلى قاعدة البيانات‪ ،‬تكون دائماً دالة ‪ execute‬ضمن المتغير الذي يخزّن‬

‫المؤشر و في حالتنا هذه المتغير هو ‪ ،cur‬اذاً نكتب اولً السطر الخاص بإضافة البيانات ‪:‬‬

‫‪insert = cur.execute('INSERT INTO names(id,name) VALUES(NULL,"' + name‬‬ ‫;)')"' ‪+‬‬ ‫عندما نقوم بأي تعديل على البيانات‪ ،‬سواء اضفنا او حذفنا او حدّثنا البيانات عن طريق الداله ‪،execute‬‬

‫يجب علينا استدعاء الداله ‪ commit‬حتى نسجّل هذه التغييرات بشكل فعلي في قاعدة البيانات‪ ،‬فإذا قمنا‬

‫مثلً بإضافة قيمه جديده في قاعدة البيانات و لم نقم بإستدعاء ‪ commit‬بعدها في حال إغلق البرنامج تذهب‬

‫هذه المعلومات التي اضفناها ول تُسجّل في قاعدة البيانات‪ ،‬و بالتالي انتبه دائماً إلى هذه النقطه حتى ل تضيع‬ ‫المعلومات‪ ،‬تقع الداله دائماً تحت متغير التصال و اسم هذا المتغير في حالتنا هو ‪: con‬‬

‫;)(‪check = con.commit‬‬ ‫الداله ‪ commit‬تُرجع ‪ None‬في حال نجاحها‪ ،‬و بالتالي نتحقق من نجاحها و في حال نجاحها نخبر‬

‫المستخدم بذلك كالتالي ‪:‬‬

‫‪if check == None:‬‬ ‫;)'تم اضافة السم بنجاح'(‪status.set_text‬‬ ‫و من اجل التسهيل على المستخدم حتى يتمكن من اضافة اسماء متعدده اسم تلو الخر نقوم بتفريغ محتوى‬ ‫مربع النص بعد نجاح العمليه كالتالي ‪:‬‬

‫;)''(‪entry.set_text‬‬

‫إنتهينا الن من الداله ‪ AddNewName‬و شيفرتها كالتالي ‪:‬‬ ‫‪def AddNewName(widget,data=None):‬‬ ‫;‪global entry,status,con,cur‬‬ ‫;)(‪name = entry.get_text‬‬ ‫‪72‬‬

‫‪if name == '':‬‬ ‫;)'يرجى كتابة السم المطلوب'(‪status.set_text‬‬ ‫‪else:‬‬ ‫)‪insert = cur.execute('INSERT INTO names(id,name‬‬ ‫;)')"' ‪VALUES(NULL,"' + name +‬‬ ‫;)(‪check = con.commit‬‬ ‫‪if check == None:‬‬ ‫;)'تم اضافة السم بنجاح'(‪status.set_text‬‬ ‫;)''(‪entry.set_text‬‬ ‫انهينا الن جزء هام في البرنامج‪ ،‬تبقى الجزء الثاني وهو عرض قائمه السماء‪ ،‬كما تعلم قمنا بإضافة الداة‬

‫‪ TreeView‬من اجل عرض قائمة السماء‪ ،‬في الحقيقه تستخدم هذه الداة في عملها اسلوب يُسمّى بـ‬

‫‪ Model-View-Controller‬و نُطلق عليه ‪ MVC‬اختصاراً‪ ،‬و حتى نتمكن من التعامل بشكل‬

‫صحيح مع هذه الداة لبد ان نفهم هذا السلوب‪.‬‬

‫يعتمد هذا السلوب على تقسيم العمل إلى ثلث اجزاء‪ ،‬الجُزء الول هو ‪ Model‬و يتخص هذا الجزء‬

‫بالبيانات بمعنى ان البيانات بأنواعها تُخزن داخل هذا الجزء‪ ،‬اما الجزء الثاني وهو ‪ View‬فتقع عليه مسؤولية‬ ‫عرض هذه البيانات المُخزنه في ‪ ،Model‬اما الجزء الثالث وهو ‪ Controller‬فهو مسؤول عن معالجة‬

‫الحداث‪ ،‬الجزءان الول و الثاني هما الهم بالنسبه لنا الن‪ ،‬اذاً يمكننا الستنتاج انّ الهدف الساسي من‬

‫اسلوب ‪ MVC‬هو فصل البيانات عن العرض‪ ،‬الجدير بالذكر انّ اسلوب ‪ MVC‬احد الساليب الهامه و‬

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

‫نعود للداة ‪ ،TreeView‬كما ذكرنا ان هذه الداة تستخدم السلوب ‪ ،MVC‬تُقدّم مكتبة ‪ GTK‬فئه‬

‫اسمها ‪ TreeViewColumn‬هذه الفئه هي المسؤوله عن جزء العرض ‪ ،View‬كما انها تُقدّم فئتين‬

‫‪ ListStore‬و ‪ TreeStore‬و يمكن استخدام احد هاتين الفئتين كـ ‪ Model‬لتخزين البيانات التي‬

‫ستُعرض في القائمه‪ ،‬تُستخدم الفئه الولى من اجل تخزين البيانات التي ستُعرض على شكل قائمه بسيطه‪ ،‬اما‬

‫الفئه الثانيه فتُستخدم من اجل تخزين البيانات التي ستُعرض على شكل شجره او بالحرى التي ستُعرض على‬

‫شكل قائمه تحتوي على هرميات و بيانات تقع تحت بيانات اخرى‪ ،‬و بالطبع لننا سوف نطبع السماء على شكل‬ ‫‪73‬‬

‫قائمه بسيطه يجب علينا استخدام الفئه ‪.ListStore‬‬ ‫نبدأ اولً بكتابة جزء العرض )‪ (View‬مع الداة ‪ ،TreeViewColumn‬كما ذكرنا ان هناك صنف‬

‫بنفس السم و بالتالي من اجل البدء بجزء العرض نقوم بإنشاء كائن من هذه الداة و نُكلّف متغير ليكن اسمه‬ ‫‪ col‬بها كالتالي ‪:‬‬

‫;)‪',gtk.CellRendererText(),text=0‬السم'(‪col = gtk.TreeViewColumn‬‬ ‫نُلحظ انّ البارامتر يحتوي على عنوان العمود الذي يكون في العلى‪ ،‬في كُل مره نُنشئ كائن جديد من الصنف‬

‫‪ TreeViewColumn‬فإننا بهذه الطريقه نقوم بإنشاء عمود جديد ضمن قائمتنا‪ ،‬في حالتنا هذه نحن بحاجه‬

‫إلى عمودٍ واحدٍ فقط لننا نريد عرض السماء فقط‪ ،‬لو كنّا نريد عرض المزيد من المعلومات مثلً السم و رقم‬ ‫الهاتف و البريد اللكتروني‪ ،‬سنحتاج إنشاء ثلث كائنات لتُنشئ بدورها ثلث اعمده‪.‬‬

‫نعود للسطر السابق‪ ،‬البارامتر الثاني غالباً ما يكون ثابتاً‪ ،‬اما البارامتر الثالث تتضح فائدته عندما تكون لدينا عدّة‬

‫اعمده حيث يأخذ العمود الول الرقم ‪ 0‬و العمود الثاني الرقم ‪ 1‬و هكذا‪ ،‬لن نفصّل حالياً هذا الموضوع لننا‬

‫سوف نفصّله فيما بعد‪ ،‬في الوقت الحالي لن لدينا عمود واحد و لن هذا العمود هو الول و بالتالي سوف‬ ‫يأخذ الرقم ‪.0‬‬

‫بعدما انشأنا العمود وهو الجزء المُسمى بـ ‪ View‬بإسلوب ‪ MVC‬الذي تستخدمه الداة ‪TreeView‬‬

‫يجب علينا الن إضافة هذا الجزء إلى الكائن المطلوب‪ ،‬لمزيد من التوضيح نفرض ان واجهة برنامجنا تحتوي على‬ ‫قائمتين‪ ،‬هذا يعني أنّ لدينا كائنان من الصنف ‪ ،TreeView‬و هذان الكائنان بحاجه إلى الجزء ‪ View‬الذي‬ ‫ننشئه من خلل الصنف ‪ ،TreeViewColumn‬لنفرض ان القائمه الولى تحتوي على عمود واحد‬

‫اسمه "البريد اللكتروني" كذلك بالنسبه للقائمه الثانيه لنفرض انها تحتوي على قائمه واحده وهي "رقم‬ ‫الهاتف"‪ ،‬ببساطه يمكننا إنشاء كائنين من الصنف ‪ TreeViewColumn‬كالتالي ‪:‬‬

‫البريد'(‪email_col = gtk.TreeViewColumn‬‬ ‫;)‪',gtk.CellRendererText(),text=0‬اللكتروني‬ ‫‪74‬‬

‫رقم'(‪phone_col = gtk.TreeViewColumn‬‬ ‫;)‪',gtk.CellRendererText(),text=0‬الهاتف‬ ‫و قبلها كما تعلم لبد ان يكون لدينا كائنين من الصنف ‪ ،TreeView‬لنفرض ان الول اسمه ‪first_tree‬‬ ‫و الثاني اسمه ‪ ،second_tree‬و لكن كيف يمكن للبرنامج ان يعرف انّ الكائن ‪ email_col‬يخص‬

‫القائمه الولى ول يخص القائمه الثانيه؟ حسناً ماذا لو قررنا جعل العمود الول هو الذي يحتوي على عمود‬ ‫"رقم الهاتف" و الثاني يحتوي على عمود "البريد اللكتروني"‪ ،‬ببساطه الصنف ‪ TreeView‬يحتوي على‬

‫الداله ‪ append_column‬هذه الداله تحدد الجزء ‪ View‬يخص اي كائن ‪ ،TreeView‬تستقبل‬

‫هذه الداله بارامتر وهو اسم الكائن الخاص بالجزء ‪ ،View‬و بالتالي حتى نضع هذين العمودين كلٌ في قائمته‬ ‫نستخدم هذه الداله كالتالي ‪:‬‬

‫;)‪first_tree.append_column(email_col‬‬ ‫;)‪second_tree.append_column(phone_col‬‬ ‫نعود لبرنامجنا الساسي‪ ،‬من الشرح السابق نستنتج اننا يجب ان نُكلّف الكائن ‪ col‬بالقائمه التي يُمثلها الكائن‬ ‫‪ tree‬كالتالي ‪:‬‬

‫;)‪tree.append_column(col‬‬ ‫هكذا انتهينا من الجزء ‪ ،View‬تبقّى جزء ‪.Model‬‬

‫كما اسلفنا انّ الجزء ‪ Model‬هو الخاص بتخزين البيانات‪ ،‬تُقدّم مكتبة ‪ PyGTK‬صنفين احدهما خاص‬

‫بالقوائم البسيطه العاديه التي استخدمناها في هذا البرنامج )‪ (ListStore‬و الخر خاص بالقوائم المُركبه و‬ ‫المُعقده و التي يُطلق عليها اسم الشجار )‪ ،(TreeStore‬بالطبع سوف نستخدم الصنف ‪ListStore‬‬ ‫حتى نُنشئ الجزء ‪ Model‬كالتالي ‪:‬‬

‫;)‪store = gtk.ListStore(str‬‬ ‫لنشرح الن نظام البارامترات هنا‪ ،‬نلحظ في برنامجنا هذا انّ الجزء ‪ View‬يحتوي على عمود واحد فقط وهو‬ ‫عمود السم‪ ،‬و البيانات التي ستقع تحت هذا العمود حتماً ستكون نصوص )او ‪ string‬كما نسميها‬ ‫‪75‬‬

‫بالبرمجه(‪ ،‬لحظ الن البارامتر الذي مررناه عندما نادينا الصنف ‪ ،ListStore‬قمنا بتمرير بارامتر واحد لن‬

‫لدينا عمود واحد و لن هذا العمود سوف تقع تحته بيانات من نوع النص فهذا البارامتر يوضّح نوع هذه‬

‫المعلومات عن طريق إرسال اسم النوع‪ ،‬حسناً ماذا لو اضفنا عمودنا الثاني و المعلومات التي تقع هي عمر‬

‫صاحب السم‪ ،‬في هذه الحاله سوف نحتاج لتمرير بارامترين الول يخص العمود الول الخاص بالسماء و‬

‫بالتالي سوف نرسل ‪ str‬اما الثاني فيخص العمود الثاني الخاص بالعمار و بالتالي سوف نرسل ‪) int‬رقم‬ ‫صحيح( و هكذا في كل مره نستخدم فيها الصنف ‪ TreeView‬لعرض قوائمنا‪.‬‬

‫هل تتذكر ما فعلناه مع الكائن الذي يمثله المتغير ‪col‬؟ حيث قُمنا بتكليف الكائن ‪ col‬إلى القائمه التي يمثلها‬ ‫المتغير ‪ tree‬عن طريق السطر ‪:‬‬

‫;)‪tree.append_column(col‬‬ ‫لنفس السبب الذي شرحناه يجب علينا كذلك تكليف الكائن ‪ store‬إلى القائمه الرئيسيه و ذلك عن طريق‬ ‫الداله ‪ set_model‬كالتالي ‪:‬‬

‫;)‪tree.set_model(store‬‬ ‫إنتهينا الن من إعداد الجزء ‪ ،Model‬نُريد الن تعبئة البيانات التي سوف تُعرض في القائمه‪ ،‬عندما يفتح‬

‫المُستخدم البرنامج لبد ان تظهر قائمة السماء المُخزنه في قواعد البيانات و يمكنه بعدها اضافة المزيد إن اراد‬ ‫ذلك‪.‬‬

‫كما تعلم لخذ قائمة السماء في قاعدة البيانات سوف نحتاج إلى استخدام مكتبة ‪ ،PySQLite‬نستخدم اولً‬ ‫الداله ‪ execute‬لرسال الستعلم‪ ،‬نحتاج إلى اخذ جميع البيانات المُخزنه في جدول ‪ names‬و بالتالي‬

‫لبد من صياغة إستعلم لتحقيق هذا المطلب بإستخدام لغة ‪: SQL‬‬

‫;)"‪get_names_query = cur.execute("SELECT * FROM names‬‬

‫‪76‬‬

‫نستقبل الن ناتج الستعلم عن طريق الداله ‪ fetchall‬و نُخزنها في ‪ ،names‬الناتج عباره عن مصفوفه ‪:‬‬ ‫;)(‪names = cur.fetchall‬‬ ‫اذا كانت هناك معلومات فعلً فإن حجم ‪ names‬يجب ان يكون اكبر من ‪ ،0‬و بالتالي لبد ان نتحقق اذا‬

‫كان هناك معلومات فعلً ام قاعدة البيانات فارغه كالتالي ‪:‬‬

‫‪if len(names) > 0:‬‬ ‫بعدما تأكدنا ان هناك معلومات فعلً نقوم بقراءة المصفوفه ووضع محتواها داخل الجزء ‪ ،Model‬هذه‬

‫المصفوفه ثنائية البعد‪ ،‬هناك عدّة مُدخلت و التي تُمثل مُدخلت قواعد البيانات وهو عدد متغير يعود إلى‬

‫البيانات التي اضافها المستخدم‪ ،‬و هناك حقلن وهما ‪ id‬و ‪ name‬الموجودان في الجدول ‪ ،names‬ما‬

‫نريده هو قراءة هذه المُدخلت كامله و طباعة محتوى الحقل ‪ name‬منها و يكون ذلك كالتالي ‪:‬‬

‫;‪x = 0‬‬ ‫‪while x < len(names):‬‬ ‫;)]]‪store.append([names[x][1‬‬ ‫;‪x += 1‬‬ ‫كما تلحظ أنشأنا حلقه تعتمد على حجم المصفوفه ‪ names‬و تقرأ البيانات‪ ،‬و استخدمنا الداله‬ ‫‪ append‬التي يقدمها الصنف ‪ ListSore‬لضافة البيانات في داخله‪.‬‬

‫انتهينا الن بشكل كامل من الجزء ‪ Model‬و الشيفره كامله لهذا الجزء ‪:‬‬ ‫;)‪store = gtk.ListStore(str‬‬ ‫;)‪tree.set_model(store‬‬ ‫;)"‪get_names_query = cur.execute("SELECT * FROM names‬‬ ‫;)(‪names = cur.fetchall‬‬ ‫;‪print names‬‬ ‫‪if len(names) > 0:‬‬ ‫‪77‬‬

‫;‪x = 0‬‬ ‫‪while x < len(names):‬‬ ‫;)]]‪store.append([names[x][1‬‬ ‫;‪x += 1‬‬ ‫هكذا نكون قد انتهينا من البرنامج و لكن هناك مشكله واحده‪ ،‬ل يتوقف برنامجنا اذا لم يتم حلّها و لكنه‬

‫سيتحسن في حال حلّها‪ ،‬جرّب اضافة اسم جديد من خلل البرنامج‪ ،‬لحظ انه على الرغم من النجاح في‬

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

‫الحل كما خمّنت بسيط جداً‪ ،‬نتوجّه إلى الداله ‪ AddNewName‬الخاصه بإضافة السماء إلى قاعدة‬

‫البيانات‪ ،‬نُضيف المتغير ‪ store‬ضمن قائمة المتغيرات التي تقع بعد ‪ global‬حتى يصبح السطر كالتالي ‪:‬‬ ‫;‪global entry,status,con,cur,store‬‬

‫نتوجّه الن إلى الشرط الذي يتحقق من نجاح اضافة السم وهو ‪:‬‬ ‫‪if check == None:‬‬ ‫;)'تم اضافة السم بنجاح'(‪status.set_text‬‬ ‫;)''(‪entry.set_text‬‬ ‫نستخدم في نهايته الداله ‪ append‬التي تحدثنا عنها منذ قليل لضافة السم إلى القائمه كالتالي ‪:‬‬ ‫;)]‪store.append([name‬‬ ‫ستصبح الشيفره بهذا الشكل ‪:‬‬ ‫‪if check == None:‬‬ ‫;)'تم اضافة السم بنجاح'(‪status.set_text‬‬ ‫;)''(‪entry.set_text‬‬ ‫;)]‪store.append([name‬‬

‫‪78‬‬

‫ حسناً و‬،‫جرّب الن و لحظ ان السم يُضاف مباشره إلى القائمه بدون الحاجه إلى إغلق البرنامج و تشغيله‬ (-: ‫اخيراً انتهينا من هذا المثال الحمدل‬ : ‫الشيفره الكامله للبرنامج‬ # -*- coding: utf-8 -*import pygtk; pygtk.require('2.0'); import gtk; import gtk.glade; from pysqlite2 import dbapi2 as sql; def delete(widget,data): False; def des(widget,data=None): gtk.main_quit(); def AddNewName(widget,data=None): global entry,status,con,cur,store; name = entry.get_text(); if name == '': status.set_text('‫;)'يرجى كتابة السم المطلوب‬ else: insert = cur.execute('INSERT INTO names(id,name) VALUES(NULL,"' + name + '")'); check = con.commit(); if check == None: status.set_text('‫;)'تم اضافة السم بنجاح‬ entry.set_text(''); store.append([name]); con = sql.connect('sqlite_db'); cur = con.cursor(); g = gtk.glade.XML('gui.glade'); window = g.get_widget('window1'); tree = g.get_widget('treeview1'); entry = g.get_widget('entry1'); 79

status = g.get_widget('label2'); signals = {

"AddNewName" : AddNewName, "des" : des, "delete" : delete}

g.signal_autoconnect(signals); ###### col = gtk.TreeViewColumn('‫'السم‬,gtk.CellRendererText(),text=0); tree.append_column(col); ### store = gtk.ListStore(str); tree.set_model(store); get_names_query = cur.execute("SELECT * FROM names"); names = cur.fetchall(); if len(names) > 0: x = 0; while x < len(names): store.append([names[x][1]]); x += 1; ###### window.show(); gtk.main();

80

‫الفصل الثالث‬ ‫إنشاء مشروع‬

‫‪81‬‬

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

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

‫البيانات و تتم الضافه من خللها‪ ،‬في هذا المشروع تحتوي النافذه الرئيسيه على قائمه بأسماء الموظفين و‬

‫اعمارهم و رواتبهم‪ ،‬في اسفل النافذه ثلث ازرار الول "اضافة موظف" و يفتح نافذه جديده تطلب بيانات‬

‫الموظف الجديد‪ ،‬اما الزر الثاني "تحديث البيانات" بحيث يختار المستخدم الموظف المطلوب من القائمه ثم‬

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

‫اربط الحدثين الساسيين و هما ‪ delete-event‬مع الداله ‪ delete‬و ‪ destroy‬مع الداله ‪ ،des‬و‬ ‫الن اربط احداث الزرار‪ ،‬اربط الحدث ‪ clicked‬لزر اضافة الموظفين مع داله بإسم‬

‫‪ AddNewEmp‬اما زر التحديث فأربط الحدث ‪ clicked‬مع داله بإسم ‪ ،UpdateEmp‬اما‬

‫الزر الخير فأربط الحدث ‪ clicked‬مع داله بإسم ‪ ،DeleteEmp‬خزّن الملف في مجلد البرنامج و‬

‫ليكن اسمه ‪gui.glade‬‬

‫نشرع الن بالشيفره‪ ،‬نبدأ اولً مع الملف ‪ database_create.py‬و الذي يُنشئ جدول قاعدة البيانات‬ ‫كما مر عليك عندما انشأنا المثال الول ‪:‬‬

‫*‪# -*- coding: utf-8 -‬‬‫;‪from pysqlite2 import dbapi2 as sql‬‬ ‫;)'‪con = sql.connect('employees‬‬ ‫;)(‪cur = con.cursor‬‬ ‫‪print cur.execute('CREATE TABLE names (id int,name varchar(255),salary‬‬ ‫‪82‬‬

‫;)')‪int,age int‬‬ ‫لحظ اننا انشأنا قاعدة بيانات اسمها ‪ employees‬تحتوي على جدول به اربع حقول ‪ id‬و ‪ name‬و‬

‫‪ salary‬و ‪ age‬و ل تخفى عليك انواعها و الهدف منها‪ ،‬نشغّل الن الملف ‪database_create.py‬‬

‫حتى يتم إنشاء قاعدة البيانات‪.‬‬

‫نبدأ بملفنا البرمجي ‪ ،main.py‬نبدأ بمناداة المكتبات ‪:‬‬ ‫*‪# -*- coding: utf-8 -‬‬‫;‪import pygtk‬‬ ‫;)'‪pygtk.require('2.0‬‬ ‫;‪import gtk‬‬ ‫;‪import gtk.glade‬‬ ‫;‪from pysqlite2 import dbapi2 as sql‬‬ ‫و دائماً الدالتين ‪ delete‬و ‪(-: des‬‬ ‫‪def delete(widget,data):‬‬ ‫;‪False‬‬ ‫‪def des(widget,data=None):‬‬ ‫;)(‪gtk.main_quit‬‬ ‫نتصل بقاعدة البيانات ‪:‬‬ ‫;)'‪con = sql.connect('employees‬‬ ‫;)(‪cur = con.cursor‬‬ ‫نستدعي الملف ‪ gui.glade‬و نُكلّف المتغير ‪ g‬به ‪:‬‬ ‫;)'‪g = gtk.glade.XML('gui.glade‬‬ ‫سوف نحتاج للتعامل مع جميع الدوات في داخل الشيفره البرمجيه و بالتالي نحتاج للداله ‪: get_widget‬‬ ‫‪83‬‬

window = g.get_widget('window1'); tree = g.get_widget('treeview1'); add_emp = g.get_widget('button1'); update_emp = g.get_widget('button2'); delete_emp = g.get_widget('button3'); add_emp ‫ المتغير‬،‫ مسؤول عن القائمه‬tree ‫ المتغير‬،‫ مسؤول عن النافذه الرئيسيه‬window ‫المتغير‬

‫ المتغير‬،"‫ مسؤول عن زر "تحديث البيانات‬update_emp ‫ المتغير‬،"‫مسؤول عن زر "اضافة موظف‬ ."‫ مسؤول عن زر "حذف موظف‬delete_emp

: ‫نربط الشارات‬ signals = {

"AddNewEmp" : AddNewEmp, "UpdateEmp" : UpdateEmp, "DeleteEmp" : DeleteEmp, "des" : des, "delete" : delete}

g.signal_autoconnect(signals); : ‫نضيف في نهاية الملف‬ window.show(); gtk.main(); ‫ العمود الول خاص‬،‫ نبدأ بإنشاء العواميد في قائمتنا كما تعلمنا عندما انشأنا المثال الول‬،‫قبل السطران السابقان‬ : ‫بالسم‬

col1 = gtk.TreeViewColumn('‫'السم‬,gtk.CellRendererText(),text=0); tree.append_column(col1);

84

‫كما ذكرنا‪ ،‬البارامتر الثالث يحتوي على القيمه ‪ 0‬بالنسبه للعمود الول و كلما زاد عمود نزيد بالرقم‪ ،‬هذا يعني‬

‫ان العمود الثاني ستكون قيمة البارامتر الثالث الخاص به هي ‪ 1‬و الثالث يأخذ القيمه ‪ 2‬و هكذا‪ ،‬نضيف الن‬ ‫العمود الثاني ‪:‬‬

‫;)‪',gtk.CellRendererText(),text=1‬الراتب'(‪col2 = gtk.TreeViewColumn‬‬ ‫;)‪tree.append_column(col2‬‬ ‫ثم العمود الثالث ‪:‬‬ ‫;)‪',gtk.CellRendererText(),text=2‬العمر'(‪col3 = gtk.TreeViewColumn‬‬ ‫;)‪tree.append_column(col3‬‬ ‫انتهينا الن من العواميد او بالحرى الجزء ‪ ،View‬لنبدأ بجزء التخزين ‪ ،Model‬بالطبع سوف نستخدم‬ ‫الصنف ‪ ListStore‬لن قائمتنا عاديه و بسيطه ‪:‬‬

‫;)‪store = gtk.ListStore(str,int,int‬‬ ‫اذا قارنا هذا السطر بالسطر المكتوب بالمثال الول نلحظ اننا اضفنا بارامترين و بالتالي اصبحت لدينا ثلث‬

‫بارامترات مُمرره‪ ،‬اما المثال الول احتوى فقط على بارامتر واحد‪ ،‬لبد و انك تعرف السبب لننا شرحناه‬

‫سابقاً ‪ ،(-:‬السبب هو انه لدينا ثلث عواميد هنا و بالتالي كل بارامتر يخص عمود من هذه العواميد و يحدد‬

‫نوعية البيانات التي تقع تحته‪ ،‬و السطر السابق يُخبر المكتبه بأن العمود الول يحتوي على نصوص‪ ،‬العمود الثاني‬ ‫يحتوي على اعداد صحيحه و كذلك بالنسبه للعمود الثالث‪.‬‬ ‫نُحدد الن الكائن الذي تنتمي إليه هذه المعلومات ‪:‬‬ ‫;)‪tree.set_model(store‬‬ ‫نأخذ قائمة السماء كما فعلنا في المثال الول ‪:‬‬ ‫‪85‬‬

‫;)"‪get_names_query = cur.execute("SELECT * FROM names‬‬ ‫;)(‪names = cur.fetchall‬‬ ‫اذا كان هناك بيانات فعلً اضفها إلى القائمه ‪:‬‬ ‫‪if len(names) > 0:‬‬ ‫;‪x = 0‬‬ ‫‪while x < len(names):‬‬ ‫;)]]‪store.append([names[x][1],names[x][2],names[x][3‬‬ ‫;‪x += 1‬‬ ‫لحظ كيف اصبحت المصفوفه المُمرره إلى الداله ‪ append‬بوجود عواميد متعدده‪ ،‬كما رأيت التعامل مع‬

‫عدّة عواميد موضوع بسيط و طبقناه هنا لتتعرف على مدى بساطته ‪(-:‬‬

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

‫الموظف‪ ،‬الثاني لكتابة راتب الموظف‪ ،‬الخير لكتابة عمر الموظف‪ ،‬و اسفلهم زر مكتوب عليه "موافق" يضغط‬

‫عليه المستخدم عندما ينتهي من تعبئة المعلومات حتى تتم اضافة المعلومات إلى قاعدة البيانات‪ ،‬و اسفل هذا‬

‫الزر نص الحاله الذي يُكتب فيه "تم اضافة المعلومات بنجاح" عند نجاح اضافة المعلومات‪ ،‬صمم هذه النافذه‬ ‫عن طريق ‪ Glade‬و خزّن الملف في مجلد البرنامج و ليكن اسمه ‪emp.glade‬‬

‫لنسمي مربع النص الخاص بإسم الموظف بـ ‪ emp_name‬اما المربع الخاص بالراتب بـ ‪ salary‬اما‬

‫المربع الخاص بالعمر ‪ ،age‬زر موافق نسميه ‪ insert_button‬و اخيراً نص الحاله نسميه ‪،status‬‬

‫لبد من لفت نظرك إلى شئ هام جداً الربط بالحدثين ‪ delete-event‬و ‪ destroy‬هنا غير مهم لن‬

‫نافذتنا التي نصممها الن نافذه فرعيه و ليست نافذه رئيسيه‪ ،‬هذا يعني انها نافذه تظهر عندما نضغط زر محدد في‬ ‫النافذه الرئيسيه‪ ،‬اذا حصل و ربطنا الحدثين في النافذه الفرعيه سوف يؤدي إغلق النافذه الفرعيه إلى إغلق‬ ‫البرنامج بالكامل و هذا الذي ل يجب أنْ يحدثَ‪ ،‬إننا بحاجه إلى الربط بحدث واحد فقط وهو ‪clicked‬‬ ‫‪86‬‬

‫الخاص بزر موافق لنربطه بـ ‪.Emp‬‬ ‫لنتعلم الن كيف يمكننا إظهار هذه النافذه و جعلها تؤدي وظيفتها بعد الضغط على زر "اضافة موظف" في النافذه‬ ‫الرئيسيه‪ ،‬نبدأ اولً بتعريف ‪: AddNewEmp‬‬

‫‪def AddNewEmp(widget,data=None):‬‬ ‫ببساطه لظهار نافذه فرعيه مُخزنه في ملف منفصل نفعل كما فعلنا مع النافذه الرئيسيه تماماً‪ ،‬ننادي الملف‬ ‫الخاص بالنافذه ثم نُكلّفه إلى متغير معين في حالتنا هذه سميناه ‪: add_gui‬‬

‫;)'‪add_gui = gtk.glade.XML('emp.glade‬‬ ‫نُكلّف النافذه بمتغير معين ليكن اسمه ‪: add_window‬‬ ‫;)'‪add_window = add_gui.get_widget('window1‬‬ ‫ثم نطلب إظهار النافذه ‪:‬‬ ‫;)(‪add_window.show‬‬ ‫هل رأيت كم العمليه بسيطه ‪ ،(-:‬نُكمل الن اخذ الدوات التي سنحتاج لستخدامها في الشيفره المصدريه بعد‬ ‫السطر ‪:‬‬

‫;)'‪add_window = add_gui.get_widget('window1‬‬ ‫نأخذ كُل من مربعات النص‪ ،‬و زر الموافقه‪ ،‬و نص الحاله ول يخفى عليك السبب ‪:‬‬ ‫;)'‪emp_name = add_gui.get_widget('emp_name‬‬ ‫;)'‪salary = add_gui.get_widget('salary‬‬ ‫;)'‪age = add_gui.get_widget('age‬‬ ‫‪87‬‬

‫;)'‪status = add_gui.get_widget('status‬‬ ‫نربط الحداث‪ ،‬و لكن ربط الحداث في هذه المره يختلف قليلً‪ ،‬لنرى الشيفره اولً ‪:‬‬ ‫})‪signals = {"Emp" : (InsertEmp,emp_name,salary,age,status‬‬ ‫;)‪add_gui.signal_autoconnect(signals‬‬ ‫من السطر السابقه تستنتج اننا عندما نضغط على زر الموافقه يتم استدعاء داله بإسم ‪ ،InsertEmp‬و لكن‬

‫لماذا في هذه المره بالذات وضعنا الداله داخل مصفوفه مع مجموعه من الكائنات التي عرفناها مسبقاً؟ قبل كل‬

‫شئ لنحدد ما الذي نريد الوصول له من الدوات من داخل الداله ‪ ،InsertEmp‬سوف نحتاج للوصول‬

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

‫الوصول لها من خلل الكائنات التاليه ‪ emp_name :‬لسم الموظف‪ salary ،‬لراتبه‪ age ،‬لعمره‪،‬‬ ‫‪ status‬لنص الحاله‪ ،‬الحل الذي اعتدنا على استخدامه هو استخدام ‪ ،global‬هذا يعني اننا لو اردنا‬

‫تطبيق هذا الحل في حالتنا هذه سوف يكون اول سطر في الداله ‪ InsertEmp‬مشابه للتالي ‪:‬‬

‫;‪global emp_name,salary,age,status‬‬ ‫و لكن هذا السطر لن يعمل في هذه الحاله! لماذا يا ترى؟ ببساطه هذه الكائنات الربعه عباره عن متغيرات محليه‬ ‫)‪ (Local variables‬و ليست متغيرات عامه )‪ ،(Global variables‬المتغيرات المحليه هي‬

‫المتغيرات التي تم تعريفها في داخل داله معينه و لن يستطيع اي جزء آخر من البرنامج الوصول لها بشكل‬

‫مباشر ما عدا الداله نفسها‪ ،‬اما المتغيرات العامه فيتم تعريفها خارج جميع الدوال و بالتالي يمكن لجميع الدوال‬ ‫الوصول لها من خلل وضع اسمها بعد ‪ ،global‬جرب بنفسك المثال التالي ‪:‬‬

‫‪def A():‬‬ ‫;‪y = 10‬‬ ‫;)(‪B‬‬ ‫‪def B():‬‬ ‫;‪global x,y‬‬ ‫;‪print x‬‬ ‫‪88‬‬

‫;‪print y‬‬ ‫;‪x = 5‬‬ ‫;)(‪A‬‬ ‫و لحظ الخطأ الذي يظهر لك‪ ،‬يطبع البرنامج اولً الرقم ‪ 5‬بنجاح و لكنه عندما يصل إلى ‪ y‬فإنه يُظهر خطأ يقول‬ ‫ان ‪ y‬ليست موجوده‪ ،‬هذه هي نفس الحاله التي تمر بنا الن و الحل بسيط ان شاء ال‪ ،‬يكمن الحل في إرسال‬

‫هذه الكائنات على شكل بارامترات إلى الداله ‪ InsertEmp‬و يتم إرسال بارمترات إلى الداله التي نناديها‬

‫عند وقوع الحدث مثلما رأيت منذ قليل‪ ،‬مصفوفه نضع فيها اسم الداله اولً و بعدها البارمترات بالترتيب‪ ،‬يمكننا‬ ‫استخدام الطريقه المشروحه في "الشارات و الدوال ‪ "Callback‬من هذا الكتاب‪ ،‬عموماً سيكون تعريف‬ ‫الداله ‪: InsertEmp‬‬

‫‪def InsertEmp(widget,emp_name,salary,age,status):‬‬ ‫يمكننا القول انّ الداله ‪ AddNewEmp‬خاصه بتجهيز و إظهار نافذة الضافه و الداله ‪InsertEmp‬‬

‫خاصه بإضافة المعلومات التي تزودها بها الداله الولى‪ ،‬لنُكمل‪ ،‬بما اننا نريد الوصول إلى الجزء ‪ Model‬في‬ ‫قائمتنا لننا نريد اضافة الموظف مباشره إلى القائمه عند النجاح في اضافته إلى قاعدة البيانات وبما ان الجزء‬

‫‪ Model‬يُمثله الكائن ‪ store‬وهو عباره عن متغير عام و ليس محلي سوف نقوم بإستخدام ‪ global‬معه‬

‫حتى نصل إليه ‪:‬‬

‫;‪global store‬‬ ‫بغرض الختصار و المثَلَه نُخزّن القيم في متغيرات منفصله ‪:‬‬ ‫;)(‪name_val = emp_name.get_text‬‬ ‫;)(‪salary_val = salary.get_text‬‬ ‫;)(‪age_val = age.get_text‬‬ ‫نقوم بعملية اختبار للقيم و إخبار المستخدم في حال فشل الختبار ‪:‬‬ ‫‪if name_val == '':‬‬ ‫;)'يرجى كتابة السم'(‪status.set_text‬‬ ‫‪89‬‬

‫‪elif salary_val == '':‬‬ ‫;)'يرجى كتابة الراتب'(‪status.set_text‬‬ ‫‪elif age_val == '':‬‬ ‫;)'يرجى كتابة العمر'(‪status.set_text‬‬ ‫نُكمل السلسله الشرطيه بإضافة ‪ else‬و الشيفره الحقيقيه اسفلها‪ ،‬اول سطر يكون الستعلم الذي يُدخل‬ ‫المعلومات إلى قاعدة البيانات ‪:‬‬

‫‪else:‬‬ ‫)‪insert = cur.execute('INSERT INTO names(id,name,salary,age‬‬ ‫‪VALUES(NULL,"' + name_val + '","' + salary_val + '","' + age_val +‬‬ ‫;)')"'‬ ‫بعدها نتأكد من اضافة البيانات إلى قاعدة البيانات ‪:‬‬ ‫;)(‪check = con.commit‬‬ ‫اذا تم إدخال البيانات بشكل صحيح يجب ان نقوم بالتالي ‪ :‬اولً طباعة ان العمليه تمت بنجاح في نص الحاله‬

‫ثم تفريغ المربعات من المعلومات القديمه حتى تكون اضافة معلومات موظف جديد اسهل مثلما فعلنا مسبقاً‪ ،‬و‬

‫اخيراً اضافة البيانات مباشره إلى قائمتنا بدلً من إغلق البرنامج و اعادة فتحه مره اخرى حتى تظهر المعلومات‬ ‫التي اضفناها ‪:‬‬

‫‪if check == None:‬‬ ‫;)'تم اضافة الموظف بنجاح'(‪status.set_text‬‬ ‫;)''(‪emp_name.set_text‬‬ ‫;)''(‪salary.set_text‬‬ ‫;)''(‪age.set_text‬‬ ‫;)])‪store.append([name_val,int(salary_val),int(age_val‬‬

‫لحظ اننا استخدمنا الداله ‪ int‬لتحويل البيانات في هذه المتغيرات إلى نوع ‪.integer‬‬ ‫انتهينا الن من كتابة ميزة اضافة الموظف إلى قاعدة البيانات‪ ،‬تبقى تحرير معلومات الموظف و حذفه‪ ،‬عندما يريد‬

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

‫على معلومات الموظف المُختار‪ ،‬يحرر المستخدم بيانات الموظف كما يشاء ثم يضغط على زر الموافقه ليتم‬

‫تحديث المعلومات في قواعد البيانات‪ ،‬يعمل الحذف بنفس السلوب تقريباً‪ ،‬يختار المستخدم الموظف‬ ‫المطلوب ثم يضغط على زر حذف الموظف فيتم حذف الموظف من قواعد البيانات و من القائمه‪.‬‬

‫لنبدأ اولً بكتابة شيفرة تحرير معلومات موظف‪ ،‬تقدم مكتبة ‪ PyGTK‬صنف يسمى ‪ TreeSelection‬و‬

‫من خلل هذا الصنف يمكننا التعامل مع الصف الذي يختاره المستخدم من القائمه‪ ،‬في حالتنا هنا يختار‬

‫المستخدم الموظف المطلوب تحديث معلوماته ثم يضغط على زر "تحديث البيانات" سيسبب الضغط على هذا‬

‫الزر مناداة داله بإسم ‪ UpdateEmp‬يجب ان تقوم هذه الداله بالتالي ‪ :‬تتعرف على اسم الموظف الذي‬

‫تم اختياره حتى تأخذ بياناته من قاعدة البيانات و حتى تستخدم السم في جملة ‪ SQL‬الخاصه بعملية‬

‫التحديث‪ ،‬حسناً السؤال هنا كيف يمكننا اخذ بيانات الموظف الذي اختاره المستخدم بإستخدام الصنف‬

‫‪ ،TreeSelection‬الصنف الرئيسي ‪ TreeView‬يوفر لنا داله اسمها ‪ get_selection‬تُرجع هذه‬

‫الداله كائن من نوع ‪ TreeSelection‬و يمكننا من خلل هذا الكائن الوصول إلى بيانات الصف المُختار‪،‬‬

‫لنعرّف اولً الداله ‪: UpdateEmp‬‬

‫‪def UpdateEmp(widget,data=None):‬‬ ‫نستخدم الداله ‪ get_selection‬التي تحدثنا عنها منذ برهه لنأخذ الكائن المطلوب و نضعه في متغير نسميه‬ ‫‪: select‬‬

‫;)(‪select = tree.get_selection‬‬ ‫الن‪ ،‬يعتبر المتغير ‪ select‬كائناً من الصنف ‪ ،TreeSelection‬يقدم لنا هذا الصنف داله اسمها‬

‫‪ get_selected‬و التي تُرجع مصفوفه تحتوي على مُدخلين الول من نوع ‪ gtk.TreeModel‬وهو‬

‫الجزء ‪ Model‬من القائمه التي اخترنا منها الموظف و يساوي في حالتنا هذه المتغير ‪ ،store‬اما المُدخل‬

‫الثاني من نوع ‪ gtk.TreeIter‬و الذي يُمثّل الصف الذي اختاره المستخدم من ضمن الصفوف الموجوده‬

‫في قائمتنا ‪:‬‬

‫‪91‬‬

‫;)(‪ar = select.get_selected‬‬ ‫سنستخدم الن الداله التي يوفرها لنا الصنف ‪ TreeModel‬وهي ‪ get_value‬لخذ اسم الموظف‬

‫الذي اختاره المستخدم‪ ،‬تأخذ هذه الداله بارامترين الول هو الصف المطلوب وهو الموجود في ‪ [ar[1‬كما‬

‫ذكرنا‪ ،‬و البارامتر الثاني هو العمود المطلوب‪ ،‬و من خلله يمكننا تحديد ما هي القيمه التي نريد اخذها بالضبط‪،‬‬ ‫اسم الموظف ام عمره ام راتبه‪ ،‬سوف نحتاج إلى اسمه هنا و السم موجود في العمود رقم ‪ 0‬و بالتالي قيمة‬ ‫البارامتر الثاني تساوي ‪ ،0‬يمكننا هنا إما استخدام الكائن ‪ store‬او استخدام ‪ [ar[0‬الذي ارجعته الداله‬ ‫‪ ،get_selected‬حسناً سوف استخدم ‪ [ar[0‬هنا حتى نستفيد منها على القل ‪: (-:‬‬

‫;)‪name = ar[0].get_value(ar[1],0‬‬ ‫اصبح اسم الموظف مُخزناً في المتغير ‪ ،name‬يمكننا استخدام هذا المتغير الن في جملة ‪ SQL‬لخذ‬

‫معلومات الموظف من قواعد البيانات ‪:‬‬

‫‪info_query = cur.execute('SELECT * FROM names WHERE name="' + name +‬‬ ‫;)'"'‬ ‫نُحضر جميع المعلومات و نخزنها في المتغير ‪: info‬‬ ‫;)(‪info = cur.fetchall‬‬ ‫بنفس الطريقه التي فتحنا بها نافذه جديده لضافة موظف جديد نفتح نافذه جديده لعرض بيانات الموظف المُختار‬

‫و السماح بتغييرها‪ ،‬سوف نستخدم نفس النافذه التي صممناها لنافذة اضافة موظف وهي ‪ emp.glade‬لنه ل‬ ‫فرق بينهما بتاتاً ‪:‬‬

‫;)'‪edit_gui = gtk.glade.XML('emp.glade‬‬ ‫نأخذ الدوات التي نحتاج ان نتعامل معها في الشيفره البرمجيه ‪:‬‬

‫‪92‬‬

‫;)'‪edit_window = edit_gui.get_widget('window1‬‬ ‫;)'‪emp_name = edit_gui.get_widget('emp_name‬‬ ‫;)'‪salary = edit_gui.get_widget('salary‬‬ ‫;)'‪age = edit_gui.get_widget('age‬‬ ‫;)'‪status = edit_gui.get_widget('status‬‬ ‫هنا نربط الحدث ‪ Emp‬بالداله ‪ EditEmp‬و هذه الداله مشابهه للداله ‪ InsertEmp‬إلى حد كبير و‬

‫تستقبل نفس البارامترات تقريباً ‪:‬‬

‫})‪signals = {"Emp" : (EditEmp,info[0][1],emp_name,salary,age,status‬‬ ‫;)‪edit_gui.signal_autoconnect(signals‬‬ ‫لحظ البارامتر الول الذي تستقبله الداله ‪ EditEmp‬وهو اسم الموظف المُراد تحرير بياناته‪ ،‬البارامتر‬

‫الثاني هو الكائن الذي يتحكم في مربع النص الخاص بإسم الموظف‪ ،‬البارامتر الثالث هو الكائن الذي يتحكم في‬

‫مربع النص الخاص بالراتب‪ ،‬البارامتر الرابع هو الكائن الذي يتحكم في مربع النص الخاص بالعمر‪ ،‬و البارامتر‬ ‫الخامس هو الكائن الذي يتحكم في نص الحاله‪ ،‬يغير المستخدم البيانات كما يشاء ثم يضغط على زر موافق‬

‫لتحديث المعلومات في قاعدة البيانات و الداله ‪ EditEmp‬هي المسؤوله عن عملية تحديث البيانات في‬ ‫قاعدة البيانات‪.‬‬

‫نعرض الن معلومات الموظف‪ ،‬كُل معلومه في محلها الصحيح ‪:‬‬ ‫;)]‪emp_name.set_text(info[0][1‬‬ ‫;))]‪salary.set_text(str(info[0][2‬‬ ‫;))]‪age.set_text(str(info[0][3‬‬ ‫و اخيراً نُظهر النافذه ‪:‬‬ ‫;)(‪edit_window.show‬‬

‫شيفرة ‪ UpdateEmp‬كامله ‪:‬‬ ‫‪93‬‬

def UpdateEmp(widget,data=None): select = tree.get_selection(); ar = select.get_selected(); name = ar[0].get_value(ar[1],0); info_query = cur.execute('SELECT * FROM names WHERE name="' + name + '"'); info = cur.fetchall(); edit_gui = gtk.glade.XML('emp.glade'); edit_window = edit_gui.get_widget('window1'); emp_name = edit_gui.get_widget('emp_name'); salary = edit_gui.get_widget('salary'); age = edit_gui.get_widget('age'); status = edit_gui.get_widget('status'); signals = {"Emp" : (EditEmp,info[0] [1],emp_name,salary,age,status)} edit_gui.signal_autoconnect(signals); emp_name.set_text(info[0][1]); salary.set_text(str(info[0][2])); age.set_text(str(info[0][3])); edit_window.show(); : EditEmp ‫نبدأ بكتابة الداله الحقيقيه لتحديث المعلومات وهي‬ def EditEmp(widget,old_name,emp_name,salary,age,status): : ‫نأخذ المعلومات الجديده التي كتبها المستخدم‬ name_val = emp_name.get_text(); salary_val = salary.get_text(); age_val = age.get_text(); : ً‫نتأكد من انّ المستخدمَ لم يترك شيئاً خاليا‬ 94

if name_val == '': status.set_text('‫;)'يرجى كتابة السم‬ elif salary_val == '': status.set_text('‫;)'يرجى كتابة الراتب‬ elif age_val == '': status.set_text('‫;)'يرجى كتابة العمر‬

else:

: ‫ و يكون تحتها الستعلم الذي يُحدّث البيانات‬else ‫نكمل هذه السلسله الشرطيه بـ‬

update = cur.execute('UPDATE names SET name="' + name_val + '",salary="' + salary_val + '",age="' + age_val + '" WHERE name="' + old_name + '"'); : ‫نُغيّر المعلومات بشكل فعلي‬ check = con.commit(); : ‫نتحقق من نجاح العمليه و نطبع ذلك للمستخدم‬

‫;)'بنجاح‬

if check == None: status.set_text('‫تم تحديث معلومات الموظف‬ : ‫ الشيفره كامله‬،InsertEmp ‫ لحظ مدى التشابه بين هذه الداله و بين اختها‬،‫هذا كل شئ‬

def EditEmp(widget,old_name,emp_name,salary,age,status): name_val = emp_name.get_text(); salary_val = salary.get_text(); age_val = age.get_text(); if name_val == '': status.set_text('‫;)'يرجى كتابة السم‬ elif salary_val == '': status.set_text('‫;)'يرجى كتابة الراتب‬ elif age_val == '': status.set_text('‫;)'يرجى كتابة العمر‬ else: update = cur.execute('UPDATE names SET name="' + name_val + '",salary="' + salary_val + '",age="' + age_val + '" WHERE name="' + old_name + '"'); 95

‫;)(‪check = con.commit‬‬ ‫‪if check == None:‬‬ ‫تم تحديث معلومات الموظف'(‪status.set_text‬‬

‫;)'بنجاح‬

‫الجزء الخير في هذا المشروع ‪ (-:‬الداله ‪ DeleteEmp‬وهي المسؤوله عن حذف الموظف‪ ،‬يختاره‬

‫المستخدم ثم يضغط على الزر ليحذفه‪ ،‬كما فعلنا تماماً مع ‪ UpdateEmp‬يجب علينا اخذ اسم الموظف‬ ‫الذي نريد حذفه حتى نستخدمه في استعلم الحذف‪ ،‬نعم كما خمّنت تماماً سوف نستخدم الصنف‬ ‫‪ ،(-: TreeSelection‬اولً التعريف ‪:‬‬

‫‪def DeleteEmp(widget,data=None):‬‬ ‫نأخذ اسم الموظف بنفس السلوب السابق ‪:‬‬ ‫;)(‪select = tree.get_selection‬‬ ‫;)(‪ar = select.get_selected‬‬ ‫;)‪name = ar[0].get_value(ar[1],0‬‬ ‫نستخدم المتغير ‪ name‬في الستعلم ‪:‬‬ ‫;)'"' ‪delete = cur.execute('DELETE FROM names WHERE name="' + name +‬‬ ‫نحدّث قاعدة البيانات ‪:‬‬ ‫;)(‪check = con.commit‬‬ ‫حسناً الذي نريده الن بعدما يتم حذف الموظف بنجاح من قاعدة البيانات هو اختفاءه من القائمه كذلك‪ ،‬نستخدم‬ ‫الداله ‪ remove‬التي يقدمها الصنف ‪ ListStore‬لزالة الموظف من القائمه‪ ،‬تحتاج هذه الداله لبارامتر‬

‫واحد وهو الصف المطلوب حذفه و كما تعلم هو موجودٌ في ‪ [ar[1‬و بالتالي شيفرتنا ستكون هكذا ‪:‬‬ ‫‪96‬‬

if check == None: store.remove(ar[1]); : ‫ الشيفره الكامله‬،(-: ‫بفضل ال و توفيقه نكون هكذا انتهينا من هذا المشروع‬

# -*- coding: utf-8 -*import pygtk; pygtk.require('2.0'); import gtk; import gtk.glade; from pysqlite2 import dbapi2 as sql; def delete(widget,data): False; def des(widget,data=None): gtk.main_quit(); def AddNewEmp(widget,data=None): add_gui = gtk.glade.XML('emp.glade'); add_window = add_gui.get_widget('window1'); emp_name = add_gui.get_widget('emp_name'); salary = add_gui.get_widget('salary'); age = add_gui.get_widget('age'); status = add_gui.get_widget('status'); signals = {"Emp" : (InsertEmp,emp_name,salary,age,status)} add_gui.signal_autoconnect(signals); add_window.show(); def InsertEmp(widget,emp_name,salary,age,status): global store; name_val = emp_name.get_text(); salary_val = salary.get_text(); age_val = age.get_text(); if name_val == '': status.set_text('‫;)'يرجى كتابة السم‬ elif salary_val == '': status.set_text('‫;)'يرجى كتابة الراتب‬ 97

elif age_val == '': status.set_text('‫;)'يرجى كتابة العمر‬ else: insert = cur.execute('INSERT INTO names(id,name,salary,age) VALUES(NULL,"' + name_val + '","' + salary_val + '","' + age_val + '")'); check = con.commit(); if check == None: status.set_text('‫;)'تم اضافة الموظف بنجاح‬ emp_name.set_text(''); salary.set_text(''); age.set_text(''); store.append([name_val,int(salary_val),int(age_val)]); def UpdateEmp(widget,data=None): select = tree.get_selection(); ar = select.get_selected(); name = ar[0].get_value(ar[1],0); info_query = cur.execute('SELECT * FROM names WHERE name="' + name + '"'); info = cur.fetchall(); edit_gui = gtk.glade.XML('emp.glade'); edit_window = edit_gui.get_widget('window1'); emp_name = edit_gui.get_widget('emp_name'); salary = edit_gui.get_widget('salary'); age = edit_gui.get_widget('age'); status = edit_gui.get_widget('status'); signals = {"Emp" : (EditEmp,info[0] [1],emp_name,salary,age,status)} edit_gui.signal_autoconnect(signals); emp_name.set_text(info[0][1]); salary.set_text(str(info[0][2])); age.set_text(str(info[0][3])); edit_window.show(); def EditEmp(widget,old_name,emp_name,salary,age,status): name_val = emp_name.get_text(); salary_val = salary.get_text(); age_val = age.get_text(); if name_val == '': 98

status.set_text('‫;)'يرجى كتابة السم‬ elif salary_val == '': status.set_text('‫;)'يرجى كتابة الراتب‬ elif age_val == '': status.set_text('‫;)'يرجى كتابة العمر‬ else: update = cur.execute('UPDATE names SET name="' + name_val + '",salary="' + salary_val + '",age="' + age_val + '" WHERE name="' + old_name + '"'); check = con.commit(); ‫;)'بنجاح‬

if check == None: status.set_text('‫تم تحديث معلومات الموظف‬

def DeleteEmp(widget,data=None): select = tree.get_selection(); ar = select.get_selected(); name = ar[0].get_value(ar[1],0); delete = cur.execute('DELETE FROM names WHERE name="' + name + '"'); check = con.commit(); if check == None: store.remove(ar[1]); con = sql.connect('employees'); cur = con.cursor(); g = gtk.glade.XML('gui.glade'); window = g.get_widget('window1'); tree = g.get_widget('treeview1'); add_emp = g.get_widget('button1'); update_emp = g.get_widget('button2'); delete_emp = g.get_widget('button3'); signals = {

"AddNewEmp" : AddNewEmp, "UpdateEmp" : UpdateEmp, "DeleteEmp" : DeleteEmp, "des" : des, "delete" : delete}

g.signal_autoconnect(signals); ### 99

col1 = gtk.TreeViewColumn('‫'السم‬,gtk.CellRendererText(),text=0); tree.append_column(col1); col2 = gtk.TreeViewColumn('‫'الراتب‬,gtk.CellRendererText(),text=1); tree.append_column(col2); col3 = gtk.TreeViewColumn('‫'العمر‬,gtk.CellRendererText(),text=2); tree.append_column(col3); ### store = gtk.ListStore(str,int,int); tree.set_model(store); get_names_query = cur.execute("SELECT * FROM names"); names = cur.fetchall(); if len(names) > 0: x = 0; while x < len(names): store.append([names[x][1],names[x][2],names[x][3]]); x += 1; ### window.show(); gtk.main();

.‫هذا و الحمدل رب العالمين و صلواته و سلمه على خير المرسلين و آله الطاهرين‬ .‫وال من وراء القصد‬

100

‫ وصلت‬: ‫ملحق أ‬ GTK ‫برامج تستخدم‬ /http://www.gimp.org : ‫ – عنوان الويب‬GIMP ‫برنامج‬

/http://www.abisource.com : ‫ – عنوان الويب‬AbiWord ‫برنامج‬ /http://pidgin.im : ‫ – عنوان الويب‬Pidgin ‫برنامج‬

/http://liferea.sourceforge.net : ‫ – عنوان الويب‬Liferea ‫برنامج‬ /http://www.gnome.org : ‫ – عنوان الويب‬GNOME ‫مشروع‬ /http://www.xfce.org : ‫ – عنوان الويب‬Xfce ‫مشروع‬

/http://gpe.linuxtogo.org : ‫ – عنوان الويب‬GPE ‫مشروع‬

‫وصلت دروس‬ : ‫" على العنوان التالي‬PyGTK 2.0 Tutorial" ‫دروس متكامله بإسم‬

http://www.pygtk.org/pygtk2tutorial/index.html : ‫" على العنوان التالي‬Creating a GUI using PyGTK and Glade" ‫درس بإسم‬

http://www.learningpython.com/2006/05/07/creating-a-gui/using-pygtk-and-glade

101

‫" على العنوان‬Building an Application with PyGTK and Glade" ‫درس بإسم‬ http://www.learningpython.com/2006/05/30/building-an- : ‫التالي‬ /application-with-pygtk-and-glade

‫" على العنوان‬A Beginner's Guide to Using pyGTK and Glade" ‫درس بإسم‬ http://www.linuxjournal.com/article/6586 : ‫التالي‬

‫" على العنوان التالي‬GTK+ and Glade3 GUI Programming Tutorial" ‫درس بإسم‬ http://www.micahcarrick.com/12-24-2007/gtk-glade-tutorial- : part-1.html

: ‫" على العنوان التالي‬Using SQLite in Python" ‫درس بإسم‬

/http://www.devshed.com/c/a/Python/Using-SQLite-in-Python : ‫" على العنوان التالي‬PyGTK tutorial" ‫دروس بإسم‬

/http://zetcode.com/tutorials/pygtktutorial

http://programming-fr34ks.net/ : ‫و الترجمه العربيه للوصله السابقه على العنوان التالي‬ /strikytutorials/pygtktutorial

102

‫قائمة المصادر‬ http://www.pygtk.org/docs/pygtk/index.html : ‫ على العنوان التالي‬PyGTK ‫الدليل الرسمي لـ‬ /http://scentric.net/tutorial : ‫" على العنوان التالي‬GTK+ 2.0 Tree View Tutorial" ‫درس بعنوان‬ /http://glade.gnome.org : ‫ الرسمي على العنوان التالي‬Glade ‫موقع‬ http://www.enode.com/x/ : ‫" على العنوان التالي‬Model-View-Controller Pattern" ‫درس بعنوان‬ markup/tutorial/mvc.html : ‫ الموجوده على العنوان التالي‬PySQLite ‫وثائق‬ http://oss.itsystementwicklung.de/download/pysqlite/doc/sqlite3.html /http://www.gtk.org : ‫ الرسمي على العنوان التالي‬+GTK ‫موقع‬

103