هذه المقالة تفترض دراية ولو بسيطة في لغة البرمجة بايثون. إن كانت هذه المقالة أول عهدك بالبرمجة ننصح بقراءة أي من المقالات الأخرى
هذه المقالة تناقش البدهيات فقط. للمزيد يمكنك قراءة
ملاحظة:
سنستعمل في هذه المقالة
لا يجوز استعمال PyQt4 من riverbankcomputing.co.uk إلا في برمجيات رخصتها متوافقة مع GPL. لذا إن كانت الرخصة غير متطابقة مع GPL عليك إما أن تشتري رخصة مملوكة من الشركة سابقة الذكر أو استعمال مشروع pyside وقد كان يعيب pyside أنه لم يصدر نسخة لنظام ويندوز إلا أن هذا قد انتهى الآن هناك نسخة متوفرة منه للعديد من الأنظمة بما فيها ويندوز.
استخدم أي محرر نصوص لكتابته ثم احفظه باسم hello1.py مثلا
#! /usr/bin/python # -*- coding: UTF-8 -*- import sys from PyQt4 import QtGui app = QtGui.QApplication(sys.argv) n, ok = QtGui.QInputDialog.getText(None, u"مرحبا يا عالم!", u"فضلا اكتب اسمك:") if ok and n: QtGui.QMessageBox.information(None, u"أهلا بك في Qt", u"مرحبا بك يا "+n+u"!") else: QtGui.QMessageBox.information(None, u"أهلا بك في Qt", u"أنت لم تكتب اسما")
لتشغيل البرنامج اكتب
python hello1.py
أو امنح البرنامج صلاحيات التنفيذ ثم انقر عليه نقرا مزدوجا.
أول سطرين في البرنامج
#! /usr/bin/python # -*- coding: UTF-8 -*-
يتكرران في كل البرامج. الأول يحدد مسار مفسر اللغة إن كنت تجهله أو كان مختلفا اكتب
#! /usr/bin/env python
أما الثاني فيحدد الترميز التلقائي المستخدم في حفظ الملف من أجل سلاسل يونيكود النصية في كل الأمثلة سنستعمل UTF-8.
السطرين اللاحقين يقومان باستيراد الحزم والوحدات الإضافية (المكتبات) في هذا المثال هما sys
و QtGui
import sys from PyQt4 import QtGui
ونلاحظ أن هناك صيغتان لتلك العملية. الطريقة الأولى هي استيراد حزمة إلى في فضاء التسمية الخاص بها أي أنه لو كان هناك متغير اسمه argv موجود في الحزمة sys سيكون اسمه sys.argv. أما الصيغة الثانية فتجلب شيء من الحزمة إلى فضاء التسمية الحالي فإن كان هناك وحدة اسمها QtGui في حزمة PyQt4 فإنها لن تكون PyQt4.QtGui بل QtGui.
الوحدة sys تحتوي على الكثير من الأمور المتعلقة بالبيئة التي يعمل فيها البرنامج ومنها argv التي تحتوي المعاملات التي نمررها للبرنامج من سطر الأوامر. وهي تلزمنا حتى نمررها كما هي ل Qt.
الوحدة الثانية هي QtGui حيث تحتوي على الفئات classes المتعلقة بالواجهة الرسومية في Qt
كل برنامج يستعمل Qt يجب أن ينشئ كائن من نوع QApplication ويكون ذلك هكذا على سبيل المثال
app = QtGui.QApplication(sys.argv)
للحصول على مدخلات من المستخدم يمكننا استخدام
تعيد هذه الدوال الساكنة قيمتين هما القيمة التي اختارها المستخدم ثم نحدد هل أتم المستخدم الإدخال أم نقر على إلغاء Cancel
وفي هذا المثال نحن استخدمنا QInputDialog.getText للسؤال عن اسم المستخدم.
n, ok = QtGui.QInputDialog.getText(None, u"مرحبا يا عالم!", u"فضلا اكتب اسمك:")
حيث وضعنا اسم المستخدم في المتغيّر n وبيان إتمام العملية في المتغيّر ok. أما المعاملات التي مررناها فهي على الترتيب
ثم قمنا بفحص النتيجة بالأداة الشرطية if هكذا (انتبه لوجود : في نهاية الجملة)
if ok and n:
وهنا عملنا علاقة “و” المنطقية بين شرطين هما:
فإن تطابق الشرطان نعرض نافذة معلومات. توفر لنا Qt عدة دوال لهذه الغاية تختلف فيما بينها بالأيقونة الموجودة على جانبها وهي
ونحن في مثالنا استخدمنا QtGui.QMessageBox.information
لعرض الترحيب بالمستخدم باسمه الذي أدخله سابقا
QtGui.QMessageBox.information(None, u"أهلا بك في Qt", u"مرحبا بك يا "+n+u"!")
أما المعاملات التي مررناها فهي على الترتيب :
في هذا البرنامج سنعمل حلقة تظل تدور تسأل عن طول المستطيل وعرضه ثم تعرض مساحته ثم تعيد الكرة إن رغب المستخدم في ذلك.
#! /usr/bin/python # -*- coding: UTF-8 -*- import sys from PyQt4 import QtGui app = QtGui.QApplication(sys.argv) reply=QtGui.QMessageBox.Yes while(reply == QtGui.QMessageBox.Yes): w, ok = QtGui.QInputDialog.getDouble(None, u"مساحة المستطيل!", u"فضلا ادخل طول المستطيل:") if ok: h, ok = QtGui.QInputDialog.getDouble(None, u"مساحة المستطيل!", u"فضلا ادخل عرض المستطيل:") if ok: a=w*h QtGui.QMessageBox.information(None, u"مساحة المستطيل", u"مساحة المستطيل الذي أدخلته تساوي "+str(a)) reply=QtGui.QMessageBox.question(None, u"مساحة المستطيل", u"هل تريد المحاولة من جديد؟", QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
أغلب الكود يشبه الكود السابق فلا داع لتكرار شرحه.
قمنا في السطر التالي باستهلال قيمة للمتغير reply لتكون QtGui.QMessageBox.Yes
reply=QtGui.QMessageBox.Yes
الهدف من هذا هو أن نلزم البرنامج دخول الحلقة التكرارية while
والتي تعني “طالما” حيث أننا اشترطنا فيها أن تكون تلك القيمة التي تجعل الحلقة تظل تدور.
while(reply == QtGui.QMessageBox.Yes):
لاحظ استخدام فحص المساواة بعملية == وليس المساواة المفردة = فهذه الأخيرة تعني الإحلال assignment أي وضع قيمة في متغير.
القيمة QtGui.QMessageBox.Yes
تأتي من رد المستخدم على سؤال “هل تريد المحاولة من جديد؟”
reply=QtGui.QMessageBox.question(None, u"مساحة المستطيل", u"هل تريد المحاولة من جديد؟", QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
فإن أجاب المستخدم بالضغط على “لا” فإن قيمة reply ستكون QtGui.QMessageBox.No عندها ستخرج الحلقة التكرارية while لأن المساواة مع QtGui.QMessageBox.Yes لم تتحقق.
أما الجزء المسؤول عن عرض النتيجة فلا يكاد يختلف عن المثال السابق
a=w*h QtGui.QMessageBox.information(None, u"مساحة المستطيل", u"مساحة المستطيل الذي أدخلته تساوي "+str(a))
لاحظ أننا قمنا بحساب المساحة بضرب الطول في العرض ثم حفظها في المتغير a الذي سيحتوي الجواب عددا نسبيا Float ولعرض الرقم قمنا بتحويله إلى نص عبر str ثم أضفناه إلى نهاية النص “مساحة المستطيل الذي أدخلته تساوي ”
عند تشغيل Qt4 Designer تحصل على صندوق حوار كما في الشكل
انقر على نافذة رئيسية MainWindow ثم إنشاء Create فتحصل على نافذة للتصميم كما في الشكل التالي:
لاختبار التصميم وتشغيله اضغط على زر CTRL+R
بعد الانتهاء من التصميم يتم حفظه في ملف ينتهي ب .ui مثلا test.ui.
يتوفر في Qt عدد من ودجات الأزرار كما في الصورة ومنها:
وتوفر عدد من ودجات الإدخال مثل
وهناك ودجات مخصصة للعرض دون التحرير مثل
وهناك ودجات تعرض عناصر متعددة مثل
وهناك عدد من الحاويات وهي ودجات تستخدم لتجميع عدد من الودجات معا مثل
اعمل مشروع جديد ونافذة رئيسية جديد ثم اختر النافذة الرئيسية بالنقر على مكان خال فيها ثم اذهب إلى صندوق محرر الخصائص Property Editor ثم حدد عنوان النافذة windowTitle ليكون “محول وحدات القياس” وحيث أن قائمة الخصائص طويلة يمكنك ترتيبها هجائيا بالنقر على الترتيب Sort الموجود على أيقونة إعداد محرر الخصائص في الزاوية. أو يمكنك البحث عن جزء من الخاصية التي تريد تعديلها مثل كلمة title كما في الصورة
قم بإضافة ملصق عنوان ثم تغيير نصه عبر Text أو عبر النقر المزدوج
أكمل تصميم واجهة البرنامج بإضافة بقية اللصقات ثم أضف صندوق Combo box ثم إضافة الوحدات المطلوب التحويل بينها عبر النقر بالزر الأيمن ثم Edit Items ثم أضف Double Spin Box ثم أضف الزر Button لتبديل الوحدتين.
قم بتجربة التصميم عبر CTRL+R أو عبر Form ثم Preview أو Preview in ثم اختر السمة Style التي تريد.
احفظ التصميم السابق باسم جديد ثم انقر بالزر الأيمن على مكان خال في النافذة الرئيسية ثم اختر Layout Vertically حتى تحصل على ما يشبه الصورة المرفقة ثم قم بتكبير أو تضغير النافذة ولاحظ الفرق بنفسك (أيضا اضغط على CTRL+R لتجريب التصميم)
وبهذا يصبح البرنامج مكون من صفوف منتظمة مكدسة فوق بعضها. وحيث أن أغلب البرامج لا تكون مجرد صفوف يمكن أن يكون كل صف فيها عبارة عن تكديس أفقي للعناصر وذلك بوضع Horizontal layout كما في الخطوات التالية
إن من أجمل المخططات هي التي تتم عبر Grid Layout حيث هناك شبكة تشبه الجدول تتوزع العناصر فيها بين نقاطها مع إمكانية عمل توسع span على أكثر من صف أو أكثر من عمود.
لتحويل التصميم الأولي إلى مخطط الجدول حمل الملف الأول ثم احفظه باسم جديد ثم انقر بالزر الأيمن على مكان خال في النافذة الرئيسية للتصميم ثم اختر من القائمة Layout ثم Layout in grid
قم بإعادة تحريك الودجات مرة أخرى حتى تتأكد من أنها موضوعة في مكانها الصحيح (عندما تجرها إلى خلية في صف موجود مسبقا تضيء باللون الأحمر وعندما تعمل صف أو عمود جديد يظهر خط ممتد باللون الأزرق)
إذا أردت أن يمتد زر “تبديل الوحدتين” على قدر كل الأعمدة قم بجر طرفه الأيمن لتوسيعه وستجد أنه يتوسع فقط بقدر الأعمدة (لا يوجد عمود ونصف)
كل ما عليك هو استعمال الأداة pyuic4
كما في هذا المثال
pyuic4 uitest.ui -o uitest.py
حيث:
uitest.ui
هو اسم ملف التصميمuitest.py
هو اسم ملف بايثون الناتجكل ما علينا الآن هو عمل برنامج يستورد النافذة الرئيسية من الوحدة الناتجة عن ملف ui (وهي في مثالنا وحدة uitest) ثم يعمل فئة مشتقة منها ويعمل كائن من تلك الفئة.
import sys from PyQt4 import QtGui from uitest import Ui_MainWindow class MainWindow(QtGui.QMainWindow, Ui_MainWindow): def __init__(self): QtGui.QMainWindow.__init__(self) Ui_MainWindow.__init__(self) self.setupUi(self) app = QtGui.QApplication(sys.argv) w = MainWindow() w.show() sys.exit(app.exec_())
السطر التالي يستورد النافذة الرئيسية Ui_MainWindow من التصميم. لاحظ أن اسمها يكون مسبوقا ب Ui_ ثم الاسم الذي حددته للكائن في برنامج التصميم
from uitest import Ui_MainWindow
ثم قمنا بعمل فئة مشتقة من فئة QtGui.QMainWindow الموجودة في PyQt4 و التي جاءت من التصميم Ui_MainWindow
class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
تم نأتي لكود استهلال كائن من هذه الفئة
def __init__(self): QtGui.QMainWindow.__init__(self) Ui_MainWindow.__init__(self)
وأول ما يقوم به هو استهلال الفئات التي تم اشتقاقه منها. ويجوز أن تأخذ دالة الاستهلال init الخاصة بهذه الفئة معاملات خاصة بها لا علاقة لها بأصليها QtGui.QMainWindow و Ui_MainWindow.
ثم نستدعي دالة setupUi التي تبني التصميم
self.setupUi(self)
وخارج الفئة نعمل الكود الذي ينفذ عند تشغيل البرنامج وهو استهلال التطبيق QApplication ثم إنشاء كائن من فئة النافذة الرئيسية التي صممناها ثم إظهارها
app = QtGui.QApplication(sys.argv) w = MainWindow() w.show()
ثم ننفذ التطبيق عبر الدالة app.exec_ ونرسل الكود الذي تعيده للنظام عبر sys.exit هكذا
sys.exit(app.exec_())
انقر بالزر الأيمن على مكان خال في النافذة الرئيسية للتطبيق ثم اختر Change Singals/Slots ثم انقر على زر الإضافة أسفل الأتلام slots وأضف سطر يحتوي
fromValueChanged(double)
انقر على صندوق إدخال المقدار الذي نريد تحويله وتأكد من أن اسم الكائن ObjectName هو fromValue ثم من محرر الإشارات والأتلام Signal/Slot Editor انقر على زر الإضافة ثم غيّر المرسل <sender> إلى fromValue ثم غيّر <signle> إلى valueChanged التي تأخذ double ثم غير المستلم <receiver> إلى النافذة الرئيسية MainWindow ثم غير التلم <slot> إلى التلم الذي أضفناه للنافذة الرئيسية في الخطوة السابقة وهو
fromValueChanged(double)
قم بحفظ ملف التصميم ui ثم أعد توليد ملف python بواسطة
pyuic4 converter.ui -o converter.py
اعمل ملف نصي جديد يحتوي الكود الذي يشغل التصميم ومحتوياته هي
#! /usr/bin/python # -*- coding: UTF-8 -*- import sys from PyQt4 import QtGui from converter import Ui_MainWindow class MainWindow(QtGui.QMainWindow, Ui_MainWindow): def __init__(self): QtGui.QMainWindow.__init__(self) Ui_MainWindow.__init__(self) self.setupUi(self) def fromValueChanged(self, v): self.toValue.setText(str(v*1.609344)) app = QtGui.QApplication(sys.argv) w = MainWindow() w.show() sys.exit(app.exec_())