دوال النمط الرسومي في ++C

c

دوال النمط الرسومي

تقتصر إمكانيات النمط النصي علي إظهار النصوص والمحارف الرسومية , أما النمط الرسومي فيمكنك من رسم الأشكال المختلفة , من خطوط ودوائر وغيرها . وفي النمط النصي يمكنك التعامل مع 2000 نقطة فقط (80x25) , ولكنك في النمط الرسومي تتعامل علي مستوي البكسلة pixel , وهي نقاط الشاشة . ويترتب علي ذلك أن تظهر الرسوم أكثر دقة وسلاسة . فعلي شاشة تعمل بموائم VGA يمكنك التعامل مع 307200 بكسلة .

وتتطلب دوال النمط الرسومي , كحالة النمط النصي , منصة الدوس , وليس برنامج easywin ومن المهم أيضا بالنسبة إلي بورلاند أن تؤثر علي الصندوق الحواري المميز بـــ BGI في جزء standard libraries من صندوق New Project حينما تقوم بعمل مشروع برنامجك . فإذا لم تفعل لن يتعرف الرابط علي الدوال الرسومية .

وفي تيربو سي++ أختر Options/Linker ثم libraries ثم أشر علي graphics library في النافذة التي تظهر .

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

وتخزن في الفئة إحداثيات المركز حيث تقوم الدالة set() بتحديد هذه البيانات من المعاملات المرسلة لها كما تقوم الدالة draw() بعملية الرسم . وكل الدوائر التي يرسمها برنامجا لها نفس القطر .

ezball.cpp


 


// ezball.cpp


// stationary ball class


// UCS Laboratories


 


#include <graphics.h>         // for graphics functions


#include <conio.h>            // for getch()


 


const int RAD = 75;


 


class ball                    // ball class


   {


   private:


      int xCo, yCo;           // coordinates of center


   public:


      ball()                  // no-argument constructor


     { xCo=0; yCo=0; }   


      void set(int x, int y)  // set position


     { xCo=x; yCo=y; }


      void draw()             // draw the ball


     { circle(xCo, yCo, RAD); }


   };


 


void main()


   {


   int driver, mode;


   driver = DETECT;           // set to best graphics mode


   initgraph(&driver, &mode, "\\tc\\bgi");


 


   ball b1;           // create three balls


   ball b2;


   ball b3;


 


   b1.set(320, 150);  // position them


   b2.set(255, 150);


   b3.set(385, 150);


 


   b1.draw();         // draw them


   b2.draw();


   b3.draw();


 


   getch();           // wait for keypress


   closegraph();      // close graphics system


   }




يتضمن هذا البرنامج عدة دوال رسومية كلها محتواه في الملف graphics.h الذي تصدر البرنامج سوف نعرض لها واحدة تلو الأخري





الدالة initgraph()



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



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



تحديد برنامج الربط بالموئم



يقصد بالمعامل driver البرنامج الذي يقوم بالربط interface بين البرنامج والموائم الخاص بالشاشة في الجهاز ويوجد أكثر من اختيار لهذا المعامل منها مثلا :EGA, VGA, CGA (تجد المزايا في نشرة الشركة ) , وهي تتدرج في حداثتها ولكن بإمكانك أن تختار نوعا أدني وسوف يعمل علي الأنواع الأعلي من الأجهزة بسبب ما يسمي التوافق الخلفي backward compatability الذي يتبع في تطوير أنظمة الحاسبات فاختيارك للنوع CGA يضمن أن يعمل الجهاز علي النوعين الثانيين .



وكافة برامج الربط بالموائم لها الامتداد bgi . وهي بالتالي موجودة تحت الدليل BGI



تحديد النمط



يقصد بالنمط mode الأسلوب الذي يتعامل به كل موائم مع الشاشة طبقا لما هو مبين بالجدول التالي :



جدول الأنماط الرسومية















































































نمط الشاشة



ثابت النمط



الموائم



320x200, 4 colors, palette 0



CGAC 0



CGA



320x200, 4 colors, palette 1



CGAC 1



320x200, 4 colors, palette 2



CGAC 2



320x200, 4 colors, palette 3



CGAC 3



640x200, 2 colors



CGAHI



640x200, 16 colors



EGAL 0



EGA



640x350, 16 colors



EGALI



640x200, 16 colors



VGAL 0



VGA



640x350, 16 colors



VGAMED



640x480, 16 colors



VGAHI





