البرامج الرسومية في السي ++

تتضمن كل من بورلاند سي++ وتيربو سي++ كما كبيرا من الدوال المكتبية الرسومية للاستخدام في برامج الدوس . هذه الدوال تفتح عالما مليئا بالإثارة , فعن طرقها يمكنك وضع كل ما تشاء تقريبا علي الشاشة . وهناك تلاءم خاص بين البرمجة الكائنية والبرامج الرسومية , لأن كثيرا من الأشكال كمتعددات الأضلاع يمكن أن تمثل ككائنات , كما أن البرامج الرسومية تتيح وسيلة جيدة لرؤية الكائنات متمثلة بالحياة .

وتقع الدوال الرسومية في مجموعتين أساسيتين ؛ تلك التي تعمل في النمط النصي text mode والتي تمثل في النمط الرسومي graphic mode وتتولي دوال النمط النصي إظهار النصوص والمحارف الرسومية علي الشاشة بمرونة أكبر مما تتيحه دوال الإظهار العادية . ويمكنك استخدام هذه الدوال حتي في برامج النصوص الصرفة (غير الرسومية ) وسوف تعالج هذه المجموعة من الدوال أولا .

وتحتاج دوال النمط النمط الرسومي شاشة ملونة وبطاقة موائم EGA, ) adapter أو VGA ) وعليك أن تنظر في شرح الدالة initgraph() في مستندات شركة بورلاند لكي تحصل علي قائمة بالموائمات المطلوبة . وتتيح لك هذه الدوال رسم النقاط والخطوط والأشكال الهندسية كالدوائر والمستطيلات وأن نضع الألوان علي الخطوط والمساحات والقيام بالعديد من النشاطات الأخري المتعلقة بالرسم .

والهدف من هذا الفصل أن نمكنك من استخدام تلك الدوال , ولن نتعرض إلي موضوعات أساسية خاصة باللغة ذاتها فهي إذن فرصة استرخاء ومراجعة لما مر بك من مفاهيم , كالفئات والكائنات والتوارث .

ولن نقدم بطبيعة الحالة كل الدوال الرسومية , بل سنعرض لأهمها ونري كيف تستخدم في بيئة البرمجة الكائنية . علي أننا سنضيع الأساليب للكثير من المواقف المختلفة , مما يمكن من الإستفادة من بقية الدوال .

ولا تعمل الدوال المكتبية في هذا الفصل مع البرنامج EasyWin فهي محتاجة لشاشة دوس كاملة وليس نافذة فإذا كنت مستخدما بورلاند سي ++ فعليك العمل علي منصة الدوس كما وضحنا في مقالات سابقة .

كما أن أغلب الدوال المستخدمة هنا علي عكس بقية الدوال المكتبية لا تقبل النقل علي بيئة أخري كاليونكس أو حتي بيئات السي++ خلاف بورلاند وتيربو .

رسومات النمط النصي

عند إظهار الرسومات بالنمط النصي text mode ( أحيانا يطلق عليه console mode ) تقسم الشاشة إلي كواضع تقع عليها المحارف والتقسيم النمطي هو 80 عامود x 25 صف وتوجد تقسيمات أخري مثل 40 x 25 , 80 x 43 وغيرها . ودوال الإظهار , مثل cou<< تعمل في النمط النصي ولكن بورلاند تقدم دوال أخري تيسر كتابة النصوص في نوافذ ولفظ نافذة في هذا المعني يقصد به مساحة محددة يظهر فيها النص . والنوافذ أداة طيبة في البرامج التي تستخدم الواجهات الرسومية Graphical User Interface GUI , مثل البيئة المتكاملة للبرمجة التي تستخدمها في كتابة برامج هذه المقالات .

ويوجد أسلوبان لرسومات النمط النصي , أولا تمشيا مع مفهوم البرمجة الكائنية تقدم بورلاند الفئة constream التي تساعدك علي إنشاء النوافذ وثانيا هناك دوال مكتبية قائمة بذاتها يمكنك استخدامها في مضمار البرمجة الكائنية أو الهيكلية طيقا لرغبتك وسوف نعرض للأسلوبين .

الفئة constream

تعطيك الفئة constream طريقة كائنية سهلة لإنشاء نوافذك في النمط النصي وهي فئة مشتقة من الفئة iostream التي سوف نتناولها في الفصل الرابع عشر . ولكن الفئة constream أنسب للإستخدام في البرامج الرسومية , فمن المنطقي أن نتناولها هنا .

ويمثل كائن الفئة المذكورة نافذة غير ظاهرة الحدود , مجرد مساحة تحتوي النص وعلي ذلك فليس بمقدورك رؤيتها إلي أن تبدأ الكتابة فيها . وتتيح لك الدوال المنتمية للفئة أن تتحكم في مساحتها , وألوانها وتحريك المشيرة عليها .

ولكي تستخدم هذه الفئة عليك أن تضمن برنامجك الملف constrea.h الذي يحتوي إعلان الفئة ودوالها وعلي العكس من النمط الرسومي والذي يحتاج لدالة مخصوصة لكي تستهل النظام الرسومي لا يحتاج النمط النصي لإعداد مسبق حيث تكون بالفعل عند مشيرة الدوس .

وإليك برنامجا يستخدم هذه الفئة وهو ينشئ نافذتين مستخدما الدالة window() لتحديد أبعادهما , ويكتب نصا علي الأولي , ثم نصا أخر علي الثانية ثم نصا ثالثا علي الأولي .

conwin.cpp


 


// conwin.cpp


// uses the constream class


// UCS Laboratories


#include <constrea.h>   // for constream class


#include <conio.h>


 


void main()


   {


   clrscr();            // clear entire screen


 


   char s1[] = "The disk drive is jammed\n\


or on fire, or the CPU\n\


is flooded.  Correct the\n\


situation and try again.\n\


Press Enter to continue: ";


 


   char s2[] = "This is a string that will wrap at the right \


edge of the window, probably breaking words inappropriately \


in the process.";


 


   char s3[] = "Everything is under control\n\


now, and we are carrying\n\


out our mission. You have\n\


nothing to worry about.";


 


   constream w1, w2;            // make two windows


 


   w1.window(25, 6, 55, 18);    // window 1, middle of screen


   w2.window(1, 1, 25, 10);     // window 2, upper left corner


 


   w1 << s1;                    // output text to window 1


   getch();                     // wait for keypress


   w1.clrscr();                 // clear window 1 only


 


   w2 << setclr(BLUE) << s2;    // output blue text to window 2


   getch();                     // wait for keypress


   w2.clrscr();                 // clear window 2 only


   


   w1 << s3;                    // output new text to window 1


   getche();                     // wait for keypress


   }




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



الدالة window()



الدالة الرئيسية لفئة constream هي الدالة window() وهي تتقبل أربعة معاملات لتحديد حدود النافذة الأربعة : أعلي وأسفل ويسار ويمين وفي الشاة 80x 25 ترقم الصفوف من 1 إلي 25 والأعمدة من 1 إلي 80 وتظهر النصوص التي تكتب بدوال أخري في هذه المساحة بدءا من اليسار العلوي وتطوي النصوص تلقائيا عندما تصل إلي حدود النافذة .



مؤثر << مزاد التحميل



أحد الخصائص المدهشة للفئة constream هي أنه بمقدورك أن استخدم المؤثر << لكتابة في النافذة وكما ستعرف في الفصل 14 يمكن ذلك لأن الفئة المذكورة مشتقة من الفئة ostream .



دوال أخري للفئة comstream



نستخدم أيضا دالة أخري هي (clear screen ) clrser() لمسح ما علي النافذة قبل الكتابة فيها ولاحظ أنه عندما تستخدم هذه الدالة كدالة منتمية فإنها تمسح ما علي النافذة فقط وليس الشاشة بأكملها .



ولدينا أيضا دالة أخري فقط باقية هي textmode() وهي تستخدم للتحويل من النمط الرسومي ويبين الجدول دوال الفئة constream



جدول بعض دوال الفئة constream





























الدالة



استخدامها



Clrser()



مسح ما بالنافذة



Window()



تحديد حدود النافذة



Textmode()



تغيير النمط





المتحكمات manipulators



تضم الفئة أيضا مجموعة من المتحكمات للعمل مع المؤثر << وفي برنامج conwin.cpp استخدامها احدها setclr لتغيير لون النص علي الشاشة الثانية ويبين الجدول بعض هذه المتحكمات كما يبين الجدول الألوان المتاحة في النمط النصي والألوان من 0 إلي 7 فقط هي المتاحة للخلفية .



جدول المتحكمات



























































المتحكم



وظيفته



Setclr(int)



اختيار اللون



Setbk(int)



اختيار لون الخلفية



Setcrsrtype(int) (NUNCURSOR, _SOLIDCUROR, _NORMALCURSOR



اختيار شكل المشيرة



Clreol



مسح إلي أخر السطر



Highvideo



نص علي الوضوح



Normvideo



نص عادي الوضوح



Delline



محو سطر



Lnsline



إدخال خط





جدول ألوان النمط النصي









































































































الرقم



اللون



الرقم



اللون



0



أسود



8



رصاصي غامق



1



أزرق



9



أزرق فاتح



2



أخضر



10



أخضر فاتح



3



سيان



11



سيان فاتح



4



أحمر



12



أحمر فاتح



5



ماجنتا



13



ماجنتا فاتح



6



بني



14



أصفر



7



رصاصي فاتح



15



أبيض







128



وميض





استخدام الدوال القائمة بذاتها



يمكن الوصول إلي ما تحققه الفئة Constram بواسطة مجموعة من الدوال القائمة بذاتها stand-alone الموجودة بالملف conio.hللوصول لبعض الإمكانيات التي تقدمها الفئة المذكورة . ففي المثال التالي سوف ننشئ نافذة وتكتب فيها نصوصا كما فعلنا في المثال السابق , منشئين فئة بمعرفتنا .






homewin.cpp


 


// homewin.cpp


// home-made text window class


// UCS Laboratories


#include <conio.h>      // for window(), cputs()


 


class textwin           // text window class


   {


   private:


      int left, top, right, bottom;      // window dimensions


   public:


                         // set window size


      void setsize(int l, int t, int r, int b)


     {


     left=l; top=t; right=r; bottom=b;


     }


      void erase()                       // erase the window


     {


     window(left, top, right, bottom);


     clrscr();


     }


      void drawtext(char* str)           // draw text in window


         {


     window(left, top, right, bottom);


     cputs(str);


         }


     void color(int c)                   // change text color


        {


        textcolor(c);


        }


   };


 


void main()


   {


 


   char s1[] = "Keep an eye out at all times\n\r\


for stragglers from Major\n\r\


Higsby's brigade.";


 


   char s2[] = "We can't be too careful.\n\r\


You remember what happened to\n\r\


those poor chaps at Khartoum.";


 


   char s3[] = "As dusk approaches we\n\r\


may hear to the south\n\r\


the sound of elephants.";


 


   textwin a, b;              // define two text windows


 


   clrscr();                  // clear entire screen


 


   a.setsize(25, 6, 55, 18);  // window in middle of screen


   a.drawtext(s1);            // draw text in it


   getch();                   // wait for keypress


   a.erase();                 // erase window


 


   b.setsize(1, 1, 30, 10);   // window in upper left corner


   b.color(BLUE);             // set color to blue


   b.drawtext(s2);            // draw text in it


   getch();                   // wait for keypress


   b.erase();                 // erase window


 


   a.color(WHITE);            // restore color


   a.drawtext(s3);            // draw new text in first window


   getch();                   // wait for keypress


   }




أنشأنا في البرنامج فئة أسميناها textwin تحمل بعض إمكانيات من التي للفئة comstream (القليل منها في الواقع) ولفئتنا دوال تقابل دوال الفئة comstream في وظائفها ؛ فلحجم النافذة setsize() مقابل window كما تقابل الدوال erase() , color() الدالتين clrscr(), setclr() علي الترتيب , أما الدالة drawtext() فتقابل مؤثر << مزاد التحميل .



من داخل دالتنا textwin() نستخدم بعض الدوال المكتبية القائمة بذاتها stand-alone الرسومية الخاصة بالنمط النصي , سوف نتعرض لها . يجب الانتباه إذن إلي أننا سوف نتحدث عن نوعين من الدوال , الدوال القائمة بذاتها مثل window(), cput() وسوف نميز بينهما باسمي "الدالة المكتبية" أو " الدالة المنتمية" . والدوال الأولي محتواة في الملف cinio.h الذي صدرنا به برنامجنا .



الدوال المكتبية المستخدمة في الفئة textwin



الدالة window()



تحدد الدالة window() النافذة , وحيث إنها ليست دالة منتمية فليس من الممكن وجود أكثر من نافذة فعالة علي الشاشة في المرة الواحدة , فنحن نحدد حجم الشاشة , وندخل النص المطلوب بالدالة cputs() فإذا أردنا إظهار النص التالي يجب أن نستثير الدالة window() مرة أخري .



والوضع الابتدائي لهذه الدالة هي الشاشة بأكملها .



الدالة cputs()



الأسلوب المعتاد لإظهار نص علي الشاشة وهو cout والمؤثر << لا يصلح في إظهار نص في النافذة التي ننشئها (إلا إذا استخدمنا consteam ) أغلب دوال السي ++ لا تعرف وجود النوافذ النصية , فعي تفترض أن الشاشة بأكملها لها . فلكي تعمل من خلال نافذة عليك أن تستخدم دالة مكتبية مخصصة لهذا العرض , ومن أهم تلك الدوال الدالة cputs() ( الحرف c اختصار لكلمة consol وتعني الشاشة ) .



ومن خصائص الدالة المذكورة أنها لا تترجم المحرف n\ علي أنه سطر جديد وأول السطر في نفس الوقت , بل يجب استخدامها للإنتقال لسطر جديد , واستخدام المحرف \r للإنتقال لأول السطر في السطر الجديد , وتستخدم هذه المجموعة كلما أردنا الانتقال إلي سطر جديد .



الدالة clrscr()



تقوم هذه الدالة المكتبية بمحو النصوص من علي النافذة وهي مستخدمة في البرنامج في موضعين , في الدالة المنتمية text::erase() لمحو محتويات النافذة وفي الدالة الأصلية لكي تمهد النافذة قبل إنشاء أي نافذة .



الدالة textcolor()



تستخدم هذه الدالة بواسطة الدالة المنتمية text::color لكي تعطي النص لونا معينا , وتحمل كافة النصوص التي تلي استثارة هذه الدالة اللون المحدد .



ويوجد عدد كبير من الدوال القائمة بذاتها الخاصة بالألوان لم نستخدمها في برنامجنا , والكثير منها تتشابه دوال الفئة constream في إمكانياتها منها مثلا الدالة textbackground() وهي تتقبل الرقم المقابل للون الخلفية والدالة highvedio() التي تتحكم في وضوح النص .



عمل البرنامج



تقوم الدالة الأصلية بتحديد ثلاثة نصوص , وإنشاء كائنين من نوع الفئة textwin , الأول ينشئ نافذة في وسط الشاشة , والثاني ينشئ أخري في أعلاها من اليسار . ويدخل الكائن الأول النص الأول في الشاة الأولي والكائن الثاني في الشاشة الثانية ثم يعود البرنامج للكائن الأول مدخلا النص الثالث .



فئة داخل فئة



سوف نطور برنامجنا الأول لرسم حدود للنافذة التي ننشئها حتي نعطيها شكل النافذة المألوف . سوف نفعل ذلك باستخدام محارف رسومية بأشكال خطوط أفقية وأسية وأركان . وسوف نسمي الفئة التي تتولي رسم الحدود textbox() وسوف ندمج في هذه الفئة كائنا من الفئة constram بحيث يمكننا أن نستخدم دوالها في الفئة التي وضعناها .






conboxes.cpp


// conboxes.cpp


// text boxes as objects


// each text box is based on a constream window


// UCS Laboratories


 


#include <constrea.h>   // for constream class


#include <string.h>     // for strcpy()


#include <conio.h>


 


const int LEFT = 25;    // default window dimensions


const int TOP = 6;


const int RIGHT = 55;


const int BOTTOM = 18;


 


class textbox           // text window class


   {


   private:


      int left, top, right, bottom;      // box dimensions


      constream w;                       // a constream window


      int color;                         // text color


   public:


      textbox()                          // no-arg constructor


     {                               // default size


         left=LEFT; top=TOP; right=RIGHT; bottom=BOTTOM;


     color = WHITE;


     }


                                         // 5-arg constructor


      textbox(int l, int t, int r, int b, int c=WHITE)


     {                               // size from arguments


         left=l; top=t; right=r; bottom=b;


         color=c;                        // color from arg


         }


      void erase()                       // erase the box


     { w.clrscr(); }


      void drawtext(char*);              // display the box


   };


 


void textbox::drawtext(char* str)        // display box with text


   {


   w.window(left, top, right, bottom+1); // frame window


   w.clrscr();                             // erase window


   w << setclr(color);                   // set window color


   int width = right - left + 1;


   int height = bottom - top + 1;


   for(int j=1; j<=width; j++)           // draw horiz lines


      {


      w << setxy(j, 1) << char(205);        // top


      w << setxy(j, height) << char(205);   // bottom


      }


 


   for(j=1; j<=height; j++)              // draw vertical lines


      {


      w << setxy(1, j) << char(186);        // left


      w << setxy(width, j) << char(186);    // right


      }


                                         // draw corners


   w << setxy(1, 1) << char(201);           // upper left


   w << setxy(width, 1) << char(187);       // upper right


   w << setxy(1, height) << char(200);      // lower left


   w << setxy(width, height) << char(188);  // lower right


                                         // reframe window


   w.window(left+2, top+1, right-2, bottom-3);


   w << str;                             // display text


 


   w.window(left, top, right, bottom+1); // reframe window


   w << setxy(3, height-1);              // go to last line


   w << "Press any key to continue: ";   // display prompt


   getch();                              // wait for keypress


   }


 


void main()


   {


   clrscr();                          // clear screen


 


   textbox bx1;                       // box, no-arg constructor


   textbox bx2(1, 1, 31, 8, YELLOW);  // box, 5-arg constructor


 


                      // text for box 1


   char s1[] = "\"The time,\" said the\n\


Duchess, \"is surely ripe;\n\


make haste, lest seconds\n\


spoil.\"";


                      // text for box 2


   char s2[] = "Should you continue\n\


along the present path you\n\


risk investigation\n\


for felonious chicanery.";


 


   bx1.drawtext(s1);                  // output text in box 1


   bx1.erase();                       // erase box 1


   bx2.drawtext(s2);                  // output text in box 2


   bx2.erase();                       // erase box 2


   bx2.drawtext("Thank you");         // output new text in box 2


   getche();


   }




للفئة textbox دالتان بادئتان , الأولي لا معاملات , لإنشاء مستطيل بأبعاد في وسط الشاشة كخيار مبدئي , والثانية بخمسة معاملات لرسم المستطيل بالأبعاد التي يدخلها المستخدم . يضاف النص لمستطيل المحدد للنافذة عن طريق دالة drawtext() .



الدالة المتحكمة setxy()



هذه الدالة من دوال الفئة constram تضع المشيرة في نقطة معينة علي النافذة ومعاملاها هما البعد السيني والصادي للنقطة التي توضع فيها المشيرة . ويجب ملاحظة أن هذه الأبعاد تؤخذ بالنسبة للنافذة وليس للشاشة , فالنقطة 1,1 تعني الركن الأيسر العلوي للنافذة . وقد استخدمنا هذه الدالة أكثر من مرة .



 



نافذة داخل نافذة



استخدمت الدالة drawtext() الدالة المنتمية window() لإنشاء عدة نوافذ في نفس الموضع بأحجام مختلفة قليلا . ففي موضع مبكر من الدالة استخدمنا الأمر :



W.window(left, top, right, bottom+1);



لإنشاء ما نسميه "النافذة الإطارية frame window " وقد أزحنا الخط الأسفل منها بمقدار 1 حتي نتيح إظهار الركن الأيمن السفلي دون أن نتسبب في طي محتويات النافذة بأكملها لأعلي أما حدود النص الفعلية فتنشأ بالأمر :



w.window(left+2, top+1, right -2, bottom-3);



وأبعاد هذه النافذة تكون بالطبع أقل قليلا من أبعاد النافذة الإطارية .

التسميات: