03-10-12, 09:15 AM
كاتب الموضوع : silverlight
الموضوع : تطوير الكزنترول Rendering Controlاللغة المستخدمة: الفيجوال بيسك
التطبيق: فيجوال استوديو 2005 و 2008
المستوي: التقييم متروك للقارئ
إعداد: مهندس / عمر أمين إبراهيم
ماذا تعني كلمة Rendering ؟
الإجابة ببساطه شديدة أن هذه الكلمة تعني رسم واجهة التطبيق التي يتعامل معها المستخدم أو كما يطلق عليها User Interface ولكي نقوم بذلك فإننا نستخدم VisualStyles الموجودة في نظام التشغيل مثل Windows XP علي سبيل المثال وعموما واجهة التطبيق ممكن تكون أي شئ إما كونترول معين أو فورم.
ولتوضيح الأمر قليلا لو نظرت الي أي فورم عادي ستجد في اعلاه مجموعه من الباتون مثل Close و Maximize و Minimize وهي مناطق لا تستطيع تغييرها فهي موجودة في كل فورم تقوم بإنشائه في الفيجوال استوديو وكل هذه الباتون تم رسمها باستخدام VisualStyles Class
طبعا كلنا نحلم بتغيير الشكل التقليدي للفورم أو للكونترول بشكل عام وكلنا نريد أن يظهر البرنامج الذي نصممه في أجمل شكل لكي نبهر المستخدم أو نشجعه علي شراء المنتج الذي نصممه. الحقيقة الموضوع مش صعب لكنه محتاج وقت وهو مكلف من هذه الناحية لأنه يأخذ وقت كثير جدا لكي نبني ونرسم كل جزء إما في الفورم أو في الكونترول لأننا سوف نقوم برسم الكونترول أو الفورم في كل حالاته مثلا عند دخول الماوس أو عند خروج الماوس أو عند الضغط علي الماوس أو عند تحريك الكونترول أو الفورم أو عند تغيير مقاس الكونترول أو الفورم وهكذا
منذ سنوات وتحديدا عندما قامت مايكروسوفت بإصدار Windows XP كلنا لاحظنا التكنولوجيا المستخدمة في إظهار الكونترول أو الفورم بشكل لطيف يشد انتباه المستخدم كل هذا تم باستخدام VisualStyles
طبعا في السنوات الأخيرة بدأت تظهر شركات كثيرة وهذه الشركات قائمة فقط علي تطوير الكونترول وإعطاؤه الشكل الجمالي الذي يريده المستخدم أو المبرمج بشكل خاص وطبعا كلكم تعلمون عن هذه المنتجات جيدا وتعاملتم معها.
لن أطيل عليكم كثيرا في الحديث عن تاريخ VisualStyles وكيف تم صنعها فأنتم تعلمون عنها الكثير ولكن كيف لنا أن نغير شكل الكونترول أو تحديدا كيف نغير في شكل الكونترول التقليدي الموجود مع الفيجوال استوديو باستخدام Rendering
في الواقع هناك القليل من Classes التي تتعامل مع Control Rendering وهي مقسمة الي فئتان بعضها يسمح برسم الكونترول سواء استخدمنا VisualStyles أم لا والبعض الأخر منها يحتاج الي وجود VisualStyles وبدونها سيحدث خطأ أو Error أثناء رسم هذه الكونترول وهذه الكونترول مرتبه كالأتي
Button
CheckBox
GroupBox
RadioButton
تلك العناصر الأربعة كل منها يملك كلاس خاص به يقوم بعمل Rendering وكما أسلفنا فإن هذه Classes تنتمي الي الفئة الأولي التي من الممكن استخدامها لرسم الكونترول في وجود أو عدم وجود VisualStyles
أما الفئة الثانية والتي تحتاج الي وجود VisualStyles فهي مقسمة كما يلي وأيضا كل منها يمتلك كلاس خاص به يقوم بعملية Rendering وهذه الكلاس كالأتي
ComboBox
ProgressBar
ScrollBar
Tab
Textbox
TrackBar
لو بحثت جيدا في مواقع مايكروسوفت ستجد أنها قد قامت بإعطاء فكرة عن كيفية التعامل مع هذه الكونترول تحديدا وكيفية استخدام Rendering Classes في تغيير شكل الكونترول أو تصميمه من الصفر أو مثلما يقولون From Scratch
لكن مايكروسوفت استخدمت VisualStyles الموجودة في نظام التشغيل لكي ترسم هذه الكونترول المختلفة إذن الأمر في النهاية لا يوجد هناك شيئا جديدا لكي نستفيد منه في تصميم كونترول له شكل مبهر للمستخدم. كيف نجد حلا لهه المعضلة؟ الامر بسيط جدا يجب أن نبني VisualStyles Classes بأنفسنا لكي نستطيع تغيير الشكل الكلاسيكي للكونترول المختلفة
كيف نبني Our VisualStyles Classes لكي نحصل علي كونترول له شكل مناسب ومختلف عن الكونترول الكلاسيكي الموجود في الفيجوال استوديو إن هدف هذا المقال هو الإجابة علي هذا السؤال تحديدا ولكي نفعل ذلك سوف نعطي مثالا عمليا مثل ScrollBar
لن ادخل في تفاصيل بناء ScrollBar فهناك أمثلة كثيرة علي ذلك موجودة في الكثير من المواقع وسوف اختار مثالا موجودا بالفعل في مواقع مايكروسوفت والكود التالي يوضح المثال الذي أعطته مايكروسوفت لبناء ScrollBar عن طريق الوراثة Inherits للكونترول كلاس
لنفتح Windows Application Form ونضيف له الكلاس التالي ولسوف نطلق عليه MSCustomScrollBar
كود :
Imports System.Windows.Forms.VisualStyles
Public Class MsCustomScrollBar
Inherits Control
Private clickedBarRectangle As Rectangle
Private thumbRectangle As Rectangle
Private leftArrowRectangle As Rectangle
Private rightArrowRectangle As Rectangle
Private leftArrowClicked As Boolean = False
Private rightArrowClicked As Boolean = False
Private leftBarClicked As Boolean = False
Private rightBarClicked As Boolean = False
Private thumbClicked As Boolean = False
Private thumbState As ScrollBarState = ScrollBarState.Normal
Private leftButtonState As ScrollBarArrowButtonState = _
ScrollBarArrowButtonState.LeftNormal
Private rightButtonState As ScrollBarArrowButtonState = _
ScrollBarArrowButtonState.RightNormal
' This control does not allow these widths to be altered.
Private thumbWidth As Integer = 15
Private arrowWidth As Integer = 17
' Set the right limit of the thumb's right border.
Private thumbRightLimitRight As Integer = 0
' Set the right limit of the thumb's left border.
Private thumbRightLimitLeft As Integer = 0
' Set the left limit of thumb's left border.
Private thumbLeftLimit As Integer = 0
' Set the distance from the left edge of the thumb to the
' cursor tip.
Private thumbPosition As Integer = 0
' Set the distance from the left edge of the scroll bar track to
' the cursor tip.
Private trackPosition As Integer = 0
' This timer draws the moving thumb while the scroll arrows or
' track are pressed.
Private WithEvents progressTimer As New Timer()
Public Sub New()
With Me
.Location = New Point(10, 10)
.Width = 200
.Height = 20
.DoubleBuffered = True
End With
SetUpScrollBar()
progressTimer.Interval = 20
End Sub
' Calculate the sizes of the scroll bar elements.
Private Sub SetUpScrollBar()
clickedBarRectangle = Me.ClientRectangle
thumbRectangle = New Rectangle(ClientRectangle.X + _
Me.ClientRectangle.Width / 2, Me.ClientRectangle.Y, _
thumbWidth, Me.ClientRectangle.Height)
leftArrowRectangle = New Rectangle(Me.ClientRectangle.X, _
Me.ClientRectangle.Y, arrowWidth, Me.ClientRectangle.Height)
rightArrowRectangle = New Rectangle(Me.ClientRectangle.Right - _
arrowWidth, Me.ClientRectangle.Y, arrowWidth, _
Me.ClientRectangle.Height)
' Set the default starting thumb position.
thumbPosition = thumbWidth / 2
' Set the right limit of the thumb's right border.
thumbRightLimitRight = Me.ClientRectangle.Right - arrowWidth
' Set the right limit of the thumb's left border.
thumbRightLimitLeft = thumbRightLimitRight - thumbWidth
' Set the left limit of the thumb's left border.
thumbLeftLimit = Me.ClientRectangle.X + arrowWidth
End Sub
' Draw the scroll bar in its normal state.
Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
MyBase.OnPaint(e)
' Visual styles are not enabled.
If Not ScrollBarRenderer.IsSupported Then
Me.Parent.Text = "CustomScrollBar Disabled"
Return
End If
Me.Parent.Text = "CustomScrollBar Enabled"
' Draw the scroll bar track.
ScrollBarRenderer.DrawRightHorizontalTrack(e.Graphics, _
Me.ClientRectangle, ScrollBarState.Normal)
' Draw the thumb and thumb grip in the current state.
ScrollBarRenderer.DrawHorizontalThumb(e.Graphics, _
thumbRectangle, thumbState)
ScrollBarRenderer.DrawHorizontalThumbGrip(e.Graphics, _
thumbRectangle, thumbState)
' Draw the scroll arrows in the current state.
ScrollBarRenderer.DrawArrowButton(e.Graphics, _
leftArrowRectangle, leftButtonState)
ScrollBarRenderer.DrawArrowButton(e.Graphics, _
rightArrowRectangle, rightButtonState)
' Draw a highlighted rectangle in the left side of the scroll
' bar track if the user has clicked between the left arrow
' and thumb.
If leftBarClicked Then
clickedBarRectangle.X = thumbLeftLimit
clickedBarRectangle.Width = thumbRectangle.X - thumbLeftLimit
ScrollBarRenderer.DrawLeftHorizontalTrack(e.Graphics, _
clickedBarRectangle, ScrollBarState.Pressed)
' Draw a highlighted rectangle in the right side of the scroll
' bar track if the user has clicked between the right arrow
' and thumb.
ElseIf rightBarClicked Then
clickedBarRectangle.X = thumbRectangle.X + _
thumbRectangle.Width
clickedBarRectangle.Width = thumbRightLimitRight - _
clickedBarRectangle.X
ScrollBarRenderer.DrawRightHorizontalTrack(e.Graphics, _
clickedBarRectangle, ScrollBarState.Pressed)
End If
End Sub
' Handle a mouse click in the scroll bar.
Protected Overrides Sub OnMouseDown(ByVal e As MouseEventArgs)
MyBase.OnMouseDown(e)
If Not ScrollBarRenderer.IsSupported Then
Return
End If
' When the thumb is clicked, update the distance from the left
' edge of the thumb to the cursor tip.
If thumbRectangle.Contains(e.Location) Then
thumbClicked = True
thumbPosition = e.Location.X - thumbRectangle.X
thumbState = ScrollBarState.Pressed
' When the left arrow is clicked, start the timer to scroll
' while the arrow is held down.
ElseIf leftArrowRectangle.Contains(e.Location) Then
leftArrowClicked = True
leftButtonState = ScrollBarArrowButtonState.LeftPressed
progressTimer.Start()
' When the right arrow is clicked, start the timer to scroll
' while arrow is held down.
ElseIf rightArrowRectangle.Contains(e.Location) Then
rightArrowClicked = True
rightButtonState = ScrollBarArrowButtonState.RightPressed
progressTimer.Start()
' When the scroll bar is clicked, start the timer to move the
' thumb while the mouse is held down.
Else
trackPosition = e.Location.X
If e.Location.X < Me.thumbRectangle.X Then
leftBarClicked = True
Else
rightBarClicked = True
End If
progressTimer.Start()
End If
Invalidate()
End Sub
' Draw the track.
Protected Overrides Sub OnMouseUp(ByVal e As MouseEventArgs)
MyBase.OnMouseUp(e)
If Not ScrollBarRenderer.IsSupported Then
Return
End If
' Update the thumb position, if the new location is within
' the bounds.
If thumbClicked Then
thumbClicked = False
thumbState = ScrollBarState.Normal
If e.Location.X > thumbLeftLimit + thumbPosition And _
e.Location.X < thumbRightLimitLeft + thumbPosition Then
thumbRectangle.X = e.Location.X - thumbPosition
thumbClicked = False
End If
' If one of the four thumb movement areas was clicked,
' stop the timer.
ElseIf leftArrowClicked Then
leftArrowClicked = False
leftButtonState = ScrollBarArrowButtonState.LeftNormal
progressTimer.Stop()
ElseIf rightArrowClicked Then
rightArrowClicked = False
rightButtonState = ScrollBarArrowButtonState.RightNormal
progressTimer.Stop()
ElseIf leftBarClicked Then
leftBarClicked = False
progressTimer.Stop()
ElseIf rightBarClicked Then
rightBarClicked = False
progressTimer.Stop()
End If
Invalidate()
End Sub
' Track mouse movements if the user clicks on the scroll bar thumb.
Protected Overrides Sub OnMouseMove(ByVal e As MouseEventArgs)
MyBase.OnMouseMove(e)
If Not ScrollBarRenderer.IsSupported Then
Return
End If
' Update the thumb position, if the new location is
' within the bounds.
If thumbClicked Then
' The thumb is all the way to the left.
If e.Location.X <= thumbLeftLimit + thumbPosition Then
thumbRectangle.X = thumbLeftLimit
' The thumb is all the way to the right.
ElseIf e.Location.X >= thumbRightLimitLeft + thumbPosition Then
thumbRectangle.X = thumbRightLimitLeft
' The thumb is between the ends of the track.
Else
thumbRectangle.X = e.Location.X - thumbPosition
End If
Invalidate()
End If
End Sub
' Recalculate the sizes of the scroll bar elements.
Protected Overrides Sub OnSizeChanged(ByVal e As EventArgs)
MyBase.OnSizeChanged(e)
SetUpScrollBar()
End Sub
' Handle the timer tick by updating the thumb position.
Private Sub progressTimer_Tick(ByVal sender As Object, _
ByVal myEventArgs As EventArgs) Handles progressTimer.Tick
If Not ScrollBarRenderer.IsSupported Then
Return
End If
' If an arrow is clicked, move the thumb in small increments.
If rightArrowClicked And thumbRectangle.X < thumbRightLimitLeft Then
thumbRectangle.X += 1
ElseIf leftArrowClicked And thumbRectangle.X > thumbLeftLimit Then
thumbRectangle.X -= 1
' If the track bar to right of the thumb is clicked, move the
' thumb to the right in larger increments until the right edge
' of the thumb hits the cursor.
ElseIf rightBarClicked And thumbRectangle.X < thumbRightLimitLeft _
And thumbRectangle.X + thumbRectangle.Width < trackPosition Then
thumbRectangle.X += 3
' If the track bar to left of the thumb is clicked, move the
' thumb to the left in larger increments until the left edge
' of the thumb hits the cursor.
ElseIf leftBarClicked And thumbRectangle.X > thumbLeftLimit And _
thumbRectangle.X > trackPosition Then
thumbRectangle.X -= 3
End If
Invalidate()
End Sub
End Class