تقييم الموضوع :
  • 0 أصوات - بمعدل 0
  • 1
  • 2
  • 3
  • 4
  • 5
مقال - الصور المتحركة في الدوت نت Animation الجزء الثاني
#1
كاتب الموضوع : silverlight

الموضوع : الصور المتحركة في الدوت نت Animation
اللغة المستخدمة: الفيجوال بيسك
التطبيق: فيجوال استوديو 2008
الدوت نت : .Net Framework 3.5

مـقـدمـة:

اليوم سنناقش نفس الموضوع ولكن برؤية تختلف قليلا عن ما هو موجود في الجزء الأول.
أيضا سوف نناقش أفكارا إضافية يمكن استخدامها للتعامل مع الصور Image Processing ورسمها بالشكل الذي نريده علي أن تكون المحصلة النهائية هي بناء كونترول يمكن إستخدامه في برامجنا

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

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

كما يعلم الجميع أن فكرة الحركة Animation مبنية علي إستخدام Timer ومن ثم نستخدم هذا Timer في تحريك أي شئ نريده مثل سلسلة من الصور أو الكلمات أو أي شئ أخر وبالتالي نعطي الإيحاء بعملية الحركة

وبناء Slides مثل الموجودة في برنامج Power Point تستخدم نفس التكنولوجيا أو نفس الأسلوب تقريبا فهي تعتمد علي Timer ومن ثم يتم رسم أي شئ مثل الصور أو Text أو أي شئ أخر باستخدام +GDI

ما هو الدور الذي تقوم به +GDI ؟

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

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

السؤال الأول:
هل من الممكن إعادة رسم صورة في أي شكل نريده؟
بالتأكيد نستطيع أن نرسم أي شئ في الشكل الذي نريد والمسئول عن كيفية تنفيذ ذلك هو GraphicsPath Class والمثال التالي يوضح ذلك
لنفترض أنه لدينا صورة ما Image ونريد أن نرسمها بحيث تظهر في شكل دائري أو علي شكل متوازي أضلاع أو خلافه فكيف نفعل ذلك باستخدام GraphicsPath Class . الكود التالي يوضح ذلك


كود :
Public Class Form1

' Create image
Private bmp As New Bitmap(My.Resources.baby_5)

End Class
في الكود أعلاه قمنا بتعريف الصورة Image وهي صورة تم إضافتها الي Resources المشروع وبالتالي يسهل الوصول إليها و إستخدامها كيفما شئنا داخل البرنامج


كود :
Private Sub DrawCircularShape(ByVal g As Graphics)

' Create graphics path.
Dim path As New Drawing2D.GraphicsPath()
' Create rectangle.
Dim rect As New Rectangle(100, 10, 100, 100)
' add the rectangle to the graphics path.
path.AddEllipse(rect)

' fill the graphics path with red color
Using sb As New SolidBrush(Color.Red)
g.FillPath(sb, path)
End Using

' Set clipping region to path, region is replaced by another use combine mode to do that
g.SetClip(path, Drawing2D.CombineMode.Replace)
' dispose the path
path.Dispose()

' draw the image inside rectangle
g.DrawImage(bmp, rect, 0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel)

End Sub
في الكود أعلاه قمنا بتعريف مستطيل Rectangle و مسار GraphicsPath
ثم تم إضافة هذا المستطيل Rectangle الي المسار GraphicsPath ولكن علي شكل Ellipse
ثم تم رسم أو ملأ هذا المسار GraphicsPath باللون الأحمر
ثم استخدمنا SetClip لتحديد المنطقة التي تحدث بها عملية الرسم
ومن ثم قمنا برسم الصورة Image داخل المستطيل Rectangle
أرجو أن تلاحظوا الدور الذي تلعبه كل من SetClip وأيضا CombineMode.Replace فهما تحددان أن عملية الرسم ستتم فقط داخل المسار المحدد وأيضا سيتم استبدال هذا المسار بشئ أخر


كود :
Private Sub DrawAnyShapePath(ByVal g As Graphics)

' Create graphics path.
Dim path As New Drawing2D.GraphicsPath()
path.AddLine(New Point(100, 100), New Point(200, 200))
path.AddLine(New Point(200, 200), New Point(100, 300))
path.AddLine(New Point(100, 300), New Point(0, 200))
path.CloseFigure()

' Create rectangle and its dimensions shall be located within path
Dim rect As New Rectangle(0, 100, 200, 200)
' Set clipping region to path, region is replaced by another use combine mode to do that
g.SetClip(path, Drawing2D.CombineMode.Replace)
' dispose the path
path.Dispose()

' draw the image inside rectangle
g.DrawImage(bmp, rect, 0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel)

End Sub
في الكود أعلاه قمنا بتعريف مستطيل Rectangle و مسار GraphicsPath
ثم تم رسم مجموعة من الخطوط داخل هذا المسار GraphicsPath
ثم تم رسم أو ملأ هذا المسار GraphicsPath باللون الأحمر
ثم استخدمنا SetClip لتحديد المنطقة التي تحدث بها عملية الرسم
ومن ثم قمنا برسم الصورة Image داخل المستطيل Rectangle
أرجو أن تلاحظوا وللمرة الثانية الدور الذي تلعبه كل من SetClip وأيضا CombineMode.Replace
حاول عزيزي القارئ أن تقوم بالتغيير في قيمة CombineMode لكي تكتشف أهميتها بنفسك


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

DrawCircularShape(e.Graphics)
DrawAnyShapePath(e.Graphics)

End Sub
في الكود أعلاه قمنا بتمرير ما قمنا برسمه الي الحدث Paint Event الخاص بالفورم لكي يظهر ما رسمناه علي سطح الفورم

السؤال الثاني:
هل من الممكن رسم أي مسار GraphicsPath نريده؟
بالتأكيد نستطيع أن نرسم أي شكل نريده باستخدام GraphicsPath ولنفرض علي سبيل المثال أننا نريد أن نرسم مسار علي شكل حلزوني Spiral كل مع علينا فعله هو أن نحدد شكل المسار ثم نقوم بعملية الرسم وغالبا هذا الأمر يحتاج فقط لمعرفة جيدة بالعمليات الرياضية Mathematics و المثال التالي يوضح كيفية رسم الشكل الحلزوني



كود :
Public Class Form1

Private bmp As New Bitmap(My.Resources.baby_5)
Private m_percent As Double = 40
Private n As Single = 5
Private Path As Drawing2D.GraphicsPath

Private Sub DrawSpiralShape(ByVal g As Graphics)

Dim rect As New Rectangle(100, 100, 200, 200)

Dim angle As Double = n * (Math.PI * 2) / 100
Dim distance As Double = Math.Max(CDbl(rect.Width), CDbl(rect.Height)) / 100
Path = New Drawing2D.GraphicsPath(Drawing2D.FillMode.Winding)

Dim cx As Single = rect.Width / 2
Dim cy As Single = rect.Height / 2

Dim p1 As Double = m_percent - 100
Dim p2 As Double = m_percent

If p1 < 0 Then
p1 = 0
End If

Dim b As Double = angle * p2
Dim p3 As New PointF(CSng((cx + (p1 * distance * Math.Sin(b)))), CSng((cy + (p1 * distance * Math.Cos(b)))))
b = angle * p1
While (p1 <= p2)
Dim pt As New PointF(CSng((cx + (p1 * distance * Math.Cos(b)))), CSng((cy + (p1 * distance * Math.Sin(b)))))
Path.AddLine(p3, pt)
p3 = pt
p1 += 0.1
b += angle / 10
End While

Path.CloseAllFigures()
g.SetClip(Path, Drawing2D.CombineMode.Replace)
g.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
g.DrawPath(Pens.Black, Path)

End Sub

Private Sub DrawImageInsideSpiralshape(ByVal g As Graphics)

Dim rectA As RectangleF = Path.GetBounds()
Dim rectB As Rectangle = New Rectangle(rectA.X, rectA.Y, rectA.Width, rectA.Height)

g.DrawImage(bmp, rectB, 0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel)
Path.Dispose()

End Sub

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

DrawSpiralShape(e.Graphics)
DrawImageInsideSpiralshape(e.Graphics)

End Sub

End Class
حيث في الكود أعلاه قمنا بتعريف متغير يرمز الي المسار GraphicsPath وأيضا متغير يشير الي صورة ما Bitmap وهذه الصورة تم إضافتها الي Resources المشروع كما فعلنا في المثال السابق وأيضا تم تعريف متغير قيمته عبارة عن Double وهذا المتغير يسمح لنا بالتحكم في مقياس الرسم بحيث نستطيع تكبير أو تصغير مقياس الرسم عند رسمه علي سطح الفورم والمتغير الأخير قيمته من النوع Single وهو يسمح لنا بالتحكم في زاوية دوران المسار الحلزوني Spiral Path ثم وباستخدام بعض العمليات الرياضية قمنا برسم المسار GraphicsPath ومن ثم قمنا برسم الصورة داخل هذا المسار ثم أخيرا نقوم بتمرير ما قمنا برسمه الي الحدث Paint Event الخاص بالفورم لكي يظهر ما رسمناه علي سطح الفورم

السؤال الثالث:
هل من الممكن رسم أي تكست Text علي شكل مسار GraphicsPath ؟
بالتأكيد نستطيع أن نرسم أي تكست Text نريده باستخدام GraphicsPath ولنفرض علي سبيل المثال أننا نريد أن نرسم تكست ثم نريد أن نملأ هذا التكست بصورة ما. المثال التالي يوضح كيفية عمل ذلك


كود :
[align=left]Public Class Form1

Private bmp As New Bitmap(My.Resources.baby_5)

Private Sub DrawStringPathVertical(ByVal g As Graphics)

g.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias

Dim txt As String = "GDI+"
Dim Path As New Drawing2D.GraphicsPath()

Path.AddString(txt, New FontFamily("Times New Roman"), FontStyle.Bold, 100, _
New Point(0, 0), New StringFormat(StringFormatFlags.DirectionVertical))

Using tb As New TextureBrush(bmp)
g.FillPath(tb, Path)
End Using

g.DrawPath(Pens.Black, Path)
Path.Flatten(New Drawing2D.Matrix(), 30.0F)

End Sub

Private Sub DrawStringPathHorizontal(ByVal g As Graphics)

g.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias

Dim txt As String = "GDI+"
Dim Path As New Drawing2D.GraphicsPath()

Path.AddString(txt, New FontFamily("Times New Roman"), FontStyle.Bold, 100, _
New Point(100, 0), New StringFormat(StringFormatFlags.NoClip))

Using tb As New TextureBrush(bmp)
g.FillPath(tb, Path)
End Using

g.TranslateTransform(0, 100)
g.DrawPath(Pens.Black, Path)
Path.Flatten(New Drawing2D.Matrix(), 30.0F)

End Sub

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

End Class[/align]
أعتقد أن الكود اعلاه في المثال الثالث بسيط وواضح ولا يحتاج إلا أي تعليق

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

الأن وبعد أن أعطينا بعضا من الأفكار السريعة للتعامل مع GraphicsPath لنبدأ في بناء الكونترول الذي سوف نستخدمه في عرض الصور علي شكل Slides كما يحدث في برنامج Power Point


يتبع في المشاركة التالية
}}}
تم الشكر بواسطة:
#2
الكونترول Slider

غالبا يسمح برنامج Power Point لمستخدميه بإضافة بعض الصور ومن ثم يتيح للمستخدم تحريك هذه الصور علي شكل Slides و أيضا يتيح للمستخدم إمكانية تحديد الإتجاه الذي سوف تظهر منه الصورة فعلي سبيل المثال الصورة يمكن أن تظهر من اليسار الي اليمين أو من أسفل إلي اعلي أو من الممكن أن تتحرك الصورة بشكل قطري من أسفل الي اعلي والعكس

لذلك في الكونترول الذي نقوم ببنائه سوف نقوم بإضافة كلاس الي المشروع وداخل هذا الكلاس سوف نقوم بتعريف Enum ولنطلق عليه SlideEffects والكود التالي يوضح شكل هذا Enum الذي سوف نستخدمه لاحقا داخل الكونترول لكي نحدد الاتجاهات التي سوف تتحرك فيها الصورة



كود :
Public Enum SlideEffects

' Image Slides from Left to right
LeftToRight

' Image Slides from right to left
RighTotLeft

' Image slide from top to down
TopToDown

' Image slide from down to top
DownToTop

' Image slide diagonally from top left to bottom right
TopLeftToBottomRight

' Image slide diagonallyfrom bottom right to top left
BottomRightToTopLeft

' Image slide diagonally from bottom left to top right
BottomLeftToTopRight

' Image slide diagonally from top right to bottom left
TopRightToBottomLeft

End Enum
صفات الكونترول Control Property

تم إضافة ثلاثة Property رئيسية للتحكم في الكونترول بالإضافة الي بعض الصفات الأخري لكن الصفات التي يهمنا التحدث عنها هي:

§ SlidingEffect والهدف منها هو تحديد إتجاه الصورة


كود :
<System.ComponentModel.DefaultValue(GetType(SlideEffects), "LeftToRight")> _
<System.ComponentModel.Description("Set iamge direction.")> _
<System.ComponentModel.Category("Control Style")> _
Public Property SlidingEffect() As SlideEffects
Get
Return m_slidEffect
End Get
Set(ByVal value As SlideEffects)
m_slidEffect = value
End Set
End Property
§ SlidingImage والهدف منها هو تحديد الصورة التي سوف تستخدم داخل الكونترول


كود :
<System.ComponentModel.DefaultValue(GetType(Bitmap), "")> _
<System.ComponentModel.Description("Set iamge.")> _
<System.ComponentModel.Category("Control Style")> _
Public Property SlidingImage() As Bitmap
Get
Return m_slidingBmp
End Get
Set(ByVal value As Bitmap)
m_slidingBmp = value
End Set
End Property
§ SlidingSpeed والهدف منها هو التحكم في سرعة حركة الصورة


كود :
<System.ComponentModel.DefaultValue(GetType(Single), "2")> _
<System.ComponentModel.Description("Set slide speed.")> _
<System.ComponentModel.Category("Control Style")> _
Public Property SlidingSpeed() As Single
Get
Return CSng(m_slidingSpeed.TotalSeconds)
End Get
Set(ByVal value As Single)
m_slidingSpeed = New TimeSpan(0, 0, 0, 0, CInt((1000 * value)))
End Set
End Property

التحكم في الصورة المتحركة

تم إضافة Public Sub للتحكم في حركة الصورة وهو يسمي AnimateSlide حيث هو المسؤل عن تحريك الصورة والكود الخاص به كالتالي



كود :
Public Sub AnimateSlide()
m_thread = New System.Threading.Timer(New System.Threading.TimerCallback(AddressOf ThreadTimer_Tick), Nothing, 30, 30)
m_percent = 0
m_sliding = True
m_startTime = DateTime.Now
Invalidate()
End Sub
رسم الصورة المتحركة

تم إضافة Protected Sub حيث فيه تتم عملية الرسم والفكرة هنا مبنية علي إستخدام الكلاس Matrix ومن ثم نقوم بعمل Transform للرسم باستخدام هذه Matrix ومن ثم نرسم الصورة طبقا للحالة الخاصة بها أو طبقا لاتجاهها في Enum والكود تكراري تقريبا ولكن يختلف طبقا للاتجاه الموجود في SlideEffects Enum والكود التالي يوضح جزء من هذا الإجراء