وتعني كلمة palette لوحة من الألوان , 640x200, 16 colors ويستخدم نمط CGA أربعة لوحات , لكل لوحة أربعة ألوان . أما النمطين الأخرين فلا يستخدما هذا الأسلوب . ] أعتقد أن هذا العرض ليس له سوي قيمة تاريخية , حيث إن الأجهزة اليوم لا تستخدم موائمات تقل عن النوع الثالث [



فيمكنك مثلا أن تدخل الأوامر التالية لضبط النمط الرسومي لبرنامجك .



Int driver = VGA;



Int mode = VGAHI;



Intgraph(&driver, &mode, ''\\BC45\\BGI'');



دع النظام يختار الأفضل له



عن طريق الاختيار الذاتي يمكن للنظام أن يختار أفضل القيم عن طريق الأمر DETECT المستخدم في البرنامج المعطي .



مؤثر العنوان



لعلك لاحظت أنه بدلا من إدخال قيم النمط والموائم مباشرة في الدالة initgraph فإننا حددناهما في أوامر سابقة ثم أدخلنا اسميهما مسبوقا بالمؤثر الجديد عليك , & فما معني ذلك ؟



إن هذا المؤثر يسمي مؤثر العنوان address operator فهو يبين للدالة أين تجد القيم المطلوبة في الذاكرة وسوف نتعرض لهذا المؤثر بالتفصيل في الفصل 12 ( لا تخلط بينه وبين مؤثر التعامل المباشر passing by reference الذي له نفس الرمز ) .



المسار



المعامل الثالث في الدالة initgraph() هو مسار برنامج الربط بالموائم (البرنامج المسمي driver ) وقد وضعنا في المثال المسار المعتاد للتيربو سي++ . وعليك أن تدخل الخاص بالدليل bgi في جهازك .



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



الدالة circle()



أنشأنا في الدالة الأصلية ثلاثة كائنات تنتمي للفئة ball وحددنا مواضعها بواسطة الدالة المنتمية للكائنات set() ثم رسمناها بالدالة draw() هذه الدالة تستخدم الدالة المكتبية المسئولة عن رسم الدوائر , وتسمي circle() وتأخذ هذه الدالة ثلاثة معاملات إحداثيي المركز X, Y ونصف القطر RAD .



Closrgraph() الدالة



بعد أن تنتهي برنامجك يجب أن تعيد جهازك للوضع الذي عليه قبل تشغيل البرنامج , وهو في الغالب النمط النصي المعتاد ولو نسيت ذلك فقد يتصرف الجهاز بشكل غريب , كان تفقد المشيرة أو تجد اختلافا في نمط الحروف . وتشغيل الدالة closegraph() كفيل بتحرير الذاكرة من كافة القيم المتعلقة بالنمط الرسومي الذي استخدمناه .



الألوان



يمكنك رسم الأشكال بألوان مختلفة كما يمكنك أيضا ملء المساحات بالألوان وسوف نطور البرنامج السابق لنستغل هذه المزايا (لا تنس استخدام المسار المناسب لك للدليل bgi ) .






colorbal.cpp


 


// colorbal.cpp


// adds colors to ball class


// UCS Laboratories


#include <graphics.h>         // for graphics functions


#include <conio.h>            // for getch()


 


const int RAD = 75;


 


class ball                    // ball class


   {


   private:


      int xCo, yCo;           // coordinates of center


      int linecolor;          // color of outline


      int fillcolor;          // color of interior


   public:


      ball()                  // no-arg constructor


         { xCo=0; yCo=0; linecolor=WHITE; fillcolor=WHITE; }


      void set(int x, int y, int lc, int fc)    // set data


     { xCo=x; yCo=y; linecolor=lc; fillcolor=fc; }


      void draw()             // draw the ball


     {


     setcolor(linecolor);                      // line color


     setlinestyle(SOLID_LINE, 0, THICK_WIDTH); // line width


     circle(xCo, yCo, RAD);                    // draw circle


     setfillstyle(SOLID_FILL, fillcolor);   // set fill color


     floodfill(xCo, yCo, linecolor);        // fill circle


     }


   };


 


void main()


   {


   int driver, mode;


   driver = DETECT;                 // set to best graphics mode


   initgraph(&driver, &mode, "\\tc\\bgi");


 


   ball b1;                         // create three balls


   ball b2;


   ball b3;


 


   b1.set(100, 150, YELLOW, RED);   // set position and colors


   b2.set(200, 150, YELLOW, GREEN);


   b3.set(300, 150, YELLOW, BLUE);


 


   b1.draw();                       // draw them


   b2.draw();


   b3.draw();


 


   getch();                         // wait for keypress


   closegraph();                    // close graphics system


   }




للفئة ball هذه المرة أربعة معاملات في الدالة set وقد زاد معامل لتحديد لون الدائرة linecolor ومعامل لتحديد لون المساحة التي تحتويها fillcolor ويبين الشكل خرج البرنامج وللأسف ليس بمقدورنا أن نعرضه ملونا , فإستخدمنا أنواعا مختلفة مع التظليل عوضا عن ذلك . وإليك الدوال الجديدة المستخدمة في البرنامج :



الدالة setcolor()



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



الدالة setlinestyle



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



جدول أشكال الخطوط





















































الرقم



الثابت



التأثير



0



SOLID_LINE



خط متصل



1



DOTTED_LINE



خط منقط



2



CENTER_LINE



خط محاور (نقطة وشرطة)



3



DASHED_LINE



خط متقطع



4



USREBIT_LINE



معرف بواسطة المستخدم







وهذه الخيارات لا تنطبق في الواقع إلا علي الخطوط المستقيمة , ومن ثم فليس هاما ما ندخله في المعامل الأول لهذه الدالة في حالة الأشكال المنحنية كالدوائر , وقد وضعنا فيه القيمة الأولي , ] وهي الوحيدة المتاحة [ , أما المعامل الثاني فهو رقم يدخل في حالة اختيار تحديد الشكل بواسطة المستخدم (المعامل الأول 4 ) ولذا فقد وضعنا 0 .



المعامل الثالث يحدد سمك الخط وله خياران , عادي NORM_WIDTH ويكون سمك الخط بكسلة واحدة THICK_WIDTH وسمك الخط فيه 3 بكسلات , وهو الخيار الذي اخترناه في البرنامج .



الدالة setfillstyle()



تختص هذه الدالة بطريقة ملء المساحة المحتواة باللون المطلوب طبقا للجدول التالي ( أنظر الجدول ) .



جدول طرق التلوين





















































































































الرقم



الثابت



التأثير



0



EMPTY_FILL



لون الخلفية



1



SOLID_FILL



تلوين عادي



2



LINE_FILL



خطوط أفقية



3



LTSLASH_FILL



خطوط مائلة خفيفة



4



SLASH_FILL



خطوط مائلة ثقيلة



5



BLSLASH_FILL



خطوط مائلة عكسية خفيفة



6



LTBKSLASH_FILL



خطوط مائلة عكسية ثقيلة



7



HATCH_FILL



خطوط متقاطعة خفيفة



8



XHATCH_FILL



خطوط متقاطعة ثقيلة



9



INTERLEAVE_FILL



خطوط متداخلة



10



WIDE_DOT_FILL



نقط متباعدة



11



CLOSE_DOT_FILL



نقط متقاربة



12



USER_FILL



تصميم المستخدم





وتأخذ الدالة المذكورة معاملين , الأول هو شكل ملء المساحة , والثاني هو اللون المختار .



الدالة floodfill()



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



الخطوط والمستطيلات



البرنامج التالي مشابه للبرنامج السابق , عدا أن الأشكال المرسومة مستطيلات .



 





rectline.cpp


 


// rectline.cpp


// rectangle and line


// UCS Laboratories


 


#include <graphics.h>         // for graphics functions


#include <conio.h>            // for getch()


 


const int W = 75;             // 1/2 width of rectangle


 


class rect                    // rect class


   {


   private:


      int xCo, yCo;           // coordinates of center


      int linecolor;          // color of outline


      int fillcolor;          // color of interior


   public:


      rect()                  // no-arg constructor


         { xCo=0; yCo=0; linecolor=WHITE; fillcolor=WHITE; }


      void set(int x, int y, int lc, int fc)  // set data


     { xCo=x; yCo=y; linecolor=lc; fillcolor=fc; }


      void draw()             // draw the rectangle


     {


     setcolor(linecolor);                   // line color


     setlinestyle(SOLID_LINE, 0, THICK_WIDTH); // line width


         rectangle(xCo-W, yCo-W, xCo+W, yCo+W); // draw rectangle


     setfillstyle(SOLID_FILL, fillcolor);   // set fill color


     floodfill(xCo, yCo, linecolor);        // fill rectangle


     line(xCo-W, yCo+W, xCo+W, yCo-W);      // draw diagonal


     }


   };


 


void main()


   {


   int driver, mode;


   driver = DETECT;               // set to best graphics mode


   initgraph(&driver, &mode, "\\tc\\bgi");


 


   rect r1;                       // create three rects


   rect r2;


   rect r3;


 


   r1.set(80, 150, YELLOW, RED);  // set position and colors


   r2.set(250, 150, YELLOW, GREEN);


   r3.set(420, 150, YELLOW, BLUE);


 


   r1.draw();                     // draw them


   r2.draw();


   r3.draw();


 


   getch();                       // wait for keypress


   closegraph();                  // close graphics system


   }


multshap.cpp


 


// multshap.cpp


// balls, rects, and polygons


// UCS Laboratories


 


#include <graphics.h>         // for graphics functions


#include <conio.h>            // for getch()


 


const int W = 75;             // size of images


 


class shape                   // base class


   {


   protected:


      int xCo, yCo;           // coordinates of center


      int linecolor;          // color of outline


      int fillcolor;          // color of interior


   public:


      shape()                 // no-arg constructor


     { xCo=0; yCo=0; linecolor=WHITE; fillcolor=WHITE; }


      void set(int x, int y, int lc, int fc)  // set data


     { xCo=x; yCo=y; linecolor=lc; fillcolor=fc; }


      void draw()


     {


     setcolor(linecolor);                      // line color


     setlinestyle(SOLID_LINE, 0, THICK_WIDTH); // line width


     setfillstyle(SOLID_FILL, fillcolor);   // set fill color


     }


   };


 


class ball : public shape


   {


   public:


      ball() : shape()        // no-arg constr


     { }


      void set(int x, int y, int lc, int fc)    // set data


      { shape::set(x, y, lc, fc); }


      void draw()             // draw the ball


     {


     shape::draw();                         // set colors


     circle(xCo, yCo, W);                   // draw circle


     floodfill(xCo, yCo, linecolor);        // fill circle


     }


   };


 


class rect : public shape


   {


   public:


      rect() : shape()        // no-arg constr


     { }                                    


      void set(int x, int y, int lc, int fc)    // set data


      { shape::set(x, y, lc, fc); }


      void draw()             // draw the rectangle


     {


     shape::draw();                         // set colors


     rectangle(xCo-W, yCo-W, xCo+W, yCo+W); // draw rectangle


     floodfill(xCo, yCo, linecolor);        // fill rectangle


         line(xCo-W, yCo+W, xCo+W, yCo-W);      // draw diagonal


     }


   };


 


class tria : public shape


   {


   public:


      tria() : shape()        // no-arg constr


     { }


      void set(int x, int y, int lc, int fc)    // set data


      { shape::set(x, y, lc, fc); }


      void draw()             // draw the triangle


     {


     int triarray[] = { xCo,   yCo-W,      // top


                xCo+W, yCo+W,      // bottom right


                xCo-W, yCo+W };    // bottom left


     shape::draw();                        // set colors


     fillpoly(3, triarray);                // draw triangle


     }


   };


 


void main()


   {


   int driver, mode;


   driver = DETECT;                 // set to best graphics mode


   initgraph(&driver, &mode, "\\tc\\bgi");


 


   ball b1;                         // create ball


   rect r2;                         // create rectangle


   tria t3;                         // create triangle


 


   b1.set(80, 150, YELLOW, RED);    // set position and colors


   r2.set(250, 150, YELLOW, GREEN);


   t3.set(420, 150, YELLOW, BLUE);


 


   b1.draw();                       // draw them


   r2.draw();


   t3.draw();


 


   getch();                         // wait for keypress


   closegraph();                    // close graphics system


   }





يبين الشكل خرج البرنامج أما الدوال الجديدة فتعرض لها فيما يلي :



الدالة rectangle()



لهذه الدالة أربعة معاملات أثنان يحددان إحداثيي الركن الأيسر العلوي وإثنان للركن الأيمن السفلي .



الدالة line()



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



متعددات الأضلاع



نستخدم في البرنامج التالي التوارث لدمج الشكلين المرسومين في البرنامجين السابقين ونضيف إليهما رسم المثلث .



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



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



الدالة fillpoly()



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



وتتولي رسم متعددات الأضلاع دالة fillpoly() وهي تتطلب قبلها مصفوفية تحدد النقاط التي يتم بينها توصيل الخطوط يمثل فيها كل نقطة بإحداثييها , فإذا كان الشكل مكونا من أربعة أضلاع ] عدا المستطيل والمربع طبعا فرسمهما بالدالة rect() أسهل [ ، كانت المصفوفة علي الصورة التالية :



Int polyarray[]={x1, y1, x2, y2, x3, y3, x4, y4}:



تأخذ الدالة fillpoly() هذه الإحداثيات وتتولي توصيل الخطوط بينها وهي تتقبل معاملين الأول عدد النقاط الموصلة بينها (ليس عدد الأرقام في المصفوفة ) والثاني اسم المصفوفة المختزن بها الإحداثيات بعد ذلك تملأ الدالة الشكل باللون المبين في الدالة set() .



توجد دالة أخري في بورلاند سي++ تتولي رسم متعددات الأضلاع دون ملئها باللون .



تصميم البرنامج



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



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

التسميات: