مقدمة
GDI+ هى الجيل الجديد من تقنية GDI (graphics deviceinterface) وهى عبارة عن مجموعة من المكتبات تزودنا بواجهه لانشاء تطبيقات مختلفية سواء تطبيقات ويندوز او ويب تلك التطبيقات الى تتفاعل مع اجهزة العرض المختلفة كالطابعات او الشاشات او الملفات
GDI+ هى مجموعة من المكتبات مكتوبة بلغة C++ توجد فى الملف المسمىGdiplus.dll وهذا الملف ياتى ضمنا مع ملفات تشغيل WindowsXPوWindows Server 2003
بالامكان استخدام GDI+ على انظمة اخرى خلاف XP وذلك بنسخ الملف Gdiplus.dllالى مجلد النظام
وبمجرد تحميل .NET FrameWork يتم نسخ هذا الملف اتوماتيكيا
ذكرنا قبل قليل ان GDI+ مكتوب بلغة C++ وبهذا يعتبر استخدامه بهذه اللغة كود غير مدار Unmanaged Code
فكيف يتم التعامل معه من خلال الدوت نت,الدوت نت يغلف هذه الفئات ويقدمها فى اطار دوت نت ككود مدار
ومكتبة الفئات المدارة فى الدوت نت تقع فى الملف System.Drawing.dll
يمكن تفسيم وظائف GDI+ الى ثلاث اقسام وهى 2D vector graphics, imaging, and typography
هذه فضاءات الاسماء التى تقع فيها فئات GDI+
System.Drawing, System.Drawing.Design, System.Drawing.Drawing2D, System.Drawing.Imaging, System.Drawing.Printing, and System.Drawing.Text
لمزيد من التفاصيل حول هذه الفضاءات وما تحتويه من فئات راجع MSDN
مفاهيم اساسية
اى برنامج رسم يشمل ثلاثة مكوّنات مشتركة: مسطح للرسم , فرشاة أو قلم، عملية.
1-مسطح الرسم هو المساحة التى سيتم الرسم عليها,فمثلا فى تطبيقات ويندوز يعتبر الفورم مكان للرسم.
2-الفرشاة أو القلم يمثّل الخام( لون، وعرض الهدف الذى سيرسم على المكان)
3 -العملية تصف كيف يرسم الهدف على المكان
على سبيل المثال لرسم مربع او خط انت بحاجة الى قلم او فرشاة مع تحديد مواصفاته(الخامtexture) و عملية تصف فيها كيف يتم الرسم ومكان ترسم عليه
GDI+يزودنا بثلاث انواع من اسطح الرسم هى:
1-النوافذFORMS + الادوات CONTROLS
2-الطابعاتPRINTERS
3-الصورBITMAPS
ولكل اسطح الرسم اربع خصائص مشتركة هى:
الطول والعرضwidth and height:وهى تمثل حجم مسطح الرسم ويتم تحديدها بعدد من البكسلPIXEL افقيا وعموديا
الدقةresolution:وهى تمثل مقياس جودة المخرجات لكائن الرسم او الصورة. مجموعة نقاط لكل انشDPI)),فمثلا الدقة 72 تعنى انه يوجد فى كل انش 72 بكسل افقيا وعموديا
عمق اللونcolor depth:هو عدد الالوان المستخدمة لتمثيل كل بكسل
تعريف البكسلPixel: يمكن تعريفه على انه اصغر عنصر مشارك فى عمليه الرسم لعرض كائن الرسم او الصورة على الشاشة.
نظام الاحداثيات(X,Y) فى GDI+
تختلف الاحداثيات السينية والصادية فى GDI+ عن الاحداثيات فى النظام الديكارتى فهى تبداء من الزاوية العليا على اليسار(يسار الشاشة)حيث فيها تكون قيم(X,Y) (0,0) والمحور السينى يكون باتجاه اليمين والمحور الصادى لللاسفل
كائنات GDI+
كائن اللون Color Object:
وهو عبارة عن تركيبةStructur تمثل الالوان من عناصرها الاساسية ARGB
A(ALPHA) ويمثل شفافية اللون
R(RED) اللون الاحمر
G(GREEN) اللون الاخضر
B(BLUE) اللون الازرق
حيث ان اى لون هو عبارة عن خليط من الالوان السابقة وكل لون ياخذ من القيمة 0 الى 255 اى بايت واحد
والقيمة 255 تمثل اشباع اللون
يمكن الحصول على اى لون عن طريق الخاصية Color والتى تعود باحدى قيم المرقم Color متمثلا فى اسم اللون
Dim color As Color = color.Blue
الطريقة FromArgb تستخدم لتكوين لون بتمرير القيم للالوان الاساسية
Dim color As Color = color.FromArgb(255, 0, 0, 255) 'return blue
كائن النقطةPoint Object
وهو عبارة عن هيكلية تمثل الاحداثيات السينية والصادية ويمكن انشاء مثيل من هذه التركيبة باستخدام الكلمة المحجوزة new ومنشئ الفئة تم اعادة تعريفة ثلاث مرات حيث يمكن انشاءه من قيمة واحدة(عدد صحيح) او من كائن الحجم Size Object او من قيمتين تمثلان الاحداثى السينى والصادى
Dim pt1 As Point = New Point(10) Dim pt2 As Point = New Point(New Size(20, 20)) Dim pt3 As Point = New Point(30, 30)
كما يوجد ايضا الكائن PointF وهو مشابه للكائن الاول الا انه يختلف عنه بانه له منشئ واحد كما انه ياخذ قيم من النوع الحقيقى قيمتين تمثلا الاحداثى السينى والصادى
Dim pt As PointF = New PointF(10.5F, 10.5F)
الخاصية IsEmpty تعود بالقيمة True اذا كانت النقطة خالية اى قيمة x,y تساوى صفر ولانشاء نقطة خالية
Dim pt As Point = Point.Empty
كائن المستطيل Rectangle and RectangleF
وهو عبارة عن مستطيل تخزن به قيم الزاوية العليا اليسرى والعرض والارتفاع
ويمكن انشاءه من كائن النقطه الذى سيمثل قيمة الزاوية وكائن الحجم الذى سيمثل العرض والارتفاع او يمكن انشاءه بتمرير اربع قيم تمثل احداثيات البداية والنهاية
يوجد لهذا الكائن خصائص التى التى تعود بقيم الاحداثيات
Dim pt As Point = New Point(10, 10) Dim sz As Size = New Size(20, 20) Dim rect As Rectangle = Rectangle.Empty rect.Location = pt rect.Width = sz.Width rect.Height = sz.Height '*************************** Dim rect1 As Rectangle = New Rectangle(10, 10, 20, 20)
وطبعا الكائن RectangleF هو نفس Rectangle ولكن الفرق عنه انه ياخذ قيم من النوع الحقيقى ولا تنسى استخدام pointF,sizeF معه
كائن الحجم Size and SizeF
ويتم انشاءه من التركيبة SIZE تمثل الحجم (الراتفاع والعرض) والفرق بينهم الاول ياخذ ارقام من النوع INTEGER والثانى REAL
Dim sz As Size = Size.Empty sz = New Size(10, 10)
كائن الرسم Graphics
لرسم اى شئ لابد من وجود كائن الرسم فهو يحتوى على جميع الطرق للازمة للرسم وتعبئة الاشكال ..الخ ويتم انشاءه من الفئة Graphic ولكن لا يمكن انشاءه مباشرة باستخدام الكلمة المحجوزه new ولكن يوجد العديد من الطرق للحصول على كائن الرسم منها
استخدام الحدث Paint للفورم
حيث يمكن الحصول عليه من الخاصية Graphics لـPaintEventArgs فى حدث رسم الفورم
Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint Dim g As Graphics = e.Graphics End Sub
اعادة قيادة الطريقةOnPaint للفورم
ايضا يتم الحصول عليه من الوسيط PaintEventArgs كما فى الحدث Paint
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs) Dim g As Graphics = e.Graphics End Sub
طرق اخرى لانشاء كائن الرسم
يوجد العديد من الطرق المختلفة لانشاء كائن الرسم بخلاف الحصول عليه من حدث رسم الفورم وقد تحتاج الى هذه الطرق فى حاله كنت تريد انشاء كائن الرسم فى حدث ظغط زر مثلا
والتى تعود بكائن رسم CreateGraphics تحتوى على الطريقةFormالفئة
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Dim g As Graphics = Me.CreateGraphics g.Dispose() End Sub
End Sub
هذه الطريقة موجوده فى معظم الادواتCreateGraphics
dispose()تذكر استدعاء الطريقة لانشاء كائن الرسم CreateGraphicsعند استخدام الطريقة لتحرير ه
كما يمكن انشاء كائن الرسم من الطرق FromImage, FromHwnd, and FromHdc وهى طرق مشتركة للفئة Graphics
Dim bmb As Bitmap = New Bitmap(600, 400, System.Drawing.Imaging.PixelFormat.Format32bppPArgb) Dim g As Graphics = Graphics.FromImage(bmb) Dim g1 As Graphics = Graphics.FromHwnd(Me.Handle)
يمكن تقسيم الطرق الموجوده فى كائن الرسم الى اثنين الاولى الخاصة برسم الاشكال والثانية الخاصة بتعبئة الاشكال
رسم الاشكال:
رسم الخطوط :
ويتم ذلك باستخدام الطريقة DrawLine وهى تقوم برسم خط بين نقطتين وهذه الطريقة تم اعادة تعريفها overloads اربع مرات المعامل الاول لهذه الطريقة هو كائن القلم pen وسنتحددث عليه لاحقا ويمكن ان ياخذ معاملين اخرين من الكائن poit او pointf او يمكنك تمرير اربع قيم من النوع integer او النوع real تمثل الاحداثيات لنقطة البداية والنهاية
DrawLine(Pen, Point, Point) DrawLine(Pen, PointF, PointF) DrawLine(Pen, int, int, int, int) DrawLine(Pen, float, float, float, float)
الكود التالى يرسم خطان على الفورم
Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint 'انشاء كائنان قلم بالوان مختلفة وعرض مختلف Dim redPen As Pen = New Pen(Color.Red, 1) Dim bluePen As Pen = New Pen(Color.Blue, 2) 'رسم خط بتمرير الاحداثيات e.Graphics.DrawLine(redPen, 10, 10, 200, 10) 'رسم خط بتمرير كائن نقطة Dim pt1 As Point = New Point(10, 10) Dim pt2 As Point = New Point(10, 200) e.Graphics.DrawLine(bluePen, pt1, pt2) End Sub
فى بعض الاحيان تحتاج الى رسم خطوط متصله فلا داعى لاستخدام الطريقة DrawLineعدة مرات لعمل ذلك الطريقة DrawLines توفر عليك العناء وهذه الطريقة تاخذ معاملين الاول هو القلم الذى سترسم به والثانى مصفوفة من point,pointf
الكود التالى يرسم مثلث وذلك برسم عدة خطوط متصله
Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint
Dim redPen As Pen = New Pen(Color.Red, 5)
Dim ptArray As PointF() = {New PointF(20.0F, 20F), New PointF(20.0F, 200.0F), New PointF(200.0F, 200.0F), New PointF(20.0F, 20.0F)}
e.Graphics.DrawLines(redPen, ptArray)
End Subرسم المستطيل:
الطريقة DrawRectangle هى المسؤلة عن رسم المستطيل وكل ما عليك هو اعطائها احداثيات بداية الرسم واالعرض والارتفاع ايضا هذه الطريقة تم اعادة تعريفها وهى تاخذ المعاملات فى الصيغ التالية:
DrawRectangle(Pen, Rectangle) DrawRectangle(Pen, int, int, int, int) DrawRectangle(Pen, float, float, float, float)
Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint Dim redPen As Pen = New Pen(Color.Red, 5) Dim rect As Rectangle = New Rectangle(10, 10, 100, 100) e.Graphics.DrawRectangle(redPen, rect) e.Graphics.DrawRectangle(redPen, 20, 20, 80, 80) End Sub
كما توجد الطريقة DrawRectangles والتى تستخدم لرسم سلسلة من المستطيلات فهى تاخذ مصفوفة من المستطيلات
رسم الشكل البيضاوى:
ويتم ذلك بالطريقة DrawEllipse فلرسم شكل بيضاوى ما عليك الا استدعاء هذه الطريقة وتمرير مستطيل الذى سيتم الرسم فيه ايضا هذه الطريقة تم اعادة تعريفها اربع مرات وهى تاخذ معاملات بالشكل التالى
DrawEllipse(Pen, Rectangle) DrawEllipse(Pen, RectangleF) DrawEllipse(Pen, int, int, int, int) DrawEllipse(Pen, float, float, float, float
الكود التالى يقوم برسم مستطيلين
Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint Dim redPen As Pen = New Pen(Color.Red, 5) Dim rect As Rectangle = New Rectangle(10, 10, 250, 100) e.Graphics.DrawEllipse(redPen, rect) e.Graphics.DrawEllipse(redPen, 20, 20, 150, 80) End Sub
رسم النصوص:
ويتم ذلك باستخدام الطريقة DrawString وهذه الطريقة تم اعادة تعريفها باشكال عدة
اقصاها تاخذ هذه المعاملات text, font, brush, starting location, and string format.
وابسطها ياخذ هذه المعاملات string, Font, Brush, PointF
DrawString(string, Font, Brush, RectangleF) DrawString(string, Font, Brush, PointF, StringFormat) DrawString(string, Font, Brush, RectangleF, StringFormat) DrawString(string, Font, Brush, float, float) DrawString(string, Font, Brush, float, float, StringFormat)
StringFormat ياخذ كائن من الفئة StringFormatالمعامل
التى منهها تستطيع تحديد تنسيق النص, الخاصية FormatFlags تاخذ احد قيم المرقم StringFormatFlags القيمة StringFormatFlags.DirectionVertical تمكنك من الكتابة عموديا
الكود التالى يقوم برسم نص افقيا وعموديا
Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint
Dim redBrush As SolidBrush = New SolidBrush(Color.Red)
Dim rect As RectangleF = New RectangleF(90.0F, 80.0F, 250.0F, 100.0F)
Dim pt As Point = New Point(20, 20)
Dim str As String = "Hello ArabTeam"
Dim font As Font = New Font("verdana", 14)
Dim format As StringFormat = New StringFormat
format.FormatFlags = StringFormatFlags.DirectionVertical
e.Graphics.DrawString(str, font, redBrush, 100, 100, format)
e.Graphics.DrawString("solo.net", New Font("Times New Roman", 12), New SolidBrush(Color.Blue), rect)
End Subمثال تطبيقى:
سنقوم الان بعمل مثال لبرنامج يوضح استخدام الدوال السابقة فى الرسم
البرنامج عبارة عن فورم وبه زر واداة اختيارCheckbox وسنرسم فيه مبدئيا خطا افقيا وخطا عموديا يمثلان المجور السينى والصادى وبعدها يقوم المستخدم برسم خطوط على الفورم بواسطة النقر على الفورم بزر الفأرة الايسرنقطة البداية ستكون هى نقطة تقاطع المحور السينى مع المحور الصادى نهاية الخط سيتم تحديدها بشكل دائرى(الافتراضى) او بشكل مربع صغير وذلك فى حالة جعل قيمة CHECKBOX.CHECKED=TRUE
وفى كل مرة يتم فيها النقر على نقطه جديده على الفورم يتم توصيلها بسابقتها بخط
والان لنرى الكود
فى البداية نحتاج لتعريف متغيرين على مستوى النموذج واعطائهما قيم هى تمثل نقطة البداية والنهاية
كما قلنا نقطة البداية هى نقطة تقاطع المحور السينى مع الصادى
Private startPoint As Point = New Point(50, 217) Private endPoint As Point = New Point(50, 217)
الخطوة الثانية هى رسم المحور السينى والصادى مع ترقيمهن ونستخدم فى ذلك طريقة رسم النصوص
هذا الكود نقوم بكتابته فى حدث رسم النموذج(لماذا؟)
Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint
Dim g As Graphics = e.Graphics
Dim drawFont As Font = New Font("verdana", 10, FontStyle.Bold)
Dim vertBrush As SolidBrush = New SolidBrush(Color.Black)
Dim horzBrush As SolidBrush = New SolidBrush(Color.Blue)
Dim vertPen As Pen = New Pen(Color.Black, 2)
Dim horzPen As Pen = New Pen(Color.Blue, 2)
'رسم الخط الافقى والراسى
g.DrawLine(vertPen, 50, 220, 50, 25)
g.DrawLine(horzPen, 50, 220, 250, 220)
'ترقيم الاحداثى السينى
g.DrawString("0", drawFont, horzBrush, 30, 220)
g.DrawString("1", drawFont, horzBrush, 50, 220)
g.DrawString("2", drawFont, horzBrush, 70, 220)
g.DrawString("3", drawFont, horzBrush, 90, 220)
g.DrawString("4", drawFont, horzBrush, 110, 220)
g.DrawString("5", drawFont, horzBrush, 130, 220)
g.DrawString("6", drawFont, horzBrush, 150, 220)
g.DrawString("7", drawFont, horzBrush, 170, 220)
g.DrawString("8", drawFont, horzBrush, 190, 220)
g.DrawString("9", drawFont, horzBrush, 210, 220)
g.DrawString("10", drawFont, horzBrush, 230, 220)
'رسم النصوص افقيا
Dim vertStrFormat As StringFormat = New StringFormat
vertStrFormat.FormatFlags = StringFormatFlags.DirectionVertical
g.DrawString("-", drawFont, horzBrush, 50, 212, vertStrFormat)
g.DrawString("-", drawFont, horzBrush, 70, 212, vertStrFormat)
g.DrawString("-", drawFont, horzBrush, 90, 212, vertStrFormat)
g.DrawString("-", drawFont, horzBrush, 110, 212, vertStrFormat)
g.DrawString("-", drawFont, horzBrush, 130, 212, vertStrFormat)
g.DrawString("-", drawFont, horzBrush, 150, 212, vertStrFormat)
g.DrawString("-", drawFont, horzBrush, 170, 212, vertStrFormat)
g.DrawString("-", drawFont, horzBrush, 190, 212, vertStrFormat)
g.DrawString("-", drawFont, horzBrush, 210, 212, vertStrFormat)
g.DrawString("-", drawFont, horzBrush, 230, 212, vertStrFormat)
'رسم الاحداثى الصادى
g.DrawString("100-", drawFont, vertBrush, 20, 20)
g.DrawString("90 -", drawFont, vertBrush, 25, 40)
g.DrawString("80 -", drawFont, vertBrush, 25, 60)
g.DrawString("70 -", drawFont, vertBrush, 25, 80)
g.DrawString("60 -", drawFont, vertBrush, 25, 100)
g.DrawString("50 -", drawFont, vertBrush, 25, 120)
g.DrawString("40 -", drawFont, vertBrush, 25, 140)
g.DrawString("30 -", drawFont, vertBrush, 25, 160)
g.DrawString("20 -", drawFont, vertBrush, 25, 180)
g.DrawString("10 -", drawFont, vertBrush, 25, 200)
'dispose the object
drawFont.Dispose()
vertBrush.Dispose()
horzBrush.Dispose()
vertPen.Dispose()
horzPen.Dispose()
End Subيمكن استبدال الكود الذى يقوم برسم – على المحور الافقى بالداله drawline او الدالة drawlines
قلنا ان عملية رسم الخطوط ستتم بنقر زر الماوس الايسر من قبل المستخدم اذا انسب حدث لكتابة كود الرسم هذا هو الحدث MouseDown فى اول مرة ينقر فيها المستخدم تعتبر نقطة البداية هى نقطة تقاطع المحور السينى والصادى واول مكان ينقر فيه المستخدم هو نقطة النهاية بعد ذلك نعتبر ان نقطة النهاية هى نقطة البداية لاستكمال رسم الخط ونختبر ايضا ان كانت قيمة check للcheckbox فاذا كانت true نرسم مربع صغير فى نهاية الخط يمثل نقطة التوصيل بين الخطوط واذا كانت false نرسم شكل بيضاوى
ويمكن الحصول على القيم(X,Y) من الخاصيتين X,Y لل MouseEventArgs والتى تمثل موضع نقر المستخدم
Private Sub Form1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseDown 'اختبار ان الزر المظغوط هو الزر الايسر If e.Button = MouseButtons.Left Then 'انشاء كائن الرسم Dim g As Graphics = Me.CreateGraphics ' انشاء القلم الذى سنرسم به الخطوط Dim linePen As Pen = New Pen(Color.Green, 1) 'انشاء القلم الذى سنرسم به علامة توصيل الخطوط Dim ellipsePen As Pen = New Pen(Color.Red, 1) 'جعل نقطة البداية هى نقطة النهاية السابقة Me.startPoint = Me.endPoint 'نقطة البداية تساوى الموقع الذى نقر فيه بالماوس Me.endPoint = New Point(e.X, e.Y) 'رسم الخط g.DrawLine(linePen, Me.startPoint, Me.endPoint) 'رسم شكل يمثل علامة توصيل الخطوط If Me.CheckBox1.Checked Then g.DrawRectangle(ellipsePen, e.X - 2, e.Y - 2, 4, 4) Else g.DrawEllipse(ellipsePen, e.X - 2, e.Y - 2, 4, 4) End If 'dispose the object g.Dispose() linePen.Dispose() ellipsePen.Dispose() End If End Sub
واخير بقى لدينا الكود الذى سيمسح الخطوط التى رسمناها وكذلك اعادة نقطة البداية والنهاية الى نقطة تقاطع المحورين
ولعمل ذلك نقوم باعادة رسم النموذج وذلك باستدعاء الطريقة Invalidate او Refresh
وهذا الكود
Me.startPoint.X = 50 Me.endPoint.X = 50 Me.startPoint.Y = 217 Me.endPoint.Y = 217 Me.Invalidate(Me.ClientRectangle) 'me.Refresh
وللموضوع بقية......... :rolleyes:

