الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

تطوير الفورم في الدوت نت باستخدام +gdi – الكلاس Skinner

بدأه a_pess في 9 مارس 2009 · 2 رد · 1,001 مشاهدة · في Microsoft Visual Basic.NET
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

تطوير الفورم في الدوت نت باستخدام +GDI – الكلاس Skinner

اللغة المستخدمة: الفيجوال بيسك

التطبيق: فيجوال استوديو 2005 و 2008

المستوي: التقييم متروك للقارئ

إعداد: مهندس / عمر أمين إبراهيم

مقدمة

من المؤكد أننا جميعا قد لاحظنا كيف يبدو شكل الفورم في الويندوز فيستا ولقد أتاحت شركة مايكروسوفت لمستخدمي نظام الفيستا إمكانية التعديل علي ألوان الفورم والمقصد هنا تحديدا هو التعديل في ألوان الجزء الذي يطلق عليه Non Client Area وكما تعلمون جميعا فإن هذه الخاصية ليست مدعومة أو ليست متاحة لمصممي البرامج من خلال الفيجوال دوت نت و بما أن مايكروسوفت لم تسمح بالتعديل علي ألوان Non Client Area من خلال الفيجوال استوديو لذا علينا أن نصمم ذلك بأن نضيف خصائص الي برامجنا تتيح لنا التغيير في شكل الفورم.

عموما أو بشكل عام كل ذلك يحدث باستخدام GDI+ ومن المؤكد أننا جميعا قد قرأنا عن GDI+ أو علي الأقل نعلم معني هذه الكلمة ولنعطي فكرة سريعة عن ماهية هذه الكلمة أو معناها

كلمة GDI+ هي نسخة محسنة أو نسخة مطورة من GDI التي تمثل الثلاثة الأحرف الأولي لكلمة Graphics Device Interface و GDI+ هي جزء من نظام التشغيل في الويندوز إكس بي Windows XP وهي المسئولة عن التعامل مع الرسم والصور وفي الدوت نت يعتبر System.Drawing Namespace هو المسئول عن إعطاؤنا الإمكانيات للدخول الي GDI+ والتعامل معها لذلك أفترض أن القارئ الذي سيتابع هذا الموضوع لدية دراية أو خلفية مناسبة عن كيفية التعامل مع +GDI بالإضافة الي ما يمكن أن نطلق عليه Dot Net Drawing Library وهي مجموعة من الكلاس الموجودة داخل System Drawing Namespace وهي التي سوف تساعدنا في أن نتعامل مع كثير من الأشياء مثل الرسم و الصور و الفونت و التكست و الألوان و الأيقونات و أيضا الأشكال الهندسية المختلفة الي أخره من هذه الأشياء. إذن كيف نغير شكل الفورم؟ أو كيف نصنع شيئا مماثلا للفيستا فورم ؟ هذا هو هدفنا هنا من هذا الموضوع وسنحاول الإجابة علي هذا السؤال من خلال طرح ومناقشة مجموعة من الأفكار التي ستساهم بشكل كبير في مساعدتنا علي تصميم الفورم

رسم الفورم

كما تعلمون فإن الرسم علي الفورم يحدث داخل الحدث Paint أو عن طريق عمل Override للحدث OnPaint أو للحدث OnPaintBackground وليس شرطا أن نستخدم أي من هذه الأحداث مباشرة ولكن أيضا يمكننا أن نرسم علي الفورم من أي مكان نريده داخل الكود و مجموعة الأمثلة التالية توضح بعض الأفكار عن كيفية الرسم داخل الفورم

المثال الأول: وهنا سوف نرسم مستطيل داخل الفورم ولتنفيذ المثال افتح مشروع جديد وفي داخل الحدث Paint الخاص بالفورم ضع الكود التالي



Dim rect As New Rectangle(0, 0, 100, 100)
Dim sb As New SolidBrush(Color.Aqua)
e.Graphics.FillRectangle(sb, rect)

End Sub
	Private Sub Form1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint

ولنلقي نظرة علي الكود أعلاه وهو كود بسيط جدا حيث هنا نرسم مستطيل ما حيث عرض المستطيل = 100 وطول المستطيل يساوي 100 ونقطة بداية رسم المستطيل علي الفورم هي النقطة صفر وصفر وهي النقطة التي تقع في اعلي يسار الفورم ثم قمنا بتعريف فرشاة SolidBrush حيث سنستخدمها في تلوين المستطيل باللون المطلوب ثم رسمنا المستطيل داخل الفورم

المثال الثاني: وهنا سوف نقوم بتعريف مستطيلا واحدا ثم سنرسم هذا المستطيل في مكانان مختلفان داخل الفورم ولتنفيذ المثال افتح مشروع جديد وفي داخل الحدث Paint الخاص بالفورم ضع الكود التالي



Dim rect As New Rectangle(0, 0, 100, 100)
Dim sb As New SolidBrush(Color.Aqua)
e.Graphics.FillRectangle(sb, rect)
e.Graphics.TranslateTransform(100, 100)
e.Graphics.FillRectangle(sb, rect)
e.Graphics.ResetTransform()

End Sub
	Private Sub Form1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint

ولنلقي نظرة علي الكود أعلاه وهو أيضا كود بسيط جدا حيث هنا نرسم مستطيل ما حيث عرض المستطيل = 100 وطول المستطيل يساوي 100 ونقطة بداية رسم المستطيل علي الفورم وهي ما يمكن أن نطلق عليها نقطة الأصل وهي النقطة صفر وصفر ثم قمنا بتعريف فرشاة SolidBrush حيث سنستخدمها في تلوين المستطيل باللون المطلوب ثم رسمنا المستطيل داخل الفورم ثم بعد ذلك نقلنا نقطة الرسم علي الفورم الي النقطة 100 و 100 وذلك باستخدام TranslateTransform ثم رسمنا نفس المستطيل بنفس الأبعاد ولكن نقطة الرسم هنا هي النقطة 100 و 100ثم استخدمنا ResetTransform وذلك لكي نعود الي نقطة الأصل علي الفورم وهي النقطة صفر وصفر ولماذا نفعل ذلك لأننا لو حاولنا الاستمرار في الرسم بدون عمل ResetTransform فإن الرسم سيتم ولكن نقطة الصفر الجديدة ستكون هي النقطة 100 و 100

المثال الثالث: وهو صورة أخري للكود أعلاه ولكننا فقط رسمنا المستطيل مائلا بزاوية 30 وما أريد توضيحه هنا هو أننا عندما نستخدم RotateTransform أو TranslateTransform يجب أن لا ننسي أبدا أن نستخدم ResetTransform لكي نعود دائما بالرسم الي نقطة الأصل ولتنفيذ المثال افتح مشروع جديد وفي داخل الحدث Paint الخاص بالفورم ضع الكود التالي



Dim rect As New Rectangle(0, 0, 100, 100)
Dim sb As New SolidBrush(Color.Aqua)
e.Graphics.FillRectangle(sb, rect)
e.Graphics.TranslateTransform(100, 100)
e.Graphics.RotateTransform(30)
e.Graphics.FillRectangle(sb, rect)
e.Graphics.ResetTransform()

End Sub
	Private Sub Form1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint

المثال الرابع: وبما أننا هنا نتحدث هنا عن تطوير الفورم لذا لنكتب نفس الكود الموجود في المثال الثالث أعلاه بطريقة أخري بحيث نربط الكود مع أبعاد الفورم نفسه مثل عرض الفورم مثلا وأيضا بدلا من استخدام SolidBrush لنستخدم LinearGradientBrush ثم نرسم الفورم في نقطة الأصل وهي النقطة التي تقع في أقصي يسار أعلي الفورم ثم بعد ذلك و بدلا من استخدام TranslateTransform سنقوم بتعريف Matrix أخري لعكس اتجاه الرسم بحيث نجعل نقطة الصفر للرسم تبدأ من أقصي يسار أسفل الفورم ثم نرسم المستطيل مرة أخري ولتنفيذ المثال افتح مشروع جديد وفي داخل الحدث Paint الخاص بالفورم ضع الكود التالي



Dim rect As New Rectangle(0, 0, Me.ClientRectangle.Width, 24)
Dim lgb As New Drawing2D.LinearGradientBrush(rect, Color.Blue, Color.Aqua, 90, True)
Dim m_matrix As New Drawing2D.Matrix(1, 0, 0, -1, 0, Me.ClientRectangle.Height)

e.Graphics.FillRectangle(lgb, rect)
e.Graphics.Transform = m_matrix
e.Graphics.FillRectangle(lgb, rect)
e.Graphics.ResetTransform()

End Sub
	Private Sub Form1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint

سنلاحظ أثناء تجربة الكود الموجود بالمثال أعلاه وتحديدا عند محاولة تكبير الفورم أو تغيير أبعاده أن الفورم لا يعيد رسم نفسه بالشكل الصحيح لذلك سنقوم بتعديل الكود أعلاه قليلا بحيث نجبر الفورم علي إعادة رسم نفسه مرة أخر عند تغيير أبعاده لذلك وفي الحدث Resize علينا أن نستخدم Invalidate وذلك لكي نجبر الفورم علي رسم نفسه بالشكل الصحيح والكود سيكون كالتالي



Invalidate()

End Sub
	Private Sub Form1_Resize(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Resize

ملحوظة هامة:

لو قمت عزيزي القارئ بتغيير قيمة Opacity للفورم وجعلتها مثلا 85 % ستكتشف شيئا طريفا جدا وهو أن الفورم وبالرغم من أنه يعيد رسم نفسه حيث أننا استخدمنا Invalidate في الحدث Resize ولكن عند تغيير قيمة Opacity ستلاحظ أن الفورم لا يرسم المستطيلات التي حددناها سابقا بالضبط وخصوصا عندما يكون في حالة Maximize لذلك ستلاحظ فرق ضئيل جدا في أقصي اليمين لا يتم رسمه تماما وأيضا ستلاحظ أن الرسم يهتز قليلا أي أن هناك ما يسمي Flickering أثناء محاول تغيير أبعاد الفورم ولكي نتخلص من هذه الأشياء البسيطة كل ما علينا أن نفعله هو تغيير قيمة الصفة DoubleBuffered وهي عبارة عن Boolean بأن نجعل قيمتها تساوي True

أيضا لو قمت عزيزي القارئ بإضافة كنترول ما مثل Panel علي سبيل المثال الي الفورم ولنجعل قيمة الصفة Dock لهذه Panel تساوي Fill ثم نقوم بتجربة نفس المثال أعلاه سنكتشف وبالرغم من أننا رسمنا داخل الفورم فإن Panel وهي في حالة Dock = Fill قد قامت بتغطية ما رسمناه داخل الفورم ولحل هذه المشكلة البسيطة كل ما عليك أن تفعله هو أن تتلاعب قليلا بقيمة الصفة Padding الخاصة بالفورم ويتم ذلك إما عن طريق التعامل مع الفورم في مرحلة Design أو أننا نكتب ذلك في الحدث Load الخاص بالفورم

المثال الخامس: لنعيد صياغة الكود الموجود بالمثال الرابع ونجعله أكثر فعالية بحيث نرسم الشكل النهائي للفورم ولتنفيذ المثال افتح مشروع جديد ثم اكتب الكود بالشكل التالي



Dim rectTop As New Rectangle(0, 0, Me.ClientRectangle.Width, 24)
Dim rectbottom As New Rectangle(0, 0, Me.ClientRectangle.Width, 5)
Dim rectLeft As New Rectangle(0, 5, 5, Me.ClientRectangle.Height - 5)
Dim rectRight As New Rectangle(Me.ClientRectangle.Width - 5, 5, 5, Me.ClientRectangle.Height - 5)
Dim lgb As New Drawing2D.LinearGradientBrush(rectTop, Color.Maroon, Color.Red, 90, True)
Dim lgbt As New Drawing2D.LinearGradientBrush(rectLeft, Color.Maroon, Color.Red, 90, True)
Dim m_matrix As New Drawing2D.Matrix(1, 0, 0, -1, 0, Me.ClientRectangle.Height)

e.Graphics.Transform = m_matrix
e.Graphics.FillRectangle(lgbt, rectLeft)
e.Graphics.FillRectangle(lgbt, rectRight)
e.Graphics.ResetTransform()
e.Graphics.Transform = m_matrix
e.Graphics.FillRectangle(lgb, rectbottom)
e.Graphics.ResetTransform()
e.Graphics.FillRectangle(lgb, rectTop)
Dim ico As New Icon(Me.Icon, 16, 16)
Dim mFontSize As Single
mFontSize = Me.Font.Size
mFontSize += 2.0F
Dim mfont As New Font(Me.Font.Name, mFontSize, Me.Font.Style, Me.Font.Unit)

e.Graphics.DrawIcon(ico, rectTop.X + 2, 4)
e.Graphics.DrawString(Me.Text, mfont, New SolidBrush(Color.White), rectTop.X + 18, 4)

End Sub

Private Sub Form1_Resize(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Resize
Invalidate()
End Sub

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

Me.Padding = New System.Windows.Forms.Padding(5, 24, 5, 5)
Me.DoubleBuffered = True
Me.Opacity = 0.85
Me.Left = (Screen.PrimaryScreen.WorkingArea.Width - Me.Width) / 2
Me.Top = (Screen.PrimaryScreen.WorkingArea.Height - Me.Height) / 2
Me.FormBorderStyle = Windows.Forms.FormBorderStyle.None


End Sub
	Private Sub Form1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint

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

في الحدث Paint

تم تعريف مجموعة من المتغيرات وهي عبارة عن أربعة مستطيلات وهم علي التوالي rectTop و rectBottom و rectLeft و rectRight وتم ربط أبعاد هذه المستطيلات بأبعاد الفورم أو تحديدا مع المستطيل الذي يعبر عن أبعاد الفورم وهو ما يطلق عليه اسم ClientRectangle

تم تعريف متغيران عبارة عن فرشاة ألوان وهما من النوع LinearGradientBrush وتم استخدامهم في تلوين المستطيلات الأربعة

تم تعريف Matrix حيث ستستخدم في نقل نقطة الأصل للرسم لكي نرسم بعض المستطيلات في أماكنها علي الفورم

تم رسم المستطيلات الأربعة علي الفورم

وأخيرا تم رسم أيقونة الفورم وأيضا الفورم تكست

في الحدث Resize

تم استخدام Invalidate لكي نجبر الفورم علي إعادة رسم نفسه

في الحدث Load

تم تحديد بعض الصفات الخاصة بالفورم وتم تحديد قيمتها مثل DoubleBuffered و Opacity وأيضا مكان الفورم ليكون في وسط شاشة الكمبيوتر تحديدا وذلك عن طريق استخدام Me.Left و Me.Top ثم أخيرا قمنا بإلغاء FormBorder

لربما أن الفورم حتى هذه المرحلة قد يفي باحتياجات بعض القراء ولكن لنفكر قليلا ماذا نريد أيضا من الفورم لكي يظهر بشكل احترافي ولو قليلا اعتقد مبدئيا أننا نريد أن نغير Form Edges أو أطراف الفورم ونجعلها تأخذ شكل القوس ولو قليلا وأيضا يجب أن نعطي المستخدم إمكانية تحريك الفورم علي الشاشة وأيضا يجب أن نعطي المستخدم إمكانية إغلاق الفورم أو أيضا إمكانية وضع الفورم في Task Bar عندما يكون في الحالة Minimized مثلا ولربما أيضا نريد تتغير ألوان الفورم عندما يكون الماوس خارج حدود الفورم أو في حالة أن المستخدم قد ترك الفورم واستخدم برنامج أخر أعتقد انه مازال هناك الكثير من الأشياء التي يجب إضافتها الي الكود أعلاه لكي نجعل شكل الفورم أكثر إحترافية ولكن قبل أن نفعل كل ذلك لنسأل أنفسنا سؤالا هاما جدا وهو هل يجب علينا في كل مرة نصمم برنامجا ما أن نكتب مثل هذا الكود مع كل فورم ؟ من المؤكد أن ذلك ليس منطقيا والأفضل لنا أن نبني كلاس ما ثم يمكننا أن نضيفه الي أي مشروع بعد ذلك كنوع من Reference وهنا سيجب علينا فقط أن نكتب القليل جدا من الكود مع كل فورم وهذا بالتأكيد سيوفر علينا الكثير من الجهد والوقت. أو من الممكن أن نبني هذا الكلاس علي شكل Component يتم إضافتها الي الفورم وهذا بالتأكيد سيكون عمليا أكثر حيث هنا يمكن إضافته الي الفيجوال استوديو Toolbox ومن ثم يمكن أن نستخدمه وقتما نريد مع أي فورم

والأن لنبني معا مثل هذا الكلاس حيث سيكون هو النواة الأساسية التي من الممكن التطوير بها حينما نريد وأيضا يمكن استخدامه بشكل عام في تغيير شكل الفورم وسوف أطلق علي هذا الكلاس إسم Skinner مثلا أو يمكنك أنت عزيزي القارئ أن تختار أي اسم تريده للكلاس

يتبع في المشاركة التالية....................

Example1.rar

Example2.rar

Example3.rar

Example4.rar

Example5.rar

#2

الكلاس ٍSkinner

لو نظرنا الي الكود الموجود بالمثال الخامس لربما نستطيع أن نحدد بشكل مبدئي مجموعة المتغيرات والعناصر التي نحتاجها لبناء الكلاس وعلي سبيل المثال ربما نحتاج أن نضيف الي الكلاس بعض المتغيرات الخاصة بالألوان و الفونت و التكست ومتغير يعبر عن الفورم و بعض Read-only Property التي من الممكن استخدامها لاسترجاع بيانات من الفورم وأيضا بعض Public Property أيضا نحتاج أن نضيف Constructor الي الكلاس وربما نحتاج أن نضيف أيضا بعض Handlers أو Delegates أو نضيف ما نراه مناسبا لكي يؤدي الكلاس الغرض المطلوب منه ألا وهو تغيير شكل الفورم

لتصميم الكلاس لنفتح مشروع جديد ونختار Class Library ونعطي المشروع اسم Skinner ثم نقوم بإضافة بعض References الي المشروع ويتم ذلك من قائمة Project ثم نختار Add Reference ثم نضيف System.Windows.Forms وأيضا نضيف System.Drawing وكما تعلمون بمجرد فتح المشروع سيقوم الفيجوال استوديو بإضافة كلاس الي المشروع ويكون الاسم الافتراضي أو المبدئي هو Public Class Class1 نقوم بتغيير الاسم الافتراضي الي أي اسم نريده وعموما لقد قمت بتغيير الاسم الي Public Class CairoSkin ثم نبدأ في التعامل مع الكلاس عن طريق إضافة ما نريد من الكود داخل الكلاس ويمكن تقسيم الكود المبدئي الذي يمكن إضافته للكلاس الي خمسة عناصر رئيسية وهي ستكون كالتالي

إضافة المتغيرات

في الكود التالي تم تعريف مجموعة من المتغيرات والثوابت حيث سيتم استخدامها في رسم وتلوين الفورم

أيضا تم تعريف متغير يعبر عن الفورم حيث سيتم تمرير هذا المتغير داخل Constructor الخاص بالكلاس لكي نربط الكلاس مع أي فورم نريده


Private CaptionHeight As Integer = 26
Private m_Font As New Font("Arial", 9.0F, System.Drawing.FontStyle.Bold)
Private m_DarkColor As Color = Color.FromArgb(255, 51, 102, 204)
Private m_LightColor As Color = Color.FromArgb(255, 0, 245, 255)
Private m_TextColor As Color = Color.Black
Private m_Parent As Form
Private m_Developer As String = "Omar Amin Ibrahim"
	Private FrameThickness As Integer = 5

إضافة Constructor

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



End Sub

Public Sub New(ByVal m_form As Form)

m_Parent = m_form
m_Parent.Opacity = 0.85
m_Parent.FormBorderStyle = FormBorderStyle.None
m_Parent.Padding = New System.Windows.Forms.Padding(FrameThickness, CaptionHeight, FrameThickness, FrameThickness)
m_Parent.Left = (Screen.PrimaryScreen.WorkingArea.Width - m_Parent.Width) / 2
m_Parent.Top = (Screen.PrimaryScreen.WorkingArea.Height - m_Parent.Height) / 2

AddHandler m_form.Paint, AddressOf OnPaint
AddHandler m_form.Resize, AddressOf OnResize

End Sub
	Public Sub New()

إضافة Property

في الكود التالي يتم إضافة ما نريده من Property الي الكلاس حيث يقوم بعضها وتحديدا Readonly Property باسترجاع بيانات عن الفورم وبعضها الأخر وتحديدا Public Property يتيح لمستخدم الكلاس التحكم في بعض الألوان المستخدمة في رسم الفورم


Get
Return m_TextColor
End Get

Set(ByVal value As Color)
If (value <> (m_TextColor)) Then

m_TextColor = value

End If

m_Parent.Invalidate()
End Set

End Property

Public Property LightColor() As Color
Get
Return m_LightColor
End Get
Set(ByVal value As Color)
If (value <> (m_LightColor)) Then

m_LightColor = value

End If

m_Parent.Invalidate()
End Set
End Property

Public Property DarkColor() As Color
Get
Return m_DarkColor
End Get
Set(ByVal value As Color)
If (value <> (m_DarkColor)) Then

m_DarkColor = value

End If
m_Parent.Invalidate()
End Set
End Property

Protected ReadOnly Property Text() As String
Get
Return m_Parent.Text
End Get
End Property

Protected ReadOnly Property ClientRectangle() As Rectangle
Get
Return m_Parent.ClientRectangle
End Get
End Property

Protected ReadOnly Property Developer() As String
Get
Return m_Developer
End Get
End Property

Protected ReadOnly Property Parent() As Form
Get
Return m_Parent
End Get
End Property
	Public Property TextColor() As Color

إضافة Methods

هنا يتم كتابة أي الكود الخاص بجميع Handlers التي تم إضافتها الي Constructor



Dim rectTop As New Rectangle(0, 0, Me.ClientRectangle.Width, 24)
Dim rectbottom As New Rectangle(0, 0, Me.ClientRectangle.Width, 5)
Dim rectLeft As New Rectangle(0, 5, 5, Me.ClientRectangle.Height - 5)
Dim rectRight As New Rectangle(Me.ClientRectangle.Width - 5, 5, 5, Me.ClientRectangle.Height - 5)
Dim lgb As New Drawing2D.LinearGradientBrush(rectTop, m_LightColor, m_DarkColor, 90, True)
Dim lgbt As New Drawing2D.LinearGradientBrush(rectLeft, m_LightColor, m_DarkColor, 90, True)
Dim m_matrix As New Drawing2D.Matrix(1, 0, 0, -1, 0, Me.ClientRectangle.Height)

e.Graphics.Transform = m_matrix
e.Graphics.FillRectangle(lgbt, rectLeft)
e.Graphics.FillRectangle(lgbt, rectRight)
e.Graphics.ResetTransform()
e.Graphics.Transform = m_matrix
e.Graphics.FillRectangle(lgb, rectbottom)
e.Graphics.ResetTransform()
e.Graphics.FillRectangle(lgb, rectTop)
Dim ico As New Icon(m_Parent.Icon, 16, 16)
e.Graphics.DrawIcon(ico, rectTop.X + 2, 4)
e.Graphics.DrawString(Me.Text, m_Font, New SolidBrush(m_TextColor), rectTop.X + 18, 4)

End Sub

Protected Overridable Sub OnResize(ByVal sender As Object, ByVal e As EventArgs)

m_parent.Invalidate()

End Sub
	Protected Overridable Sub OnPaint(ByVal sender As Object, ByVal e As PaintEventArgs)

إضافة Functions

هنا تم عمل Override للدالة ToString لنسترجع اسم مصمم الكلاس


Return m_Developer
End Function
	Public Overrides Function ToString() As String

بعد الانتهاء من كتابة الكود فقط علينا أن نقوم بعمل Build للكلاس وسنجد نسخة من الكلاس Skinner.dll موجودة تحديدا تحت الفهرس Debug الموجود تحت فهرس المشروع

كيف نستخدم الكلاس Skinner

لكي تستخدم الكلاس عليك أن تفتح مشروع عادي به فورم ثم تضيف هذا الكلاس الي المشروع عن طريق Add Reference من قائمة Project ثم تقوم بكتابة Import Skinner وهذا بلغة الفيجوال بيسك أو استخدام using Skinner; كما في لغة C# والمثال التالي يوضح كيف نستخدم الكلاس حيث كل ما علينا أن نفعله هو أن نقوم بتعريف متغير يعبر عن الكلاس Skinner ثم نربطه بالفورم في الحدث Load وكما تلاحظون أننا قد وفررنا كثيرا من الوقت والجهد في تكرار كتابة الكود لأننا نستطيع أن نستخدم الكلاس Skinner مع أي فورم وبنفس الأسلوب الذي اتبعناه بالمثال التالي.

حاول عزيزي القارئ أن تضيف أي عدد تريده من الفورم الي المشروع واستخدم نفس عدد الأسطر من الكود أدناه مع كل فورم تضيفه الي المشروع وشاهد ما سيحدث



Public Class Form1

Private skin As CairoSkin

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

' لو استخدمنا فقط السطر التالي مباشرة
' من الكود بدون تغيير الألوان
' فإن الفورم سيأخذ الألوان التي حددناها دخل الكلاس
skin = New CairoSkin(Me)
' هنا نقوم بتغيير ألوان الفورم لو أردنا ذلك
skin.DarkColor = Color.Maroon
skin.LieghtColor = Color.Red
skin.TextColor = Color.White

End Sub

End Class
Imports Skinner

تغيير شكل الفورم

كما سبق وأوضحنا أن الفورم أو الكلاس Skinner حتى هذه المرحلة قد يفي باحتياجات بعض القراء ولكن أعتقد أنه مازال هناك الكثير من الأشياء التي من الممكن أن نضيفها للفورم لكي يصبح أكثر إحترافية ومن هذه الأشياء تغيير شكل الفورم

مبدئيا الكلاس المسئول عن تغيير شكل الفورم الي أي شكل نريده هو الكلاس Region وغالبا ما يتم استخدام هذا الكلاس مع Rectangle Structure أو RectangleF Structure أو مع GraphicsPath Class أو مع RegionData Class لتعريف الشكل الذي نريده ثم نمرره الي الكلاس Region فيأخذ الفورم الشكل المطلوب وعموما ما يهمنا حاليا هو التركيز علي استخدام GraphicsPath والأمثلة التالية توضح بعض الأفكار عن كيفية تغيير شكل الفورم

المثال السادس: في هذا المثال سنغير شكل الفورم الي أي شكل نريده عن طريق استخدام GraphicsPath ثم نمرره الي Form Region ونري ما سيحدث ولتنفيذ المثال افتح مشروع جديد ثم اكتب الكود بالشكل التالي



Me.FormBorderStyle = Windows.Forms.FormBorderStyle.None

End Sub

Private Sub Form1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint

Dim Path As New Drawing2D.GraphicsPath

Path.AddArc(21, 21, 21, 21, 180, 90)
Path.AddArc(Me.ClientRectangle.Width - 42, 21, 21, 21, 270, 90)
Path.AddArc(Me.ClientRectangle.Width - 42, Me.ClientRectangle.Height - 42, 21, 21, 360, 90)
Path.AddArc(21, Me.ClientRectangle.Height - 42, 21, 21, 90, 90)

Path.CloseFigure()

Path.AddEllipse(New Rectangle(0, 0, 22, 22))
Path.AddEllipse(New Rectangle(Me.ClientRectangle.Width - 22, 0, 22, 22))
Path.AddEllipse(New Rectangle(0, Me.ClientRectangle.Height - 22, 22, 22))
Path.AddEllipse(New Rectangle(Me.ClientRectangle.Width - 22, Me.ClientRectangle.Height - 22, 22, 22))

Path.AddArc(21, 0, 21, 21, 180, 90)
Path.AddArc(Me.ClientRectangle.Width - 42, 0, 21, 21, 270, 90)
Path.AddArc(Me.ClientRectangle.Width - 42, 0, 21, 21, 360, 90)
Path.AddArc(21, 0, 21, 21, 90, 90)

Path.AddArc(21, Me.ClientRectangle.Height - 21, 21, 21, 180, 90)
Path.AddArc(Me.ClientRectangle.Width - 42, Me.ClientRectangle.Height - 21, 21, 21, 270, 90)
Path.AddArc(Me.ClientRectangle.Width - 42, Me.ClientRectangle.Height - 21, 21, 21, 360, 90)
Path.AddArc(21, Me.ClientRectangle.Height - 21, 21, 21, 90, 90)

Me.Region = New Drawing.Region(Path)
Dim lgb As New Drawing2D.LinearGradientBrush(Me.ClientRectangle, Color.Maroon, Color.Red, 90, True)
e.Graphics.FillRegion(lgb, Me.Region)


e.Graphics.FillRectangle(Brushes.Aqua, New Rectangle(0, 0, 22, 22))
e.Graphics.FillRectangle(Brushes.Aqua, New Rectangle(Me.ClientRectangle.Width - 22, 0, 22, 22))
e.Graphics.FillRectangle(Brushes.Aqua, New Rectangle(21, 0, Me.ClientRectangle.Width - 42, 21))

e.Graphics.FillRectangle(Brushes.Aqua, New Rectangle(0, Me.ClientRectangle.Height - 22, 22, 22))
e.Graphics.FillRectangle(Brushes.Aqua, New Rectangle(Me.ClientRectangle.Width - 22, Me.ClientRectangle.Height - 22, 22, 22))
e.Graphics.FillRectangle(Brushes.Aqua, New Rectangle(21, Me.ClientRectangle.Height - 21, Me.ClientRectangle.Width - 42, 21))

End Sub
	Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

المثال السابع: في هذا المثال سنغير شكل الفورم أيضا عن طريق استخدام GraphicsPath ثم نمرره الي Form Region ونري ما سيحدث ولتنفيذ المثال افتح مشروع جديد ثم اكتب الكود بالشكل التالي



Me.FormBorderStyle = Windows.Forms.FormBorderStyle.None

End Sub

Private Sub Form1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint

Dim Path As New Drawing2D.GraphicsPath
Path.AddArc(0, 50, 100, 100, 180, 90)
Path.AddArc(Me.ClientRectangle.Width - 100, 50, 100, 100, 270, 90)
Path.AddArc(Me.ClientRectangle.Width - 100, Me.ClientRectangle.Height - 100, 100, 100, 360, 90)
Path.AddArc(0, Me.ClientRectangle.Height - 100, 100, 100, 90, 90)
Me.Region = New Drawing.Region(Path)
e.Graphics.FillRegion(Brushes.Aqua, Me.Region)

End Sub
	Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

التحكم في نقل الفورم علي شاشة الكمبيوتر

تحريك الفورم Moving Form علي شاشة الكمبيوتر باستخدام الماوس من الممكن أن تتم بأكثر من أسلوب والفكرة ببساطة أن كل من Rectangle Structure و GraphicsPath Class و أيضا Region Class يمتلك بعض الطرق Methods التي لو استخدمت جيدا مع Mouse Events الأحداث الخاصة بالماوس سيمكننا التحكم بحركة الفورم علي شاشة الكمبيوتر بسهولة وهذه الطرق هي

Rectangle.Contains

GraphicsPath.IsVisible

Region.IsVisible

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

المثال الثامن: في هذا المثال سنقوم بتحريك الفورم اعتمادا علي Form Region ولتنفيذ المثال افتح مشروع جديد ثم اكتب الكود بالشكل التالي


Private isPoint As New Point()

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Me.FormBorderStyle = Windows.Forms.FormBorderStyle.None
End Sub

Private Sub Form1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint
Dim Path As New Drawing2D.GraphicsPath
Path.AddArc(0, 50, 100, 100, 180, 90)
Path.AddArc(Me.ClientRectangle.Width - 100, 50, 100, 100, 270, 90)
Path.AddArc(Me.ClientRectangle.Width - 100, Me.ClientRectangle.Height - 100, 100, 100, 360, 90)
Path.AddArc(0, Me.ClientRectangle.Height - 100, 100, 100, 90, 90)
Me.Region = New Drawing.Region(Path)
e.Graphics.FillRegion(Brushes.Aqua, Me.Region)

End Sub

Private Sub Form1_MouseDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseDown

If Me.Region.IsVisible(e.Location) Then
isMove = True
isPoint.X = e.X
isPoint.Y = e.Y

End If
End Sub

Private Sub Form1_MouseUp(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseUp

If isMove Then
isMove = False
End If

End Sub

Private Sub Form1_MouseMove(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseMove

If (MouseButtons.Left And e.Button) = MouseButtons.Left Then
If isMove Then
Dim x As Integer = Me.Location.X + (e.X - isPoint.X)
Dim y As Integer = Me.Location.Y + (e.Y - isPoint.Y)
Me.Location = New Point(x, y)
End If
End If

End Sub
	Private isMove As Boolean = False

المثال التاسع: في هذا المثال سنقوم بتحريك الفورم اعتمادا علي Rectangle ولتنفيذ المثال افتح مشروع جديد ثم اكتب الكود بالشكل التالي


Private isMove As Boolean = False
Private isPoint As New Point()

Private Sub Form1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint

rect = New Rectangle(0, 0, 100, 100)
Dim sb As New SolidBrush(Color.Aqua)
e.Graphics.FillRectangle(sb, rect)

End Sub

Private Sub Form1_MouseDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseDown

If rect.Contains(e.Location) Then
isMove = True
isPoint.X = e.X
isPoint.Y = e.Y

End If

End Sub

Private Sub Form1_MouseUp(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseUp
If isMove Then
isMove = False
End If

End Sub

Private Sub Form1_MouseMove(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseMove
If (MouseButtons.Left And e.Button) = MouseButtons.Left Then
If isMove Then
Dim x As Integer = Me.Location.X + (e.X - isPoint.X)
Dim y As Integer = Me.Location.Y + (e.Y - isPoint.Y)
Me.Location = New Point(x, y)
End If
End If

End Sub
	Private rect As Rectangle

المثال العاشر: في هذا المثال سنقوم بتحريك الفورم اعتمادا علي GraphicsPath وكما تلاحظون فإن الفكرة واحدة تقريبا في كما في المثالين السابقين ولتنفيذ المثال افتح مشروع جديد ثم اكتب الكود بالشكل التالي


Private isPoint As New Point()
Private path As Drawing2D.GraphicsPath

Private Sub Form1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint

path = New Drawing2D.GraphicsPath
path.AddEllipse(0, 0, 200, 200)
e.Graphics.FillPath(Brushes.Aqua, path)

End Sub

Private Sub Form1_MouseDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseDown

If path.IsVisible(e.Location) Then
isMove = True
isPoint.X = e.X
isPoint.Y = e.Y

End If

End Sub

Private Sub Form1_MouseUp(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseUp

If isMove Then
isMove = False
End If

End Sub

Private Sub Form1_MouseMove(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseMove

If (MouseButtons.Left And e.Button) = MouseButtons.Left Then
If isMove Then
Dim x As Integer = Me.Location.X + (e.X - isPoint.X)
Dim y As Integer = Me.Location.Y + (e.Y - isPoint.Y)
Me.Location = New Point(x, y)
End If
End If

End Sub
	Private isMove As Boolean = False

تبع في المشاركة التالية....................................

Example6.rar

Example7.rar

Example8.rar

Example9.rar

Example10.rar

#3

تغيير ألوان الفورم

عندما يكون الفورم في حالة Active فإنه يحتفظ بألوانه العادية ولكن عندما يكون الفورم في الحالة Inactive فإنه يأخذ ألوانا أخري وهذا يمكن أن نعتبره كنوع من التنبيه للمستخدم User بأن الفورم مستخدما أو ليس مستخدما. أيضا نفس الحالة تتم إذا قام المستخدم باختيار نافذة أخري لبرنامج أخر مثلا. كيف نفعل ذلك في الفورم الذي نرسمه؟

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


Private isActive As Boolean = True


Private Sub Form1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint

Dim rect As New Rectangle(0, 0, 100, 100)
Dim sb As New SolidBrush(Color.Aqua)
Dim sbA As New SolidBrush(Color.Gray)

If (isActive) Then
e.Graphics.FillRectangle(sb, rect)
Else
e.Graphics.FillRectangle(sbA, rect)
End If

End Sub

_
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)

Select Case (m.Msg)
Case WM_ACTIVATEAPP

isActive = (m.WParam.ToInt32() <> 0)
Me.Invalidate()

End Select

MyBase.WndProc(m)

End Sub

Private Sub Form1_VisibleChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.VisibleChanged
If Visible Then
isActive = True
Else
isActive = False
End If
End Sub
  Private Const WM_ACTIVATEAPP As Integer = &H1C

أعتقد أننا بحاجة الأن الي أن نقوم بإعادة صياغة الكود الخاص بالكلاس Skinner بحيث نضيف له بعضا من الأفكار التي استخدمناها في المثال السادس الي المثال الحادي عشر ولكن هناك ملحوظة هامة وهي تحديدا تخص المثال الحادي عشر حيث يجب أن نضع في الحسبان شيئا هاما جدا ألا وهو أننا عندما نحاول أن نضيف Handler للتعامل مع WndProc فلن نستطيع أن نفعل ذلك بالطريقة التقليدية ولو نظرنا الي الكود المبدئي للكلاس Skinner أعلاه فإننا سنلاحظ أنه وعندما كنا نريد إضافة أي Handler الي الكلاس فإن ذلك كان يتم في Constructor الخاص بالكلاس كما هو موضح بالكود التالي


AddHandler m_form.Resize, AddressOf OnResize
		AddHandler m_form.Paint, AddressOf OnPaint

إذن كيف نقوم بإضافة WndProc الي الكلاس CairoSkinner . في واقع الأمر إن ذلك يتم باستخدام الوراثة لواحد من الكلاسات الهامة جدا وهو NativeWindow Class حيث هنا يجب علينا أن نضيف كلاسا جديدا للكلاس Skinner ولقد أطلقت علي هذا الكلاس اسم WindowListener ثم نستخدم الوراثة للكلاس NativeWindow وهنا يمكننا أن نقوم بعمل Override الي WndProc ثم من داخل Constructor الخاص بالكلاس CairoSkinner نقوم بتعريف متغير يعبر عن الكلاس WindowListener ثم نستخدم هنا AssignHandle ونربطه مع الفورم

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

وفي المرفقات ستجدون النسخة الكاملة للكلاس Skinner وهي عبارة عن ملف dll بالإضافة الي السورس كود

حيث ستجدون به نسختان لتغيير شكل الفورم وهما الكلاس CairoSkin والكود الخاص به مكتوب أدناه و الكلاس CairoSkinPlus والكود الخاص به مكتوب أدناه أيضا والفارق بينهما هو أن الكلاس CairoskinPlus به باتون لإغلاق الفورم وأيضا باتون لتصغير الفورم

الكلاس CairoSkin


Imports System.Windows.Forms
Imports System.Security.Permissions

_
Public Class CairoSkin

#Region "Variables"

Private FrameThickness As Integer = 5
Private CaptionHeight As Integer = 29
Private m_Font As New Font("Arial", 10.0F, System.Drawing.FontStyle.Bold)
Private m_DarkColor As Color = Color.FromArgb(255, 51, 102, 204)
Private m_LightColor As Color = Color.FromArgb(255, 0, 245, 255)
Private m_TextColor As Color = Color.White

Private m_DarkColorDeAct As Color = Color.FromArgb(255, Color.Silver)
Private m_LightColorDeAct As Color = Color.FromArgb(255, Color.White)
Private m_TextColorDeAct As Color = Color.Gray

Private m_Developer As String = "Omar Amin Ibrahim"

Private rectMove As Rectangle
Private isMove As Boolean = False
Private isPoint As New Point()

Public Shared isActive As Boolean = True
Public Shared m_Parent As Form


#End Region

#Region "Constructor"

Public Sub New()

End Sub

Public Sub New(ByVal m_form As Form)

m_Parent = m_form
m_Parent.FormBorderStyle = FormBorderStyle.None
m_Parent.Region = SetWindow()

m_Parent.Opacity = 0.85
m_Parent.Padding = New System.Windows.Forms.Padding(FrameThickness, CaptionHeight, FrameThickness, FrameThickness)

' Add required Handlers
AddHandler m_form.Paint, AddressOf OnPaint
AddHandler m_form.Resize, AddressOf OnResize
AddHandler m_form.VisibleChanged, AddressOf OnVisibleChanged
AddHandler m_form.MouseMove, AddressOf OnMouseMove
AddHandler m_form.MouseUp, AddressOf OnMouseUp
AddHandler m_form.MouseDown, AddressOf OnMouseDown

Dim wndlisten As New WindowListener()
wndlisten.AssignHandle(Me.Handle)

End Sub

#End Region

#Region "Property"

Public Property TextColor() As Color
Get
Return m_TextColor
End Get

Set(ByVal value As Color)
If (value <> (m_TextColor)) Then

m_TextColor = value

End If

m_Parent.Invalidate()
End Set

End Property

Public Property LightColor() As Color
Get
Return m_LightColor
End Get
Set(ByVal value As Color)
If (value <> (m_LightColor)) Then

m_LightColor = value

End If

m_Parent.Invalidate()
End Set
End Property

Public Property DarkColor() As Color
Get
Return m_DarkColor
End Get
Set(ByVal value As Color)
If (value <> (m_DarkColor)) Then

m_DarkColor = value

End If
m_Parent.Invalidate()
End Set
End Property

Protected ReadOnly Property Handle() As IntPtr
Get
Return m_Parent.Handle
End Get
End Property

Protected ReadOnly Property Text() As String
Get
Return m_Parent.Text
End Get
End Property

Protected ReadOnly Property ClientRectangle() As Rectangle
Get
Return m_Parent.ClientRectangle
End Get
End Property

Protected ReadOnly Property Developer() As String
Get
Return m_Developer
End Get
End Property

Protected ReadOnly Property Parent() As Form
Get
Return m_Parent
End Get
End Property

#End Region

#Region "Methods"

Protected Overridable Sub OnPaint(ByVal sender As Object, ByVal e As PaintEventArgs)

Dim rectTop As New Rectangle(0, 0, Me.ClientRectangle.Width, CaptionHeight)
Dim rectbottom As New Rectangle(0, 0, Me.ClientRectangle.Width, FrameThickness)
Dim rectLeft As New Rectangle(0, FrameThickness, FrameThickness, Me.ClientRectangle.Height - FrameThickness)
Dim rectRight As New Rectangle(Me.ClientRectangle.Width - FrameThickness, FrameThickness, FrameThickness, Me.ClientRectangle.Height - FrameThickness)
Dim lgb As New Drawing2D.LinearGradientBrush(rectTop, m_LightColor, m_DarkColor, 90, True)
Dim lgbt As New Drawing2D.LinearGradientBrush(rectLeft, m_LightColor, m_DarkColor, 90, True)

Dim lgbDeAct As New Drawing2D.LinearGradientBrush(rectTop, m_LightColorDeAct, m_DarkColorDeAct, 90, True)
Dim lgbDeActt As New Drawing2D.LinearGradientBrush(rectLeft, m_LightColorDeAct, m_DarkColorDeAct, 90, True)

Dim m_size As SizeF = e.Graphics.MeasureString(Me.Text, m_Font)

Dim m_matrix As New Drawing2D.Matrix(1, 0, 0, -1, 0, Me.ClientRectangle.Height)
Dim ico As New Icon(m_Parent.Icon, 16, 16)
rectMove = New Rectangle(0, 0, Me.ClientRectangle.Width, CaptionHeight)

If (isActive) Then

e.Graphics.Transform = m_matrix
e.Graphics.FillRectangle(lgbt, rectLeft)
e.Graphics.FillRectangle(lgbt, rectRight)
e.Graphics.ResetTransform()
e.Graphics.Transform = m_matrix
e.Graphics.FillRectangle(lgb, rectbottom)
e.Graphics.ResetTransform()
e.Graphics.FillRectangle(lgb, rectTop)
e.Graphics.DrawIcon(ico, rectTop.X + 2, (CaptionHeight - ico.Height) / 2)
e.Graphics.DrawString(Me.Text, m_Font, New SolidBrush(m_TextColor), rectTop.X + ico.Width + 2, (CaptionHeight - m_size.Height) / 2)
Else
e.Graphics.Transform = m_matrix
e.Graphics.FillRectangle(lgbDeActt, rectLeft)
e.Graphics.FillRectangle(lgbDeActt, rectRight)
e.Graphics.ResetTransform()
e.Graphics.Transform = m_matrix
e.Graphics.FillRectangle(lgbDeAct, rectbottom)
e.Graphics.ResetTransform()
e.Graphics.FillRectangle(lgbDeAct, rectTop)
e.Graphics.DrawIcon(ico, rectTop.X + 2, (CaptionHeight - ico.Height) / 2)
e.Graphics.DrawString(Me.Text, m_Font, New SolidBrush(m_TextColorDeAct), rectTop.X + ico.Width + 2, (CaptionHeight - m_size.Height) / 2)
End If

e.Graphics.FillRectangle(New SolidBrush(Color.Empty), rectMove)

End Sub

Protected Overridable Sub OnResize(ByVal sender As Object, ByVal e As EventArgs)

m_Parent.Invalidate()

End Sub

Protected Overridable Sub OnVisibleChanged(ByVal sender As Object, ByVal e As EventArgs)

If m_Parent.Visible Then
isActive = True
Else
isActive = False
End If

End Sub

Protected Overridable Sub OnMouseDown(ByVal sender As Object, ByVal e As MouseEventArgs)

If rectMove.Contains(e.Location) Then
isMove = True
isPoint.X = e.X
isPoint.Y = e.Y

End If

End Sub

Protected Overridable Sub OnMouseUp(ByVal sender As Object, ByVal e As MouseEventArgs)
If isMove Then
isMove = False
End If

End Sub

Protected Overridable Sub OnMouseMove(ByVal sender As Object, ByVal e As MouseEventArgs)

If (MouseButtons.Left And e.Button) = MouseButtons.Left Then
If isMove Then
Dim x As Integer = m_Parent.Location.X + (e.X - isPoint.X)
Dim y As Integer = m_Parent.Location.Y + (e.Y - isPoint.Y)
m_Parent.Location = New Point(x, y)
End If
End If

End Sub

#End Region

#Region "Function"

Public Overrides Function ToString() As String
Return Me.Developer
End Function

Private Function SetWindow() As Region

Dim Path As Drawing2D.GraphicsPath = New Drawing2D.GraphicsPath
Path.AddArc(0, 0, 10, 10, 180, 90)
Path.AddArc(Me.ClientRectangle.Width - 10, 0, 10, 10, 270, 90)
Path.AddLine(Me.ClientRectangle.Width, 10, Me.ClientRectangle.Width, Me.ClientRectangle.Height)
Path.AddLine(Me.ClientRectangle.Width, Me.ClientRectangle.Height, 0, Me.ClientRectangle.Height)
Path.CloseFigure()
Dim rgn As Region = New Drawing.Region(Path)

SetWindow = rgn
m_Parent.Invalidate()

End Function

#End Region

#Region "Internal Classes"

_
Friend Class WindowListener

Inherits NativeWindow

Private Const WM_ACTIVATEAPP As Integer = &H1C

Public Sub New()

End Sub

_
Protected Overrides Sub WndProc(ByRef m As Message)

Select Case (m.Msg)

Case WM_ACTIVATEAPP
isActive = (m.WParam.ToInt32() <> 0)
CairoSkin.m_Parent.Invalidate()

End Select
MyBase.WndProc(m)
End Sub

End Class

#End Region

End Class
Imports System.Drawing

الكلاس CairoSkinPlus


Imports System.Windows.Forms
Imports System.Drawing.Drawing2D

Public Class CairoSkinPlus

#Region "Variables"

Private FrameThickness As Integer = 5
Private CaptionHeight As Integer = 29
Private m_Font As New Font("Arial", 10.0F, System.Drawing.FontStyle.Bold)
Private m_DarkColor As Color = Color.FromArgb(255, 51, 102, 204)
Private m_LightColor As Color = Color.FromArgb(255, 0, 245, 255)
Private m_TextColor As Color = Color.Black

Private m_DarkColorDeAct As Color = Color.FromArgb(255, Color.Silver)
Private m_LightColorDeAct As Color = Color.FromArgb(255, Color.White)
Private m_TextColorDeAct As Color = Color.Gray

Private m_Developer As String = "Omar Amin Ibrahim"

Private isMove As Boolean = False
Private isClosing As Boolean = False
Private isMinimizing As Boolean = False

Private isPoint As New Point()
Private rectMove As Rectangle
Private rectClose As Rectangle
Private rectMin As Rectangle

Public Shared isActive As Boolean = True
Public Shared m_Parent As Form

Private g As Graphics

Private bmp_Close As New Bitmap(My.Resources.reso.Close)
Private bmp_CloseOver As New Bitmap(My.Resources.reso.CloseHot)
Private bmp_CloseDown As New Bitmap(My.Resources.reso.ClosePressed)

Private bmp_Min As New Bitmap(My.Resources.reso.Minimize)
Private bmp_MinOver As New Bitmap(My.Resources.reso.MinimizeHot)
Private bmp_MinDown As New Bitmap(My.Resources.reso.MinimizePressed)

#End Region

#Region "Constructor"

Public Sub New()


End Sub

Public Sub New(ByVal m_form As Form)
m_Parent = m_form
m_Parent.FormBorderStyle = FormBorderStyle.None
m_Parent.Region = SetWindow()
m_Parent.Opacity = 0.85
m_Parent.Padding = New System.Windows.Forms.Padding(FrameThickness, CaptionHeight, FrameThickness, FrameThickness)

AddHandler m_form.Paint, AddressOf OnPaint
AddHandler m_form.Resize, AddressOf OnResize
AddHandler m_form.MouseMove, AddressOf OnMouseMove
AddHandler m_form.MouseUp, AddressOf OnMouseUp
AddHandler m_form.MouseDown, AddressOf OnMouseDown
AddHandler m_form.VisibleChanged, AddressOf OnVisibleChanged

Dim wndlisten As New WindowListener()
wndlisten.AssignHandle(Me.Handle)
m_Parent.Invalidate()

End Sub

#End Region

#Region "Property"

Public Property TextColor() As Color
Get
Return m_TextColor
End Get

Set(ByVal value As Color)
If (value <> (m_TextColor)) Then

m_TextColor = value
End If
m_Parent.Invalidate()
End Set
End Property


Public Property LightColor() As Color
Get
Return m_LightColor
End Get
Set(ByVal value As Color)
If (value <> (m_LightColor)) Then

m_LightColor = value
End If

m_Parent.Invalidate()
End Set
End Property

Public Property DarkColor() As Color
Get
Return m_DarkColor
End Get
Set(ByVal value As Color)
If (value <> (m_DarkColor)) Then

m_DarkColor = value
End If

m_Parent.Invalidate()
End Set
End Property

Protected ReadOnly Property Text() As String
Get
Return m_Parent.Text
End Get
End Property

Protected ReadOnly Property Handle() As IntPtr
Get
Return m_Parent.Handle
End Get
End Property

Protected ReadOnly Property ClientRectangle() As Rectangle
Get
Return m_Parent.ClientRectangle
End Get
End Property

Protected ReadOnly Property Developer() As String
Get
Return m_Developer
End Get
End Property

Protected ReadOnly Property Parent() As Form
Get
Return m_Parent
End Get
End Property

#End Region

#Region "CaptionButton Method"

Private Sub DrawCloseButtonNormal()

Dim g As Graphics = Graphics.FromHwnd(m_Parent.Handle)
g.DrawImage(bmp_Close, rectClose)
g.Dispose()

End Sub

Private Sub DrawCloseButtonOver()

Dim g As Graphics = Graphics.FromHwnd(m_Parent.Handle)
g.DrawImage(bmp_CloseOver, rectClose)
g.Dispose()

End Sub

Private Sub DrawCloseButtonDown()

Dim g As Graphics = Graphics.FromHwnd(m_Parent.Handle)
g.DrawImage(bmp_CloseDown, rectClose)
g.Dispose()

End Sub

Private Sub DrawMinButtonNormal()

' Draw the image to the form
Dim g As Graphics = Graphics.FromHwnd(m_Parent.Handle)
g.DrawImage(bmp_Min, rectMin)
g.Dispose()


End Sub

Private Sub DrawMinButtonOver()

' Draw the image to the form
Dim g As Graphics = Graphics.FromHwnd(m_Parent.Handle)
g.DrawImage(bmp_MinOver, rectMin)
g.Dispose()


End Sub

Private Sub DrawMinButtonDown()

' Draw the image to the form
Dim g As Graphics = Graphics.FromHwnd(m_Parent.Handle)
g.DrawImage(bmp_MinDown, rectMin)
g.Dispose()


End Sub

#End Region

#Region "Method"

Protected Overridable Sub OnPaint(ByVal sender As Object, ByVal e As PaintEventArgs)
If m_Parent.WindowState <> FormWindowState.Minimized Then
Dim rectTop As New Rectangle(0, 0, Me.ClientRectangle.Width, CaptionHeight)
Dim rectBottom As New Rectangle(0, 0, Me.ClientRectangle.Width, FrameThickness)
Dim rectLeft As New Rectangle(0, FrameThickness, FrameThickness, Me.ClientRectangle.Height - CaptionHeight)
Dim rectRight As New Rectangle(Me.ClientRectangle.Width - FrameThickness, FrameThickness, FrameThickness, Me.ClientRectangle.Height - CaptionHeight)
Dim lgb As New LinearGradientBrush(rectTop, Me.m_LightColor, Me.m_DarkColor, 90, True)
Dim lgbt As New LinearGradientBrush(rectLeft, Me.m_LightColor, Me.m_DarkColor, 90, True)

Dim lgbDeAct As New LinearGradientBrush(rectTop, Me.m_LightColorDeAct, Me.m_DarkColorDeAct, 90, True)
Dim lgbDeActt As New LinearGradientBrush(rectLeft, Me.m_LightColorDeAct, Me.m_DarkColorDeAct, 90, True)
Dim m_matrix As New Matrix(1, 0, 0, -1, 0, Me.ClientRectangle.Height)
Dim ico As New Icon(m_Parent.Icon, 16, 16)

'(CaptionHeight - ico.Height) / 2)
rectClose = New Rectangle(m_Parent.ClientRectangle.Right - (bmp_Close.Width + 6), (CaptionHeight - bmp_Close.Height) / 2, bmp_Close.Width, bmp_Close.Height)
rectMin = New Rectangle(m_Parent.ClientRectangle.Right - (bmp_Close.Width + 8 + bmp_Min.Width), (CaptionHeight - bmp_Min.Height) / 2, bmp_Min.Width, bmp_Min.Height)
rectMove = New Rectangle(0, 0, m_Parent.ClientRectangle.Right - rectMin.Width, CaptionHeight)


'rectMove = new Rectangle(0, 0, this.ClientRectangle.Width, CaptionHeight);
Dim m_size As SizeF = e.Graphics.MeasureString(Me.Text, m_Font)

If isActive Then
e.Graphics.Transform = m_matrix
e.Graphics.FillRectangle(lgbt, rectLeft)
e.Graphics.FillRectangle(lgbt, rectRight)
e.Graphics.ResetTransform()
e.Graphics.Transform = m_matrix
e.Graphics.FillRectangle(lgb, rectBottom)
e.Graphics.ResetTransform()
e.Graphics.FillRectangle(lgb, rectTop)
e.Graphics.DrawIcon(ico, rectTop.X + 2, (CaptionHeight - ico.Height) / 2)
'e.Graphics.DrawString(this.Text, m_Font, new SolidBrush(m_TextColor), rectTop.X + 18, 4);
e.Graphics.DrawString(Me.Text, m_Font, New SolidBrush(m_TextColor), rectTop.X + ico.Width + 2, (CaptionHeight - m_size.Height) / 2)

Else
e.Graphics.Transform = m_matrix
e.Graphics.FillRectangle(lgbDeActt, rectLeft)
e.Graphics.FillRectangle(lgbDeActt, rectRight)
e.Graphics.ResetTransform()
e.Graphics.Transform = m_matrix
e.Graphics.FillRectangle(lgbDeAct, rectBottom)
e.Graphics.ResetTransform()
e.Graphics.FillRectangle(lgbDeAct, rectTop)
e.Graphics.DrawIcon(ico, rectTop.X + 2, (CaptionHeight - ico.Height) / 2)
'e.Graphics.DrawString(this.Text, m_Font, new SolidBrush(m_TextColorDeAct), rectTop.X + 18, 4);
e.Graphics.DrawString(Me.Text, m_Font, New SolidBrush(m_TextColorDeAct), rectTop.X + ico.Width + 2, (CaptionHeight - m_size.Height) / 2)

End If

e.Graphics.DrawRectangle(New Pen(Color.Empty), rectMove)
DrawCloseButtonNormal()
DrawMinButtonNormal()

End If

End Sub

Protected Overridable Sub OnResize(ByVal sender As Object, ByVal e As EventArgs)
m_Parent.Invalidate()
End Sub

Protected Overridable Sub OnMouseMove(ByVal sender As Object, ByVal e As MouseEventArgs)
If (MouseButtons.Left And e.Button) = MouseButtons.Left Then

If isMove Then

Dim x As Integer = m_Parent.Location.X + (e.X - isPoint.X)
Dim y As Integer = m_Parent.Location.Y + (e.Y - isPoint.Y)
m_Parent.Location = New Point(x, y)

ElseIf rectClose.Contains(e.Location) Then
DrawCloseButtonOver()

ElseIf rectMin.Contains(e.Location) Then
DrawMinButtonOver()

ElseIf Not rectClose.Contains(e.Location) And isClosing Then
isClosing = False
DrawCloseButtonNormal()

ElseIf Not rectMin.Contains(e.Location) And isMinimizing Then
isMinimizing = False
DrawMinButtonNormal()
End If
Else

If rectClose.Contains(e.Location) Then
DrawCloseButtonOver()
Else

DrawCloseButtonNormal()
End If

If rectMin.Contains(e.Location) Then
DrawMinButtonOver()
Else
DrawMinButtonNormal()
End If
End If
End Sub

Protected Overridable Sub OnMouseUp(ByVal sender As Object, ByVal e As MouseEventArgs)
If isMove Then
isMove = False

ElseIf rectClose.Contains(e.Location) And isClosing Then
m_Parent.Close()
ElseIf rectMin.Contains(e.Location) And isMinimizing Then

m_Parent.WindowState = FormWindowState.Minimized
End If
End Sub

Protected Overridable Sub OnMouseDown(ByVal sender As Object, ByVal e As MouseEventArgs)
If (MouseButtons.Left And e.Button) = MouseButtons.Left Then

If rectClose.Contains(e.Location) Then
DrawCloseButtonDown()
isClosing = True

ElseIf rectMin.Contains(e.Location) Then
DrawMinButtonDown()
isMinimizing = True

ElseIf rectMove.Contains(e.Location) Then

isMove = True
isPoint.X = e.X
isPoint.Y = e.Y
End If

End If
End Sub

Protected Overridable Sub OnVisibleChanged(ByVal sender As Object, ByVal e As EventArgs)
If m_Parent.Visible Then
isActive = True
Else
isActive = False
End If
End Sub

#End Region

#Region "Function"

Public Overloads Overrides Function ToString() As String
Return Me.Developer
End Function

Private Function SetWindow() As Region
Dim functionReturnValue As Region = Nothing

Dim Path As New GraphicsPath()
Path.AddArc(0, 0, 10, 10, 180, 90)
Path.AddArc(Me.ClientRectangle.Width - 10, 0, 10, 10, 270, 90)
Path.AddLine(Me.ClientRectangle.Width, 10, Me.ClientRectangle.Width, Me.ClientRectangle.Height)
Path.AddLine(Me.ClientRectangle.Width, Me.ClientRectangle.Height, 0, Me.ClientRectangle.Height)
Path.CloseFigure()
Dim rgn As New Region(Path)

functionReturnValue = rgn
m_Parent.Invalidate()
Return functionReturnValue

End Function

#End Region

#Region "Classes"

Friend Class WindowListener
Inherits NativeWindow

Private Const WM_ACTIVATEAPP As Integer = &H1C
Public Sub New()
End Sub

_
Protected Overloads Overrides Sub WndProc(ByRef m As Message)
Select Case (m.Msg)
Case WM_ACTIVATEAPP
isActive = (m.WParam.ToInt32() <> 0)
CairoSkinPlus.m_Parent.Invalidate()
Exit Select
End Select
MyBase.WndProc(m)
End Sub
End Class

#End Region

End Class
Imports System.Drawing

ملحوظة أخيرة:

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

من المؤكد أن الكود يمكن تطويره للأفضل وهذا متروك لك عزيزي القارئ ومتروك لإبداعك حيث يمكن أن تصمم الشكل الذي تريده وتعطيه من الألوان ما تريد.

جميع الأمثلة موجودة بالمرفقات وهي بنسخة 2008

بالتوفيق

أخوكم عمر

Example11.rar

Skinner.rar

مواضيع مشابهة

عدد الزوار حالياً

المتواجدون خلال آخر دقيقتين · يتحدّث كل ٣٠ ثانية

—الإجمالي—أعضاء مسجّلون—زوار بدون تسجيل

جارٍ التحقق من المتواجدين…