كود :
Protected Sub DrawSlidingEffect(ByVal g As Graphics, ByVal control As ImageSlider)

If m_slidingBmp IsNot Nothing Then

Select Case m_slidEffect

Case SlideEffects.BottomLeftToTopRight
Dim mx As New Drawing2D.Matrix(1, 0, 0, 1, (control.Width * m_percent / 100) - control.Width, -(control.Height * m_percent / 100) + control.Height)
g.Transform = mx
g.DrawImage(m_slidingBmp, control.ClientRectangle, 0, 0, m_slidingBmp.Width, m_slidingBmp.Height, GraphicsUnit.Pixel)
mx.Dispose()
Exit Select

' ......... rest of code

End Select
End If

End Sub

كيف تستخدم الكونترول

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



كود :
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
ImageSlider1.SlidingEffect = SlideEffects.DownToTop
ImageSlider1.AnimateSlide()
End Sub
ويمكن أيضا استخدام Timer ومن ثم نقوم بتغيير الصورة الموجودة في الكونترول كل فتره زمنية مناسبة أو يمكنكم استخدامه بالشكل الذي يناسبكم

وبالمرفقات ستجدون نسخة كاملة من الكلاس وطريقة استخدامه و الملف المرفق بنسخة الفيجوال استوديو 2008

وإن شاء رب العزة سوف نكمل إضافة باقي المؤثرات الأخري في مقال لاحق

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


الملفات المرفقة
.rar   ImageSlider_v1_src.rar (الحجم : 88.92 ك ب / التحميلات : 67)
}}}
تم الشكر بواسطة:


المواضيع المحتمل أن تكون متشابهة .
الموضوع : الكاتب الردود : المشاهدات : آخر رد
  الجزء الثالث من:كيف تجعل الـ Text Box ذكي!يترجم العمليات الحسابية ويخرج الناتج (الأقواس المتعددة) !! أنس محمود 10 7,843 19-07-22, 12:15 AM
آخر رد: StartLight4000
Video [درس فيديو] تقارير الكريستال ريبورت وتغيير مسار الصور أثناء التشغيل رمضان272 0 1,615 28-03-22, 03:18 AM
آخر رد: رمضان272
  شرح خوارزميات معالجة الصور (من دروس الاستاذ فوزي برزنجي) ناديه الشجيري 19 34,374 20-02-22, 02:13 PM
آخر رد: رضوان الجماعي
  التعامل مع الصور Images في بيئة الدوت نت باستخدام +GDI - مقدمة RaggiTech 3 5,868 30-07-21, 05:14 PM
آخر رد: kebboud
  مقال: الكومبو بوكس ComboBox كيف تضيف أيقونات Blue Sky 1 3,162 30-06-19, 10:41 AM
آخر رد: invocker
  Compare Images المقارنة بين الصور Abu Ehab 0 3,276 31-10-18, 04:27 PM
آخر رد: Abu Ehab
  التــعامل مع cmd من خلال الدوت نت مبتدئ في الاحتراف 3 3,786 02-06-18, 12:36 AM
آخر رد: YousefOkasha
  مقدمة إلي ضغط الصور ..... Zip Bitmap silverlight 0 2,392 10-05-18, 04:35 AM
آخر رد: silverlight
  حساب قيمة معادلة(اقصد صيغة دون مجاهيل) مكتوبة بالتكست : الجزء الخامس والاخير محمد شريقي 4 4,521 23-02-18, 10:44 PM
آخر رد: العواد الصغير
  Text Animation silverlight 1 2,091 26-10-17, 02:04 PM
آخر رد: sendbad100

التنقل السريع :


يقوم بقرائة الموضوع: بالاضافة الى ( 1 ) ضيف كريم