منتدى فيجوال بيسك لكل العرب | منتدى المبرمجين العرب

نسخة كاملة : مقال- أفكار في الجرافكس ....... الجزء الثاني
أنت حالياً تتصفح نسخة خفيفة من المنتدى . مشاهدة نسخة كاملة مع جميع الأشكال الجمالية .
كاتب الموضوع : silverlight


بسم الله الرحمن الرحيم

السلام عليكم ورحمة الله وبركاته

مقدمـــــة:

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

الفكرة الثانية:

الفكرة التي سوف نتحدث عنها اليوم هي كيف نرسم Ribbon أو كيف نرسم Glow

المثال الأول :

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


كود :
Public Class Form1

Private DarkColor As Color = Color.DarkOrange
Private LightColor As Color = Color.Orange
Private rect As New Rectangle(10, 10, 150, 150)
Private angle As Integer

Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
MyBase.OnPaint(e)

' الغرض من رسم هذا المستطيل لكي يعمل كخلفية فقط لتوضيح كيف سيكون شكل القوس الذي نرسمه
e.Graphics.FillRectangle(Brushes.Black, Rect)
angle = 180
Using Path As Drawing2D.GraphicsPath = New Drawing2D.GraphicsPath()
Path.AddArc(Rect, angle, 180)
Using p As Pen = New Pen(DarkColor)
Using lgb As New LinearGradientBrush(Path.GetBounds(), Color.FromArgb(84, LightColor), Color.FromArgb(128, LightColor), LinearGradientMode.Vertical)
e.Graphics.FillPath(lgb, Path)
End Using
e.Graphics.DrawPath(p, Path)
End Using
End Using
End Sub

End Class
أرجو عزيزي القارئ أن تلاحظ قيمة المتغير Angle وقيمته بالمثال أعلاه تساوي صفر
حاول عزيزي القارئ أن تقوم بتغيير قيمة هذا المتغير لكي يساوي 180 أو 90 أو 270 ولاحظ الفارق في كل مرة ستجرب فيها الكود ستكتشف أن إتجاه القوس المرسوم داخل المستطيل يتغير تبعا للزاوية التي نحددها ........

المثال الثاني:

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


كود :
Public Class Form1

Private DarkColor As Color = Color.DarkOrange
Private LightColor As Color = Color.Orange
Private rect As New Rectangle(10, 10, 150, 150)
Private angle As Integer

Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
MyBase.OnPaint(e)

Dim m_blend As New Blend
m_blend.Factors = New Single() {0.0F, 0.4F, 0.8F, 1.0F}
m_blend.Positions = New Single() {0.0F, 0.3F, 0.4F, 1.0F}


' الغرض من رسم هذا المستطيل هو أن يعمل كخلفية فقط لتوضيح كيف سيكون شكل القوس الذي نرسمه
e.Graphics.FillRectangle(Brushes.Black, Rect)

angle = 180
Using Path As Drawing2D.GraphicsPath = New Drawing2D.GraphicsPath()
Path.AddArc(rect, angle, 180)
Using p As Pen = New Pen(DarkColor)
Using lgb As New LinearGradientBrush(Path.GetBounds(), Color.FromArgb(84, LightColor), Color.FromArgb(128, LightColor), LinearGradientMode.Vertical)
lgb.Blend = m_blend
e.Graphics.FillPath(lgb, Path)
End Using
e.Graphics.DrawPath(p, Path)
End Using
End Using


' الغرض من رسم هذا المستطيل هو أن يعمل كخلفية فقط لتوضيح كيف سيكون شكل القوس الذي نرسمه
Dim rect1 As Rectangle = New Rectangle(Rect.X + Rect.Width + 5, Rect.Y, Rect.Width, Rect.Height)
e.Graphics.FillRectangle(Brushes.Black, rect1)

' يتم إعادة رسم هذا الجزء من أجل المقارنة فقط لا غير
Using Path As Drawing2D.GraphicsPath = New Drawing2D.GraphicsPath()
Path.AddArc(rect1, angle, 180)
Using p As Pen = New Pen(DarkColor)
Using lgb As New LinearGradientBrush(Path.GetBounds(), Color.FromArgb(84, LightColor), Color.FromArgb(128, LightColor), LinearGradientMode.Vertical)
e.Graphics.FillPath(lgb, Path)
End Using
e.Graphics.DrawPath(p, Path)
End Using
End Using
End Sub

End Class
لو نظرت جيدا الي ما رسمناه ستجدا أن هناك فارقا قد لا يبدو ظاهرا للعين لأول وهلة لكن لو ركزت عينيك علي ما رسمناه ستجد فارقا في تدرج الألوان بسبب استخدام Blend
حالو تغيير قيم Positions و Factors الخاصة بالكلاس Blend لتكتشف بنفسك اهمية هذا الكلاس في عملية التحكم في تدرج الأولوان

المثال الثالث:

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


كود :
Public Class Form1

Private DarkColor As Color = Color.DarkOrange
Private LightColor As Color = Color.Orange
Private rect As New Rectangle(10, 10, 150, 150)
Private angle As Integer

Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
MyBase.OnPaint(e)

Dim m_blend As New Blend
m_blend.Factors = New Single() {0.0F, 0.4F, 0.8F, 1.0F}
m_blend.Positions = New Single() {0.0F, 0.3F, 0.4F, 1.0F}

' هنا تم رسم شكل بيضاوي بدلا من المستطيل الموجود في المثال السابق
e.Graphics.FillEllipse(Brushes.Black, rect)

angle = 180
Using Path As Drawing2D.GraphicsPath = New Drawing2D.GraphicsPath()
Path.AddArc(rect, angle, 180)
Using p As Pen = New Pen(DarkColor)
Using lgb As New LinearGradientBrush(Path.GetBounds(), Color.FromArgb(84, LightColor), Color.FromArgb(128, LightColor), LinearGradientMode.Vertical)
lgb.Blend = m_blend
e.Graphics.FillPath(lgb, Path)
End Using
e.Graphics.DrawPath(p, Path)
End Using
End Using

' يتم إعادة رسم هذا الجزء من أجل المقارنة فقط لا غير

Dim rect1 As Rectangle = New Rectangle(rect.X + rect.Width + 5, rect.Y, rect.Width, rect.Height)
' هنا تم رسم شكل بيضاوي بدلا من المستطيل الموجود في المثال السابق
e.Graphics.FillEllipse(Brushes.Black, rect1)

Using Path As Drawing2D.GraphicsPath = New Drawing2D.GraphicsPath()
Path.AddArc(rect1, angle, 180)
Using p As Pen = New Pen(DarkColor)
Using lgb As New LinearGradientBrush(Path.GetBounds(), Color.FromArgb(84, LightColor), Color.FromArgb(128, LightColor), LinearGradientMode.Vertical)
e.Graphics.FillPath(lgb, Path)
End Using
e.Graphics.DrawPath(p, Path)
End Using
End Using
End Sub

End Class
لو نظرت الي الرسم جيدا ستجد أن حواف الأقواس المرسومة بها عيوب ظاهرة للعين لذلك يفضل ان نضبط قيمة SmoothingMode ونجعل قيمتها تساوي SmoothingMode.AntiAlias

حاول أيضا عزيزي القارئ ان تقوم بتغيير الألوان المستخدمة في الرسم لكي تلاحظ الفوارق المختلفة في الأمثلة السابقة

المثال الرابع:

قد يتساءل البعض كيف نتحكم في ارتفاع القوس وهنا سنحاول ان نرسم نفس الكود أعلاه ولكن بأسلوب مختلف قليلا


كود :
Public Class Form1

Private DarkColor As Color = Color.Black
Private LightColor As Color = Color.Orange
Private rect As New Rectangle(10, 10, 150, 150)
Private startAngle As Integer
Private sweepAngle As Integer = 100

Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
MyBase.OnPaint(e)

e.Graphics.SmoothingMode = SmoothingMode.AntiAlias

Using path = New GraphicsPath
startAngle = ((180 - sweepAngle) / 2)
path.AddArc(rect, CSng(startAngle), CSng(sweepAngle))
Dim pt As Point = Point.Round(path.PathData.Points(0))
Using lgb = New LinearGradientBrush(New Point(Rect.Left, Rect.Bottom), New Point(Rect.Left, (pt.Y - 1)), DarkColor, Color.FromArgb(50, DarkColor))
e.Graphics.FillPath(lgb, path)
End Using
End Using

End Sub

End Class
أرجو أن تلاحظ عزيزي القارئ كيف يمكن التحكم في ارتفاع القوس عن طريق الربط بين فيمة StartAngle و SweepAngle معا حيث أن الفارق بين القيميتين يعبر عن الفارق في الإرتفاع بين النقطة التي تمثل مركز المستطيل والنقطة التي يبدأ عندها رسم القوس

أيضا أرجو أن تلاحظ كيف تم تحديد أول نقطة موجودة بالمسار GraphicsPath عن طريق تعريف متغير عبارة عن Point وكيف تم ربطها مع PathData وهو عبارة عن ReadOnly Property خاصة بالمسار وهي عبارة عن Array تحدد النقط الكلية الخاصة بشكل المسار GraphicsPath حيث باستخدامها يمكن استرجاع أول وأخر نقطة بالمسار فقط لاغير أما باق النقاط التي تمثل شكل المسار فهناك استحالة تامة لاسترجاع باق القيم الخاصة بها

المثال الخامس:

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


كود :
Public Class Form1

Private DarkColor As Color = Color.Black
Private LightColor As Color = Color.Orange
Private rect As New Rectangle(10, 10, 150, 150)
Private startAngle As Integer
Private sweepAngle As Integer = 130

Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
MyBase.OnPaint(e)

e.Graphics.SmoothingMode = SmoothingMode.AntiAlias

Using path = New GraphicsPath
startAngle = ((180 - sweepAngle) / 2)
path.AddArc(rect, CSng(startAngle), CSng(sweepAngle))
Dim pt As Point = Point.Round(path.PathData.Points(0))

Dim r As Rectangle = rect
r.Inflate(-1, -1)
path.AddArc(r, CSng(startAngle), CSng(sweepAngle))

Using lgb = New LinearGradientBrush(New Point(rect.Left, rect.Bottom), New Point(rect.Left, (pt.Y - 1)), DarkColor, Color.FromArgb(50, DarkColor))
e.Graphics.FillPath(lgb, path)
End Using
End Using

End Sub

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

أرجو أن تحاول عزيزي القارئ أن تجرب جميع الأمثلة أعلاه لكي يتضح لك مدي أهمية كلا من الأقواس Arcs و المسار GraphicsPath في طرق أو عمليات الرسم +GDI المختلفة

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

عموما هناك أفكار كثيرة لكي نتحكم في الألوان وهي ميزة هامة جدا في عمليات +GDI المختلفة حيث أن التحكم في الألوان ودرجاتها وقيمة alpha الخاصة بها ستساعدك كثيرا عزيزى القارئ في الخروج بنتائج رائعة لكي تجعل ما ترسمه يأخذ أشكالا رائعة

المثال السادس :

تخفيف الألوان والمثال التالي يوضح ذلك
لكن عليك ان تلاحظ عزيزي القارئ اهمية استخدام هذا السطر الموجود بالكود lgb.SetSigmaBellShape(0.9)



كود :
Public Class Form1

Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
MyBase.OnPaint(e)

' تعريف متغير يشير الي اللون الأصلي
Dim baseColor As Color = Color.Orange
Dim rect As New Rectangle(10, 10, 150, 150)

' هذه القيمة سوف تحدد الدرجة التي نحتاجها لتخفيقف اللون الأصلي
' هذه القيمة يجب أن لا تقل عن صفر ويجب أن لا تزيد عن 100
Dim percent As Integer = 80

' تحديد القيم الخاصة باللون الجديد
Dim alpha As Integer = baseColor.A
Dim red = baseColor.R + CInt(((255 - baseColor.R) / 100) * percent)
Dim green = baseColor.G + CInt(((255 - baseColor.G) / 100) * percent)
Dim blue = baseColor.B + CInt(((255 - baseColor.B) / 100) * percent)
' تعريف اللون الجديد
Dim lightColor As Color = Color.FromArgb(alpha, red, green, blue)

' رسم أي شي باستخدام اللون الأصلي واللون الجديد معا
Using lgb As New Drawing2D.LinearGradientBrush(rect, baseColor, lightColor, Drawing2D.LinearGradientMode.Vertical)
lgb.SetSigmaBellShape(0.9)
e.Graphics.FillEllipse(lgb, rect)
End Using

End Sub

End Class
المثال السابع:

تغميق الألون والمثال التالي يوضح ذلك


كود :
Public Class Form1

Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
MyBase.OnPaint(e)

' تعريف متغير يشير الي اللون الأصلي
Dim baseColor As Color = Color.Orange
Dim rect As New Rectangle(10, 10, 150, 150)

' هذه القيمة سوف تحدد الدرجة التي نحتاجها لتغميق اللون الأصلي
' هذه القيمة يجب أن لا تقل عن صفر ويجب أن لا تزيد عن 100
Dim percent As Integer = 80

' الحصول علي لون غامق من اللون الأصلي
Dim alphaDark As Integer = baseColor.A
Dim redDark = baseColor.R - CInt(((baseColor.R) / 100) * percent)
Dim greenDark = baseColor.G - CInt(((baseColor.G) / 100) * percent)
Dim blueDark = baseColor.B - CInt(((baseColor.B) / 100) * percent)
' تعريف اللون الجديد
Dim darkColor As Color = Color.FromArgb(alphaDark, redDark, greenDark, blueDark)

' رسم أي شي باستخدام اللون الأصلي واللون الجديد معا
Using lgb As New Drawing2D.LinearGradientBrush(rect, baseColor, darkColor, Drawing2D.LinearGradientMode.Vertical)
lgb.SetSigmaBellShape(0.9)
e.Graphics.FillEllipse(lgb, rect)
End Using

End Sub

End Class

المثال الثامن:

هنا سنحاول استخدام المثال السادس والسابع لنخرج بكود مختلف قليلا وعليك عزيزي القارئ أن تلاحظ الفارق حاول أن تتحكم في قيمة المتغير الذي يؤثر علي درجة تفتيح أو تغميق اللون


كود :
Public Class Form1

Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
MyBase.OnPaint(e)

' تعريف متغير يشير الي اللون الأصلي
Dim baseColor As Color = Color.Orange
Dim rect As New Rectangle(10, 10, 150, 150)

' هذه القيمة سوف تحدد الدرجة التي نحتاجها لتغميق اللون الأصلي
' هذه القيمة يجب أن لا تقل عن صفر ويجب أن لا تزيد عن 100
Dim percent As Integer = 20

' الحصول علي لون غامق من اللون الأصلي
Dim alphaDark As Integer = baseColor.A
Dim redDark = baseColor.R - CInt(((baseColor.R) / 100) * percent)
Dim greenDark = baseColor.G - CInt(((baseColor.G) / 100) * percent)
Dim blueDark = baseColor.B - CInt(((baseColor.B) / 100) * percent)
' تعريف اللون الجديد
Dim darkColor As Color = Color.FromArgb(alphaDark, redDark, greenDark, blueDark)

' تغيير قيمة هذا المتغير حتي نتحكم في درجة اللون الفاتح
percent = 80
' الحصول علي لون خفيف من اللون الأصلي
Dim alphaLight As Integer = baseColor.A
Dim redLight = baseColor.R + CInt(((255 - baseColor.R) / 100) * percent)
Dim greenLight = baseColor.G + CInt(((255 - baseColor.G) / 100) * percent)
Dim blueLight = baseColor.B + CInt(((255 - baseColor.B) / 100) * percent)
Dim lightColor As Color = Color.FromArgb(alphaLight, redLight, greenLight, blueLight)

' رسم أي شي باستخدام اللون الغامق واللون الفاتح معا
Using lgb As New Drawing2D.LinearGradientBrush(rect, lightColor, darkColor, Drawing2D.LinearGradientMode.Vertical)
lgb.SetSigmaBellShape(0.9)
e.Graphics.FillEllipse(lgb, rect)
End Using
End Sub

End Class
أعتقد أننا نستطيع أن نبني من الأفكار أعلاه دالتين أحدهما تستخدم في تخفيف اللون والأخري في تغميق اللون .......................... جرب وحاول بنفسك عزيز القارئ أن تبني مثل هاتين الدالتين

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

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

المثال التاسع:


كود :
Imports System.Drawing.Drawing2D

Public Class Form1

Private DarkColor As Color = Color.DarkOrange
Private LightColor As Color = Color.Orange
Private rect As New Rectangle(10, 10, 150, 150)
Private angle As Integer = 180

Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
MyBase.OnPaint(e)

Dim DarkColor As Color = Color.Orange
Dim LightColor As Color = Color.Yellow
Dim rect As New Rectangle(10, 10, 100, 100)
Dim WhiteColor As Color = Color.White
Dim darkRatio As Integer = 16
Dim scale As SizeF = New SizeF(CSng(rect.Width / 100), CSng(rect.Height / 100))
Dim sigmaBlend As New Blend
sigmaBlend.Factors = New Single() {0.0F, 0.4F, 0.8F, 1.0F}
sigmaBlend.Positions = New Single() {0.0F, 0.3F, 0.4F, 1.0F}

Dim darkerColor As Color = DarkColor

Dim mode As SmoothingMode = e.Graphics.SmoothingMode
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias

Dim darkerColorAlpha As Integer = darkerColor.A
Dim darkerColorRed As Integer = darkerColor.R - CInt(((darkerColor.R) / 100) * darkRatio)
Dim darkerColorGreen As Integer = darkerColor.G - CInt(((darkerColor.G) / 100) * darkRatio)
Dim darkerColorBlue As Integer = darkerColor.B - CInt(((darkerColor.B) / 100) * darkRatio)

Dim glowColor As Color = Color.FromArgb(darkerColorAlpha, darkerColorRed, darkerColorGreen, darkerColorBlue)

Using Path As Drawing2D.GraphicsPath = New Drawing2D.GraphicsPath()
Path.AddEllipse(rect)
Dim pgb As New Drawing2D.PathGradientBrush(Path)
pgb.CenterPoint = New PointF(rect.Left + (rect.Width / 2), rect.Bottom + (33 * scale.Height))
pgb.CenterColor = Color.FromArgb(255, LightColor)
' Creates a gradient falloff based on a bell-shaped curve.
pgb.SetSigmaBellShape(0.85)

If darkerColor.GetBrightness >= 0.3 Then
darkerColor = glowColor
End If

pgb.SurroundColors = New Color() {Color.FromArgb(255, darkerColor)}
e.Graphics.FillEllipse(pgb, rect)
End Using

Using Path As Drawing2D.GraphicsPath = New Drawing2D.GraphicsPath()
Path.AddArc(rect, angle, angle)
Using p As Pen = New Pen(glowColor)
Using lgb As New LinearGradientBrush(Path.GetBounds(), Color.FromArgb(64, WhiteColor), Color.FromArgb(84, WhiteColor), LinearGradientMode.Vertical)
lgb.Blend = sigmaBlend
e.Graphics.FillPath(lgb, Path)
End Using
e.Graphics.DrawPath(p, Path)
End Using
End Using

Dim blender As Drawing2D.Blend = New Drawing2D.Blend()
blender.Positions = New Single() {0, 0.9, 1}
blender.Factors = New Single() {0, 1, 1}

Dim sweepRectangle As Rectangle = rect
sweepRectangle.Height -= (rect.Height / 2)
sweepRectangle.Inflate(-16 * scale.Width, -3 * scale.Height)
Using lgb As New Drawing2D.LinearGradientBrush(sweepRectangle, WhiteColor, Color.Empty, 90, True)
sweepRectangle.Height -= scale.Height / 2
lgb.Blend = blender
e.Graphics.FillEllipse(lgb, sweepRectangle)
End Using

Using borderPen As New Pen(glowColor, 2)
Dim borderRect As Rectangle = rect
e.Graphics.DrawEllipse(borderPen, borderRect)
End Using

e.Graphics.SmoothingMode = mode

End Sub

End Class

بالتأكيد يمكننا ان نرسم ما نريد أو نعدل بالكود كيفما شئنا ولكنك سوف تلاحظ عزيزي القارئ أننا لم نأتي بشئ جديد كل ما في الأمر أننا استخدمنا اوامر +GDI المختلفة والموجودة بالفعل بالدوت نت ولكن بصورة أكثر فعالية حتي نحصل علي الشكل النهائي لما نريد
وفي الكود أعلاه حاول أن تلاحظ كيفية استخدام الكلاسات Blend و LinearGradientBrush و PathGradientBrush ولاحظ أيضا كيف نتأكد من Brightness الخاصة بلون ما فإذا كانت أقل من ما نريد فإننا نقوم بتغيير اللون الي لون أخر قاتم قليلا ولكنه يأتي من نفس اللون


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


كود :
Private Sub DrawGlowRibbon(ByVal g As Graphics, ByVal rect As Rectangle, ByVal darkColor As Color, ByVal lightColor As Color)

Dim mode As SmoothingMode = g.SmoothingMode
g.SmoothingMode = SmoothingMode.AntiAlias

Dim darkRatio As Integer = 16
Dim WhiteColor As Color = Color.White

Dim sigmaBlend As New Blend
sigmaBlend.Factors = New Single() {0.0F, 0.4F, 0.8F, 1.0F}
sigmaBlend.Positions = New Single() {0.0F, 0.3F, 0.4F, 1.0F}

Dim scale As SizeF = New SizeF(CSng(rect.Width / 100), CSng(rect.Height / 100))
Dim darkerColor As Color = darkColor

Dim darkerColorAlpha As Integer = darkerColor.A
Dim darkerColorRed As Integer = darkerColor.R - CInt(((darkerColor.R) / 100) * darkRatio)
Dim darkerColorGreen As Integer = darkerColor.G - CInt(((darkerColor.G) / 100) * darkRatio)
Dim darkerColorBlue As Integer = darkerColor.B - CInt(((darkerColor.B) / 100) * darkRatio)
Dim glowColor As Color = Color.FromArgb(darkerColorAlpha, darkerColorRed, darkerColorGreen, darkerColorBlue)

Using Path As Drawing2D.GraphicsPath = New Drawing2D.GraphicsPath()
Path.AddEllipse(rect)
Dim pgb As New Drawing2D.PathGradientBrush(Path)
pgb.CenterPoint = New PointF(rect.Left + (rect.Width / 2), rect.Bottom + (33 * scale.Height))
pgb.CenterColor = Color.FromArgb(255, lightColor)
pgb.SetSigmaBellShape(0.85)
If darkerColor.GetBrightness >= 0.3 Then
darkerColor = glowColor
End If
pgb.SurroundColors = New Color() {Color.FromArgb(255, darkerColor)}
g.FillEllipse(pgb, rect)
End Using

Using Path As Drawing2D.GraphicsPath = New Drawing2D.GraphicsPath()
Path.AddArc(rect, 180, 180)
Using p As Pen = New Pen(glowColor)
Using lgb As New LinearGradientBrush(Path.GetBounds(), Color.FromArgb(64, WhiteColor), Color.FromArgb(84, WhiteColor), LinearGradientMode.Vertical)
lgb.Blend = sigmaBlend
g.FillPath(lgb, Path)
End Using
g.DrawPath(p, Path)
End Using
End Using

Dim blender As Drawing2D.Blend = New Drawing2D.Blend()
blender.Positions = New Single() {0, 0.9, 1}
blender.Factors = New Single() {0, 1, 1}

Dim sweepRectangle As Rectangle = rect
sweepRectangle.Height -= (rect.Height / 2)
sweepRectangle.Inflate(-16 * scale.Width, -3 * scale.Height)
Using lgb As New Drawing2D.LinearGradientBrush(sweepRectangle, WhiteColor, Color.Empty, 90, True)
sweepRectangle.Height -= scale.Height / 2
lgb.Blend = blender
g.FillEllipse(lgb, sweepRectangle)
End Using

Using borderPen As New Pen(darkerColor, 2)
Dim borderRect As Rectangle = rect
g.DrawEllipse(borderPen, borderRect)
End Using

g.SmoothingMode = mode
End Sub
التطبيق النهائي:

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


كود :
Imports System.Drawing.Drawing2D

Public Class RibbonButton
Inherits Control

Private DarkColor As Color
Private LightColor As Color
Private rect As Rectangle
Private Path As GraphicsPath
Private m_state As ButtonState = ButtonState.Normal

Public Sub New()

Me.SetStyle(ControlStyles.OptimizedDoubleBuffer, True)
Me.SetStyle(ControlStyles.AllPaintingInWmPaint, True)
Me.SetStyle(ControlStyles.UserPaint, True)
Me.UpdateStyles()

Me.SetNormalstate()
Me.SetGraphicsData()

End Sub

Protected Overrides ReadOnly Property DefaultSize() As System.Drawing.Size
Get
Return New Size(50, 50)
End Get
End Property

Private Sub SetGraphicsData()
Path = New GraphicsPath()
Path.AddEllipse(Me.ClientRectangle)
Dim rgn As New Region(Path)
Me.Region = rgn
rect = New Rectangle(Me.ClientRectangle.X + 1, Me.ClientRectangle.Y + 1, Me.ClientRectangle.Width - 2, Me.ClientRectangle.Height - 2)
End Sub

Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
MyBase.OnPaint(e)

Select Case m_state

Case ButtonState.Default, ButtonState.Disabled, ButtonState.Normal
SetNormalstate()
DrawGlowRibbon(e.Graphics, rect, DarkColor, LightColor)

Exit Select

Case ButtonState.Hot
SetHoverstate()
DrawGlowRibbon(e.Graphics, rect, DarkColor, LightColor)
Exit Select
Case ButtonState.Pressed

SetPressedState()
DrawGlowRibbon(e.Graphics, rect, DarkColor, LightColor)
End Select

End Sub

Protected Overrides Sub OnMouseEnter(ByVal e As System.EventArgs)
MyBase.OnMouseEnter(e)
m_state = ButtonState.Hot
Invalidate()
End Sub

Protected Overrides Sub OnMouseDown(ByVal e As System.Windows.Forms.MouseEventArgs)
MyBase.OnMouseDown(e)

m_state = ButtonState.Pressed
Invalidate()

End Sub

Protected Overrides Sub OnMouseUp(ByVal e As System.Windows.Forms.MouseEventArgs)
MyBase.OnMouseUp(e)
OnMouseEnter(e)
End Sub

Protected Overrides Sub OnMouseMove(ByVal e As System.Windows.Forms.MouseEventArgs)
MyBase.OnMouseMove(e)

If (e.Button And MouseButtons.Left) = MouseButtons.Left And Not rect.Contains(e.Location) And m_state = ButtonState.Pressed Then
OnMouseLeave(e)
End If
End Sub

Protected Overrides Sub OnMouseLeave(ByVal e As System.EventArgs)
MyBase.OnMouseLeave(e)

m_state = ButtonState.Default
Invalidate()

End Sub

Protected Overrides Sub OnResize(ByVal e As System.EventArgs)
MyBase.OnResize(e)
SetGraphicsData()
Invalidate()
End Sub

Protected Overrides Sub OnSizeChanged(ByVal e As EventArgs)
MyBase.OnSizeChanged(e)
SetGraphicsData()
End Sub

Private Sub DrawGlowRibbon(ByVal g As Graphics, ByVal rect As Rectangle, ByVal darkColor As Color, ByVal lightColor As Color)

Dim mode As SmoothingMode = g.SmoothingMode
g.SmoothingMode = SmoothingMode.AntiAlias

Dim darkRatio As Integer = 16
Dim WhiteColor As Color = Color.White

Dim sigmaBlend As New Blend
sigmaBlend.Factors = New Single() {0.0F, 0.4F, 0.8F, 1.0F}
sigmaBlend.Positions = New Single() {0.0F, 0.3F, 0.4F, 1.0F}

Dim scale As SizeF = New SizeF(CSng(rect.Width / 100), CSng(rect.Height / 100))
Dim darkerColor As Color = darkColor

Dim darkerColorAlpha As Integer = darkerColor.A
Dim darkerColorRed As Integer = darkerColor.R - CInt(((darkerColor.R) / 100) * darkRatio)
Dim darkerColorGreen As Integer = darkerColor.G - CInt(((darkerColor.G) / 100) * darkRatio)
Dim darkerColorBlue As Integer = darkerColor.B - CInt(((darkerColor.B) / 100) * darkRatio)
Dim glowColor As Color = Color.FromArgb(darkerColorAlpha, darkerColorRed, darkerColorGreen, darkerColorBlue)

Using Path As Drawing2D.GraphicsPath = New Drawing2D.GraphicsPath()
Path.AddEllipse(rect)
Dim pgb As New Drawing2D.PathGradientBrush(Path)
pgb.CenterPoint = New PointF(rect.Left + (rect.Width / 2), rect.Bottom + (33 * scale.Height))
pgb.CenterColor = Color.FromArgb(255, lightColor)
pgb.SetSigmaBellShape(0.85)
If darkerColor.GetBrightness >= 0.3 Then
darkerColor = glowColor
End If
pgb.SurroundColors = New Color() {Color.FromArgb(255, darkerColor)}
g.FillEllipse(pgb, rect)
End Using

Using Path As Drawing2D.GraphicsPath = New Drawing2D.GraphicsPath()
Path.AddArc(rect, 180, 180)
Using p As Pen = New Pen(glowColor)
Using lgb As New LinearGradientBrush(Path.GetBounds(), Color.FromArgb(64, WhiteColor), Color.FromArgb(84, WhiteColor), LinearGradientMode.Vertical)
lgb.Blend = sigmaBlend
g.FillPath(lgb, Path)
End Using
g.DrawPath(p, Path)
End Using
End Using

Dim blender As Drawing2D.Blend = New Drawing2D.Blend()
blender.Positions = New Single() {0, 0.9, 1}
blender.Factors = New Single() {0, 1, 1}

Dim sweepRectangle As Rectangle = rect
sweepRectangle.Height -= (rect.Height / 2)
sweepRectangle.Inflate(-16 * scale.Width, -3 * scale.Height)
Using lgb As New Drawing2D.LinearGradientBrush(sweepRectangle, WhiteColor, Color.Empty, 90, True)
sweepRectangle.Height -= scale.Height / 2
lgb.Blend = blender
g.FillEllipse(lgb, sweepRectangle)
End Using

Using borderPen As New Pen(darkerColor, 2)
Dim borderRect As Rectangle = rect
g.DrawEllipse(borderPen, borderRect)
End Using

g.SmoothingMode = mode
End Sub

Private Sub SetNormalstate()
DarkColor = Color.Blue
LightColor = Color.Cyan
End Sub

Private Sub SetHoverstate()
DarkColor = Color.Maroon
LightColor = Color.LightYellow
End Sub

Private Sub SetPressedState()
DarkColor = Color.DarkOrange
LightColor = Color.Yellow
End Sub

#Region " Enum "

<Flags()> _
Private Enum ButtonState
Normal = &H0
Hot = &H1
Pressed = &H2
Disabled = &H4
[Default] = &H8
End Enum

#End Region

End Class

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

المثال بالمرفقات بنسخة الفيجوال استوديو 2008
أتمني ان تكون الأفكار التي تحدثنا عنها مفيدة للبعض منكم بشكل ما ...... أعتقد أنكم يمكنك تطوير الكلاس مثل رسم Text أو رسم صورة ما داخل Ribbon أو إضافة الكثير من Property له ليتناسب مع ما احتياجاتكم

أتمني أن نري إبداعاتكم المختلفة من خلال مشاركتكم اللاحقة

تقبلوا تحياتي
أخوكم عمر