هدفنا هو أن نجعل الأعداد التي ستكتب في كل من الحقل الأول و الثاني تظهر كنتيجة في الحقل الثالث بعد القيام بالعملية الحسابية المطلوبة.
هنا يجب علينا أن نتدكر أن كل زر و كل حقل لديه اسم خاص به سبق و أن قمنا بتحديده عندما أنشئنا الواجهة الرسومية أول مرة. أيضا سنحاول تقسيم البرنامج إلى أجزاء بسيطة بحيث سيكون كل جزء بمثابة وظيفة متخصصة في شيء محدد.
أولا يجب علينا أن نتصور الطريقة التي يمكن من خلالها التعبير على عدد ما، مثل 125.
إحدى هذه الطرق هي (1x100) + (2x10) + (5x1)
أو
القيمة السابقة مضروبة في 10 + العدد الجديد. مثال: X=(X*10) + y
او
أن نعتبر أن كل رقم بمثابة نص يتم إضافته في أخر السطر للقيمة السابقة، مثال: "1"+"2" النتيجة ستكون هي "21"
سأعتمد على الطريقة الأخيرة لبساطتها.
إذن كلما ضغطنا على زر رقم معين سيكتب الرقم الذي يعبر عنه في أخر السطر للقيمة الحالية.
حتى يتمكن كل زر من القيام بذلك يجب أن نحدد ماذا عليه أن يفعل عندما سيتم الضغط عليه. و هذا ما يسمى بالأحداث Events.
الآن سأحاول أن أوضح لكم كيف سيعمل البرنامج بلغة نفهمها نحن ثم بعدها نحولها إلى لغة بايثون:
1. ستظهر الواجهة الرسومية البرنامج.
2. بعدها سيقوم المستخدم بكتابة العدد 935.
3. في كل مرة يتم الضغط على زر ما، يجب عليه أن يقرر في أي حقل (الأول أم الثاني) سيقوم بإضافة العدد الذي عبر عنه إلى العدد المكتوب مسبقا. مثلا إضافة "5" إلى "93"
4. بعد ذلك سيقوم المستخدم بعملية الجمع +
5. تتكرر نفس العملية بالنسبة للعدد الثاني تماما كما في الخطوة الثالثة.
6. عندما يضغط المستخدم على زر = يجب إجراء العملية الحسابية المطلوبة بحيث سيستخدم البرنامج القيمة المتواجدة في الحقل الأول و الثاني ثم يقرر أي نوع من العمليات الحسابية سيقوم بها، ثم يظهر النتيجة في الحقل الثالث.
قبل أن أكتب الشفرة المصدرية سأدكر بأن الأزرار التي تعبر عن 0 حتى 9 إسمها c0 إلى c9
أزرار العمليات الرياضية:
+ opplus
- opminus
* opmulti
/ opdiv
زر = إسمه opequal
زر الفاصلة . opdot
زر المسح opclear
الحقل الأول إسمه value1، الحقل الثاني value2، حقل النتيجة valresult
الشفرة المصدرية للبرنامج هي:
بالنسبة للتغيرات التي حصلت فهي كالتالي:
1. تم إستيراد دالة partial من قسم functools. سيتم الإستعانة بهذه الدالة لربط بين الدوال التي سنضيفها نحن و بين الأحداث (الضغط على الأزرار)
2. تم الإستعانة بمتغيرتين bSwitch التي سنستخدمها لتحديد الحقل الذي سيكتب فيه العدد، و iMathOp لتحديد نوع العملية الحسابية المطلوبة.
3. تم إضافة دالة fAddNbr لتقوم بمهمة إضافة العدد الذي ضغط عليه المستخدم إلى العدد الموجود سابقا، و هذه الدالة قادرة على معرفة أي حقل ستستخدم إعتمادا على متغيرة bSwitch
4. تم إضافة دالة fEntrySwitch التي ستقوم بتغير قيمة المتغيرة bSwitch إلى قيمة صحيح أو خطأ و بتغير قيمة iMathOp إلى قيمة عددية من 1 إلى 4
5. دالة fCalculate التي ستقوم بمعرفة العملية الحسابية المطلوبة إعتمادا على قيمة المتغيرة iMathOp ثم تقوم بإجرائها على قيمة الحقل الأول و الثاني، ثم تضع النتيجة في الحقل الثالث.
6. دالة fClear التي تقوم بمسح محتوى الحقول و تغير قيمة المتغيرتين إلى القيمة المفترضة.
7. دالة fDecimal وظيفتها هو إضافة الفاصلة إلى العدد المتواجد في الحقل الأول أو الثاني، ثم التأكد من عدم إسناد أكثر من فاصلة واحدة إلى نفس العدد.
8. عودة إلى الدالة __init__ و التي سيتم تعديلها حتى تقوم:
8.1. بربط كل زر من أزرار الأعداد بدالة fAddNbr و بالتالي نحصل على وظيفة كتابة الأعداد في الحقلين الأول و الثاني.
8.2. بربط كل زر من أزرار العمليات الحسابية بدالة fEntrySwitch و بالتالي يستشعر البرنامج تغير قيمة المتغيرتين bSwitch و iMathOp
8.3. ربط زر يساوي = بدالة fCalculate التي ستتكلف بحساب النتيجة و وضعها في الحقل الثالث.
8.4. ربط زر الفاصلة بدالة fDecimal التي خصصناها إلى التحكم في الفاصلة.
8.5. ربط زر المسح C بدالة fClear لمسح و إعادة القيم في الحقول و المتغيرتين إلى القيم المفترضة
و بالتالي نحصل على آلة حاسبة قادرة على إجراء عمليات حسابية بسيطة. في التدوينة القادمة سنحاول أن نجعل الآلة الحاسبة تعتمد على حقل واحد كما سندخل بعض التعديلات البسيطة على الشفرة المصدرية.
يالنسبة للأصدقاء الأكثر خبرة في PyQt4 هل لذيكم أي ملاحظة على الطريقة التي إعتمدتها و الشفرة المصدرية التي كتبتها؟
تحديث 1 (14-04-2009): يمكن تحميل الشفرة المصدرية من هنا.
هنا يجب علينا أن نتدكر أن كل زر و كل حقل لديه اسم خاص به سبق و أن قمنا بتحديده عندما أنشئنا الواجهة الرسومية أول مرة. أيضا سنحاول تقسيم البرنامج إلى أجزاء بسيطة بحيث سيكون كل جزء بمثابة وظيفة متخصصة في شيء محدد.
أولا يجب علينا أن نتصور الطريقة التي يمكن من خلالها التعبير على عدد ما، مثل 125.
إحدى هذه الطرق هي (1x100) + (2x10) + (5x1)
أو
القيمة السابقة مضروبة في 10 + العدد الجديد. مثال: X=(X*10) + y
او
أن نعتبر أن كل رقم بمثابة نص يتم إضافته في أخر السطر للقيمة السابقة، مثال: "1"+"2" النتيجة ستكون هي "21"
سأعتمد على الطريقة الأخيرة لبساطتها.
إذن كلما ضغطنا على زر رقم معين سيكتب الرقم الذي يعبر عنه في أخر السطر للقيمة الحالية.
حتى يتمكن كل زر من القيام بذلك يجب أن نحدد ماذا عليه أن يفعل عندما سيتم الضغط عليه. و هذا ما يسمى بالأحداث Events.
الآن سأحاول أن أوضح لكم كيف سيعمل البرنامج بلغة نفهمها نحن ثم بعدها نحولها إلى لغة بايثون:
1. ستظهر الواجهة الرسومية البرنامج.
2. بعدها سيقوم المستخدم بكتابة العدد 935.
3. في كل مرة يتم الضغط على زر ما، يجب عليه أن يقرر في أي حقل (الأول أم الثاني) سيقوم بإضافة العدد الذي عبر عنه إلى العدد المكتوب مسبقا. مثلا إضافة "5" إلى "93"
4. بعد ذلك سيقوم المستخدم بعملية الجمع +
5. تتكرر نفس العملية بالنسبة للعدد الثاني تماما كما في الخطوة الثالثة.
6. عندما يضغط المستخدم على زر = يجب إجراء العملية الحسابية المطلوبة بحيث سيستخدم البرنامج القيمة المتواجدة في الحقل الأول و الثاني ثم يقرر أي نوع من العمليات الحسابية سيقوم بها، ثم يظهر النتيجة في الحقل الثالث.
قبل أن أكتب الشفرة المصدرية سأدكر بأن الأزرار التي تعبر عن 0 حتى 9 إسمها c0 إلى c9
أزرار العمليات الرياضية:
+ opplus
- opminus
* opmulti
/ opdiv
زر = إسمه opequal
زر الفاصلة . opdot
زر المسح opclear
الحقل الأول إسمه value1، الحقل الثاني value2، حقل النتيجة valresult
الشفرة المصدرية للبرنامج هي:
import sys from PyQt4 import QtGui, QtCore, uic from functools import partial class CalcApp(QtGui.QDialog): bSwitch = False iMathOp = 0 def __init__(self, *args): QtGui.QWidget.__init__(self, *args) uic.loadUi("PyCalc.ui", self) self.connect(self.c0, QtCore.SIGNAL("clicked()"), partial(self.fAddNbr, '0')) self.connect(self.c1, QtCore.SIGNAL("clicked()"), partial(self.fAddNbr, '1')) self.connect(self.c2, QtCore.SIGNAL("clicked()"), partial(self.fAddNbr, '2')) self.connect(self.c3, QtCore.SIGNAL("clicked()"), partial(self.fAddNbr, '3')) self.connect(self.c4, QtCore.SIGNAL("clicked()"), partial(self.fAddNbr, '4')) self.connect(self.c5, QtCore.SIGNAL("clicked()"), partial(self.fAddNbr, '5')) self.connect(self.c6, QtCore.SIGNAL("clicked()"), partial(self.fAddNbr, '6')) self.connect(self.c7, QtCore.SIGNAL("clicked()"), partial(self.fAddNbr, '7')) self.connect(self.c8, QtCore.SIGNAL("clicked()"), partial(self.fAddNbr, '8')) self.connect(self.c9, QtCore.SIGNAL("clicked()"), partial(self.fAddNbr, '9')) self.connect(self.opplus, QtCore.SIGNAL("clicked()"), partial(self.fEntrySwitch, True, 1)) self.connect(self.opminus, QtCore.SIGNAL("clicked()"), partial(self.fEntrySwitch, True, 2)) self.connect(self.opmulti, QtCore.SIGNAL("clicked()"), partial(self.fEntrySwitch, True, 3)) self.connect(self.opdiv, QtCore.SIGNAL("clicked()"), partial(self.fEntrySwitch, True, 4)) self.connect(self.opequal, QtCore.SIGNAL("clicked()"), self.fCalculate) self.connect(self.opdot, QtCore.SIGNAL("clicked()"), self.fDecimal) self.connect(self.opclear, QtCore.SIGNAL("clicked()"), self.fClear) def fAddNbr(self, x): if self.bSwitch == False: self.value1.setText(self.value1.text() + x) else: self.value2.setText(self.value2.text() + x) def fEntrySwitch(self, bSwitch, iMathOp): self.bSwitch = bSwitch self.iMathOp = iMathOp def fDecimal(self): if self.bSwitch == False: x = str(self.value1.text()) v = self.value1 else: x = str(self.value2.text()) v = self.value2 if x.find('.') == -1: v.setText(v.text() + '.') def fCalculate(self): if self.iMathOp == 1 : rCalc = float(self.value1.text()) + float(self.value2.text()) elif self.iMathOp == 2: rCalc = float(self.value1.text()) - float(self.value2.text()) elif self.iMathOp == 3: rCalc = float(self.value1.text()) * float(self.value2.text()) elif self.iMathOp == 4: rCalc = float(self.value1.text()) / float(self.value2.text()) else: return None self.valresult.setText(str(rCalc)) def fClear(self): self.bSwitch = False self.iMathOp = 0 self.value1.setText('') self.value2.setText('') self.valresult.setText('') if __name__ == '__main__': app = QtGui.QApplication(sys.argv) widget = CalcApp() widget.show() sys.exit(app.exec_())
بالنسبة للتغيرات التي حصلت فهي كالتالي:
1. تم إستيراد دالة partial من قسم functools. سيتم الإستعانة بهذه الدالة لربط بين الدوال التي سنضيفها نحن و بين الأحداث (الضغط على الأزرار)
2. تم الإستعانة بمتغيرتين bSwitch التي سنستخدمها لتحديد الحقل الذي سيكتب فيه العدد، و iMathOp لتحديد نوع العملية الحسابية المطلوبة.
3. تم إضافة دالة fAddNbr لتقوم بمهمة إضافة العدد الذي ضغط عليه المستخدم إلى العدد الموجود سابقا، و هذه الدالة قادرة على معرفة أي حقل ستستخدم إعتمادا على متغيرة bSwitch
4. تم إضافة دالة fEntrySwitch التي ستقوم بتغير قيمة المتغيرة bSwitch إلى قيمة صحيح أو خطأ و بتغير قيمة iMathOp إلى قيمة عددية من 1 إلى 4
5. دالة fCalculate التي ستقوم بمعرفة العملية الحسابية المطلوبة إعتمادا على قيمة المتغيرة iMathOp ثم تقوم بإجرائها على قيمة الحقل الأول و الثاني، ثم تضع النتيجة في الحقل الثالث.
6. دالة fClear التي تقوم بمسح محتوى الحقول و تغير قيمة المتغيرتين إلى القيمة المفترضة.
7. دالة fDecimal وظيفتها هو إضافة الفاصلة إلى العدد المتواجد في الحقل الأول أو الثاني، ثم التأكد من عدم إسناد أكثر من فاصلة واحدة إلى نفس العدد.
8. عودة إلى الدالة __init__ و التي سيتم تعديلها حتى تقوم:
8.1. بربط كل زر من أزرار الأعداد بدالة fAddNbr و بالتالي نحصل على وظيفة كتابة الأعداد في الحقلين الأول و الثاني.
8.2. بربط كل زر من أزرار العمليات الحسابية بدالة fEntrySwitch و بالتالي يستشعر البرنامج تغير قيمة المتغيرتين bSwitch و iMathOp
8.3. ربط زر يساوي = بدالة fCalculate التي ستتكلف بحساب النتيجة و وضعها في الحقل الثالث.
8.4. ربط زر الفاصلة بدالة fDecimal التي خصصناها إلى التحكم في الفاصلة.
8.5. ربط زر المسح C بدالة fClear لمسح و إعادة القيم في الحقول و المتغيرتين إلى القيم المفترضة
و بالتالي نحصل على آلة حاسبة قادرة على إجراء عمليات حسابية بسيطة. في التدوينة القادمة سنحاول أن نجعل الآلة الحاسبة تعتمد على حقل واحد كما سندخل بعض التعديلات البسيطة على الشفرة المصدرية.
يالنسبة للأصدقاء الأكثر خبرة في PyQt4 هل لذيكم أي ملاحظة على الطريقة التي إعتمدتها و الشفرة المصدرية التي كتبتها؟
تحديث 1 (14-04-2009): يمكن تحميل الشفرة المصدرية من هنا.
جميل جدا والله
ردحذفلكن عن نفسى كنت هفكر فى اتجاه تانى
مثلا استخدام sender فى ال slots والربط بloop للأزرار بدل التكرار طالما اللوجيك واحد وممكن استفادة من eval
صحيح مش لازم تضيف f او i او اى سابقة للأسماءفى رأيى بتقلل وضوح الكود يمكن مفيدة مع البرمجة ل Win32 مثلا لكن مش مفيدة فى الحالة دى
وبردو iMathOp انت ممكن تستخدم enumeration
http://programming-fr34ks.net/smf/articles-12/enums-in-python/
حاجة لفتت نظرى
class CalcApp(QtGui.QDialog):
انت اشتقيت من QDialog فإزاى يتسمى ال CalcApp ؟
فى انتظار الجزء القادم ^_^
شكرا على هذه الملاحظات. فعلا كنت سأعتمد على بعض منها في التدوينة الجديدة.
ردحذفلكن لم أفهم بالتحديد ما قصدته ب إشتقاق Qdialog و CalcApp
اللى قصدته ان فى Qt يوجد نوع واحد من التطبيق QApplication واى حد هيقرا اسم CalcApp هيجى فى باله انك ورثت ال QApplication بعكس CalcDialog -لأنك ورثت من QtGui.QDialog- او CalcWindow
ردحذفشكرا لك على هذه الملاحظة القيمة. هل تعرف/تملك كتاب/مصدر يتناول مثل هذه الملاحظات/نصائح؟
ردحذفكتاب C++ GUI Programming with Qt 4
ردحذفو كتاب Rapid GUI Programming with Python and Qt
والأمثلة اللى بتبقة مع Qt/PyQt وشرحها اللى فى ال Assistant مليئة بالأفكار وازاى تبرمج بطريقة تتكامل مع Qt
اتمنى لك التوفيق