دوال النمط الرسومي في ++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 تركز علي الخصائص المشتركة للأشكال عامة , وقد أدي هذا إلي تبسيط الفئات المعبرة عن الأشكال بشكل جذري فبالنظر لأي فئة يمكننا علي الفور تحديد العناصر التي تميزها عن الفئة العامة التي تنتمي إليها .
تعليقات
إرسال تعليق