>> الصفحة الرئيسية >> الجزء الثاني >> الدرس الثالث:تعريف slot جديدة

الأقسام الرئيسية

 التنصيب والاعداد التنصيب والاعداد
 دروس متقدمة دروس متقدمة
 سلسلة دروس للمبتدئين سلسلة دروس للمبتدئين
 اساسيات لغة سي++ اساسيات لغة سي++
 مقالات ZetCode مقالات ZetCode
 

جديد الدروس

 الوحدة QtUiTools (واجهة المستخدم ديناميكية التوليد)
التاريخ 04/07/2009 الوحدة QtUiTools (واجهة المستخدم ديناميكية التوليد)
 Qt and Phonon
التاريخ 04/07/2009 Qt and Phonon
 تتمة الرسائل ومربعات الحوار في qt
التاريخ 04/07/2009 تتمة الرسائل ومربعات الحوار في qt
 مدخل الى xml في Qt
التاريخ 04/07/2009 مدخل الى xml في Qt
 الإدخال والإخراج لبيانات الفئات
التاريخ 04/07/2009 الإدخال والإخراج لبيانات الفئات
 

الدرس الثالث:تعريف slot جديدة

بعد ان تعرفنا على كيفية الوراثة من QWidget و كيفية تقسم البرنامج الى عدة ملفات ،،
نعود الان مجددا الى المشكلة العنيدة ، كيف نعرف slot ؟


لتعريف slots او signals جديدة ، يجب وضع العبارة Q_OBJECT في اول الاعلان عن الفئة ، وبالتحديد في الملف الذي يحمل الامتداد .h ، دلالة على ان هذه الفئة تريد تعريف اشارات ودوال slots جديدة.
هذه العبارة Q_OBJECT هي عبارة عن ماكرو Macro ، يبحث عنها مترجم داخلي في Qt يسمى moc وهي اختصار لـ
Meta Object Complier .


هذا المترجم وظيفته البحث عن ملفات الرأس التي تحمل العبارة Q_OBJECT ، ثم يقوم يتحويل ملفات الرأس المطابقة الى ملفات تبدأ بـ moc_ وتحمل الامتداد .cpp ، حتى يستطيع مترجم سي++ القياسي التعامل معها.

من شروط هذا المترجم moc هو وجود ملف رأس منفصل للاعلان عن الفئة التي تريد تعريف signal/slot جديدة ، كذلك وجود العبارة Q_OBJECT.

هل عرفت اثبات نظرية "عزل الواجهة عن التطبيق" !! .

سندرس الان فكرة تعريف signals/slots جديدة ، على مثال بسيط ، ثم بعدها سنطبق على المثال الذي اختتمنا به الجزء الاول.

المثال الاول :
سنكتب برنامج لتحويل الحروف من كبيرة upper case الى صغير lower case .

شكل المخرج يجب ان يكون كالاتي:



تحليل سريع :
كما يظهر على الصورة ، يوجد كائنين من QLineEdit و كائنين من QLabel ، وكذلك يوجد مخطط افقي
ومخطط عمودي .
كائني QLineEdit متزامنين ، بحث ان تم كتابة حرف في اي منهما ، فسوف يظهر على الكائن الاخر،ولكن بعكس حالة الحرف .
نريد ان نربط اي حدث في QLineEdit يرسل في حالة التعديل عليه ، ارجع الى التوثيق ، ستجد ان هناك حديثين متشابهان تقريبا ، الاول textChanged والاخر textEdited ، سنتخار الاخير ، لانه اثناء التعديل على كائن QLineEdit نريد ان يظهر الحرف في الكائن الاخر.

اذا باعتبار نموذج الربط هذا :

  1. connect(sender, SIGNAL(signal), receiver, SLOT(slot));


فان المرسل هو احد كائنات QLineEdit ، ولنسمه upperCaseLineEdit ، والمستقبل هو الكائن الاخر ولنسمه lowerCaseLineEdit.
الكائن الاول سيرسل حدث textChanged والذي يأخذ السلسة التي تم كتابتها فيه كوسيط.

ترسل السلسلة المكونة من احرف كبيرة ، الى الكائن الثاني والذي يجب ان ينفذ دالة ما بحيث تودي الغرض .

نرجع الى التوثيق ، نبحث عن جميع ال slots ،،، لن نجد ما نريد !
فقط اقرب شيء هو دالة تعيين نص setText . وهذه سوف تقوم بكتابة النص نفسه !

اذا نحتاج الى slot جديد بحيث يحول من الاحرف الكبيرة الى احرف صغيرة ،،
وكذلك slot اخر لكي يحول من حرف صغير الى كبير .



الشفرة البرمجية :

الملف conventor.h:


  1. 1- #ifndef CONVENTOR_H
  2. 2- #define CONVENTOR_H
  3. 3-
  4. 4- #include <QWidget>
  5. 5-
  6. 6- class QLineEdit;
  7. 7-
  8. 8- class Conventor:public QWidget
  9. 9- {
  10. 10- Q_OBJECT
  11. 11-
  12. 12- public:
  13. 13- Conventor(QWidget* parent=0);
  14. 14-
  15. 15- public slots:
  16. 16- void setUpper(const QString&);
  17. 17- void setLower(const QString&);
  18. 18-
  19. 19- private:
  20. 20- QLineEdit* upperCaseLineEdit;
  21. 21- QLineEdit* lowerCaseLineEdit;
  22. 22- };
  23. 23-
  24. 24- #endif // CONVENTOR_H


ملف الرأس conventor.h تم فصله عن التطبيق وذلك لاننا نريد تعريف slots ، كذلك تم الوراثة من الفئة
QWidget ، لكي نضمن جميع خصائص اي widget.

السطر 6: يحوي اعلان عن فئة QLineEdit ، وذلك لاننا نريد تعريف مؤشر من هذه الفئة .
ومن الممكن ان نستبدل هذا الاعلان بعملية تضمين ملف الرأس QLineEdit ، ولكن لان عملية التضمين
ستأخذ وقتا من المترجم اثناء قراءة الشفرة ، لذا من الافضل دائما وضع اعلان عن الفئة اذا كنا نريد تعريف مؤشر منها .

السطر 10 : هذا السطر يحوي الاعلان عن الماكرو ، وهذه اشارة للمترجم moc بان هذا الملف بحاجة
الى ترجمة بواسطته ، النتيجة من عملية الترجمة هو الملف moc_conventor.cpp .

السطر 15: يحوي على محدد لم تستعمله من قبل وهو slots .
وجميع الدوال المعرفة تحته تعتبر دوال slot ،اي يمكن ان نربطها مع حدث ما في عبارة connect.

مستوى حماية المحدد public or private or protected ، لا تاثير لها اذا كنت تستخدم هذه الدوال
للربط فقط ، اي في عبارة connect.
اما اذا كنت تريد استخدامها كدوال تعين setter ، فيجب الانتباه الى مستوى الحماية.

الاسطر 16 و 17 :
لدينا دالتين ، الاولى تقوم بكتابة السلسة المررة اليها كأحرف كبيرة في الكائن upperCaseLineEdit.
اما الدالة الاخر ، تقوم بكتابة السلسة المررة اليها كأحرف صغيرة في الكائن lowerCaseLineEdit.

الاسطر 19 الى 21 :
تم وضع المحدد الخاص private وذلك لتعريف الكائنين upperCaseLineEdit و lowerCaseLineEdit.

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



الملف conventor.cpp :

  1. #include <QLineEdit>
  2. #include <QLabel>
  3. #include <QGridLayout>
  4.  
  5. #include "conventor.h"
  6.  
  7. Conventor::Conventor(QWidget* parent):
  8. QWidget(parent)
  9. {
  10. // Create Widgets
  11. upperCaseLineEdit=new QLineEdit;
  12. lowerCaseLineEdit=new QLineEdit;
  13. QLabel* upperCaseLabel=new QLabel("Upper Case:");
  14. QLabel* lowerCaseLabel=new QLabel("Lower Case:");
  15.  
  16. // Establish Connection
  17. connect(upperCaseLineEdit,SIGNAL(textEdited(const QString&)),this,SLOT(setLower(const QString&)));
  18. connect(lowerCaseLineEdit,SIGNAL(textEdited(const QString&)),this,SLOT(setUpper(const QString&)));
  19.  
  20. // Create Layouts
  21. QGridLayout* layout=new QGridLayout;
  22. layout->addWidget(upperCaseLabel,0,0);
  23. layout->addWidget(upperCaseLineEdit,0,1);
  24.  
  25. layout->addWidget(lowerCaseLabel,1,0);
  26. layout->addWidget(lowerCaseLineEdit,1,1);
  27.  
  28. setLayout(layout);
  29. setWindowTitle("Upper/Lower case Conventor v1.0");
  30. }
  31.  
  32. void Conventor::setUpper(const QString& str)
  33. {
  34. QString tmp=str.toUpper();
  35.  
  36. if( upperCaseLineEdit->text() == tmp )
  37. return;
  38.  
  39. upperCaseLineEdit->setText(tmp);
  40. }
  41.  
  42. void Conventor::setLower(const QString& str)
  43. {
  44. QString tmp=str.toLower();
  45.  
  46. if( lowerCaseLineEdit->text() == tmp )
  47. return;
  48.  
  49. lowerCaseLineEdit->setText(tmp);
  50. }


على نفس المنهج المتبع دائما ، حيث نبدأ بانشاء ال widgets ، ثم وضع الخصائص ، ثم الربط
ثم انشاء المخططات وتعبئتها بال widgets ، واخيرا وضع المخطط على كائن الفئة.

الامر الذي قد يبدو جديدا هذه المرة ، هو في الربط او تأسيس الاتصال ..
حيث ان الكائن المستقبل اصبح هو this ، ونعلم ان this هي مؤشر لكائن الفئة .

اذا بمعنى اخر ، فان عبارة الربط تقول ، انشيء اتصال بحيث ان المرسل هو upperCaseLineEdit والحدث المرسل هو textEdited ، اما المستقبل هو كائن هذه الفئة ، والدالة التي يجب تنفيذها هي setLower .

لاحظ انه يجب ان تتطابق انواع الوسائط في عملية الربط .

كذلك انشئ اتصال اخر بين lowerCaseLineEdit ، وكائن هذه الفئة .

وبالنسبة للمخطط ، فلم نستخدم لا الافقي والا العمودي ، حيث استخدمنا النوع الشبكي ، وسندرسه لاحقا .

نأتي لدالة setUpper ، حيث تستقبل هذه الدالة سلسلة نصية .
هدف هذه الدالة هو وضع قيمة للكائن upperCaseLineEdit ، لكن بعكس حالة الاحرف.

تستخدم الدالة toUpper والتي ستقوم بعملية التحويل .

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

اما الدالة setLower ، فهي تعمل بنفس فكرة الدالة السابقة ولكن تحول الاحرف من كبير الى صغير.

اهم شيء يجب ان تتذكره دائما عند كتابة تعريف اي دالة slots هو شرط التوقف !
حيث بدون هذا الشرط سنقع في مشكلة كبيرة !


انظر الى هذين السطرين لتعرف المشكلة !

  1. connect(upperCaseLineEdit,SIGNAL(textEdited(const QString&)),this,SLOT(setLower(const Qstring&)));
  2.  
  3. connect(lowerCaseLineEdit,SIGNAL(textEdited(const QString&)),this,SLOT(setUpper(const Qstring&)));



ولنأخذ هذا السيناريو ،،
نفرض انك قمت بالكتابة على upperCaseLineEdit ، في هذه الحالة سوف "تبعث" اشارة تدل على وجود تعديل ،، هذا الاشارة قمنا بربطها مع الدالة setLower .
وفي حالة عدم وجود الشرط في الدالة setLower فانها ستقوم بتحويل السلسة الى lower case ثم تضع النتيجة في الكائن lowerCaseLineEdit .
فورا سيتم "بعث" اشاره تدل على وجود تعديل في الكائن lowerCaseLineEdit ، وهذه الاشارة قمنا
بربطها مع الدالة setUpper.
وفي حالة عدم وجود الشرط في الدالة setUpper فانها ستقوم بتحويل السلسلة الى upper case ثم تضع النتيجة في الكائن upperCaseLineEdit .

من جديد سيتم ارسال اشاره ......الخ.
لذلك لا بد من وجود شرط التأكد في اي دالة slots ، خاصة في حالة التزامن بين الكائنات.



الملف main.cpp :

  1. #include <QApplication>
  2. #include "conventor.h"
  3.  
  4. int main(int argc,char* argv[])
  5. {
  6. QApplication app(argc,argv);
  7.  
  8. Conventor c;
  9. c.show();
  10.  
  11. return app.exec();
  12. }



من الان وصاعدا ، لن اذكر اسم الملف main.cpp مرة اخرى .
وذلك لان محتوياته اصبحت معروفة جدا ، ولن تتغير الا في حالات نادرة.
مجرد تضمين لملف الرأس للفئة التي تم كتابتها ، ثم انشاء كائن منها ، واستدعاء الدالة show.



ملاحظة على الشفرة السابقة :

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

نذهب الى المثال الاخر ..

ا.هـ

إسم الكاتب تاريخ الإضافة التقييم / المقيمين زيارات الدرس
SudaNix 19/09/2008 27 / 3 534

الأكثر زيارة

 دليل تنصيب اطار عمل Qt ، حزمة MinGW ، بيئة التطوير QDevelop
الزيارات 2320 دليل تنصيب اطار عمل Qt ، حزمة MinGW ، بيئة التطوير QDevelop
 اعداد وتنصيب Qt
الزيارات 2161 اعداد وتنصيب Qt
 دليل تنصيب اطار عمل Qt ، حزمة MinGW ، بيئة التطوير Eclipse
الزيارات 2128 دليل تنصيب اطار عمل Qt ، حزمة MinGW ، بيئة التطوير Eclipse
 C++ In a Nutshell
الزيارات 1904 C++ In a Nutshell
 التطوير السريع للتطبيقات Rapid Application Development
الزيارات 1862 التطوير السريع للتطبيقات Rapid Application Development
 

الأكثر تصويتـا

 اعداد وتنصيب Qt
نتيجة التصويت 40 من 5 شخص اعداد وتنصيب Qt
 تخطيط البرامج Program Layout
نتيجة التصويت 40 من 6 شخص تخطيط البرامج Program Layout
 التطوير السريع للتطبيقات Rapid Application Development
نتيجة التصويت 29 من 4 شخص التطوير السريع للتطبيقات Rapid Application Development
 الدرس الثالث:تعريف slot جديدة
نتيجة التصويت 27 من 3 شخص الدرس الثالث:تعريف slot جديدة
 دليل تنصيب اطار عمل Qt ، حزمة MinGW ، بيئة التطوير Eclipse
نتيجة التصويت 22 من 3 شخص دليل تنصيب اطار عمل Qt ، حزمة MinGW ، بيئة التطوير Eclipse
 
 

سكربت story-script v1 برمجة bwady.com تطوير SudaNix