65.9K
CodeProject 正在变化。 阅读更多。
Home

VB.NET Windows Forms 中的图像过渡

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.91/5 (44投票s)

2009 年 11 月 8 日

CPOL

5分钟阅读

viewsIcon

111495

downloadIcon

9178

使用 GDI+ 在 VB.NET 中实现图像过渡和视觉效果。

引言

本文演示了如何在 VB.NET 中实现简单的图像过渡。

过渡是幻灯片放映、商务演示、视频、屏幕保护程序中最常用的功能之一,通过过渡,开发人员可以使用简单且极少的代码来构建简单易用的网页/Windows Forms/视频视觉效果。

背景

您可能会发现很多文章演示如何使用 Silverlight 或 Dynamic HTML 实现图像过渡,但很少有文章讨论 C# 或 VB.NET Windows Forms 中的图像过渡……显然,图像过渡是一个很好的商机。

在本文中,我将尝试解释一些最受欢迎的图像过渡方法以及它们的实现方式。

过渡和视觉效果

下表列出了最受欢迎的图像视觉效果/过渡。您可以沿用相同的过渡名称,或根据您的方便重命名这些过渡。

  1. 卷帘式 (Barn):运动类似于门打开或关闭的效果
  2. 百叶窗式 (Blinds):运动看起来像打开或关闭百叶窗
  3. 棋盘式 (CheckBoard):方形排列,像棋盘或国际象棋棋盘
  4. 虹膜式 (Iris):运动类似于相机光圈的打开
  5. 淡入淡出式 (Fade):淡入淡出一个或两个图像
  6. 滑动式 (Slide):将部分或整个图像滑动到位
  7. 螺旋式 (Spiral):螺旋运动

过渡计时

System.Threading.Timer 类实现了一个简单轻量级的定时器,它使用回调函数。是的,它只有少数功能,但也有一些很好的优点,例如指定回调的方式、指定第一次运行回调前等待的时间,以及指定调用间隔时间。这些对于在过渡期间掌握 GDI+ 的速度和计算过渡的步骤非常重要。

此外,有些人可能更喜欢使用 System.Timers.Timer 类而不是 System.Threading.Timer 类,并将 Timer 类的 Elapsed 事件挂接起来以加速 GDI+。

以下简单代码演示了如何使用 System.Timers 类在窗体上绘制内容。

  • 声明定时器
  • Private m_timer As New System.Timers.Timer()
  • 为定时器挂接 Elapsed 事件并启用定时器(StartTimer 例程)
  • Private Sub StartTimer(ByVal m_Interval As Integer)
        AddHandler m_timer.Elapsed, AddressOf TimerTick
        m_timer.Interval = m_Interval
        m_timer.Enabled = True
    End Sub
  • 指定 Elapsed 事件触发时要执行的操作。
  • Private Sub TimerTick(ByVal source As Object, _
                          ByVal e As System.Timers.ElapsedEventArgs)
        Invalidate()
    End Sub
  • Paint 事件中绘制内容。
  • Private Sub Form2_Paint(ByVal sender As System.Object, _
                            ByVal e As PaintEventArgs) Handles MyBase.Paint
    
        Dim path As New Drawing2D.GraphicsPath()
        Dim stringText As String = Date.Now
        Dim family As New FontFamily("Verdana")
        Dim myfontStyle As Integer = CInt(FontStyle.Bold)
        Dim emSize As Integer = 20
        Dim origin As New Point(0, 0)
        Dim format As StringFormat = StringFormat.GenericDefault
        path.AddString(stringText, family, myfontStyle, emSize, origin, format)
    
        Using lgb As New Drawing2D.LinearGradientBrush(path.GetBounds(), _
                                                       Color.Cyan, Color.Blue, 90, 0)
            e.Graphics.FillPath(lgb, path)
        End Using
    End Sub
  • StartTime 例程传递给 Form Load 事件并运行。
  • Private Sub Form2_Load(ByVal sender As System.Object, _
                            ByVal e As System.EventArgs) Handles MyBase.Load
        StartTimer(1000)
    End Sub

以下代码演示了如何使用 System.Threading.Timer 在窗体上绘制内容,遵循上述相同步骤。

Public Class Form1

    Private ThreadTimer As System.Threading.Timer

    Private Sub StartTimer(ByVal Interval As Integer)
        Dim CallBackTimer As New Threading.TimerCallback(AddressOf TimerTick)
        ThreadTimer = New System.Threading.Timer(CallBackTimer, Nothing, 0, Interval)
    End Sub

    ' ........ rest of the code as explained before

End Class

卷帘式视觉效果 (Barn Visual Effect)

以下代码示例演示了如何应用简单的垂直卷帘式过渡。

  • 声明变量,如定时器、过渡步数和开始时间。
  • Public Class frmTransition
    
        Private m_timer As New System.Timers.Timer()
        Private m_Steps As Single
        Private m_startTime As DateTime
    
        ' .......... rest of code
    
    End Class
  • 为定时器挂接 Elapsed 事件,初始化变量,并启用定时器(StartTimer 例程)。
  • Private Sub StartTimer(ByVal m_Interval As Integer)
        AddHandler m_timer.Elapsed, AddressOf TimerTick
        m_timer.Interval = m_Interval
        m_timer.Enabled = True
        m_Steps = 0
        m_startTime = DateTime.Now
        Invalidate()
    
    End Sub
    ' .......... rest of code
  • 指定 Elapsed 事件触发时要执行的操作。定义和计算已用时间,定义动画时间(值越小,速度越快),计算过渡步数并使控件失效以进行重绘。
  • Private Sub TimerTick(ByVal source As Object, _
                          ByVal e As System.Timers.ElapsedEventArgs)
    
        ' define & calculate ellapsed time
        Dim timeEllapsed As TimeSpan = DateTime.Now - m_startTime
        ' define animation time
        'the lowest the value the highest the speed
        Dim AnimationTime As Integer = 2
        ' calcualte transition steps
        m_Steps = CSng((100.0F / AnimationTime * timeEllapsed.TotalSeconds))
        ' check transition steps value & fix it
        If m_Steps > 100 Then
            m_Steps = 100
        End If
        ' invalidate the paint
        Invalidate()
    
    End Sub
    ' .......... rest of code

要绘制过渡效果,请按照以下步骤操作:

  1. 定义一个过渡位图。
  2. 定义一个过渡矩形。
  3. 通过定义目标矩形的上部来绘制卷帘式的上部效果。定义图像的上部源矩形,然后绘制图像的上部。
  4. 重复步骤 3,通过定义目标矩形的下部来绘制卷帘式的下部效果。定义图像的下部源矩形,然后绘制图像的下部。
  5. Private Sub frmTransition_Paint(ByVal sender As Object, _
                                    ByVal e As PaintEventArgs) _
                                    Handles MyBase.Paint
    
        ' define transition bitmap
        Dim bmp As New Bitmap(My.Resources.baby_5)
    
        ' define transition rectangle
        Dim m_rect As New Rectangle(0, 0, 100, 100)
    
        ' draw the top part barns effect 
        ' draw the top part of the image based on transition steps
    
        ' define the top part of destination rectangle
        Dim destTopRect As New Rectangle(0, 0, m_rect.Width, _
                        CInt(m_rect.Height * m_Steps / 200))
    
        ' define the image top part source rectangle
        Dim srcTopRect As New Rectangle(0, 0, bmp.Width, CInt(bmp.Height / 2))
    
        ' draw the top part of the image
        e.Graphics.DrawImage(bmp, destTopRect, srcTopRect, GraphicsUnit.Pixel)
    
    
        ' let us repeat the steps above to draw the bottom part of the barns effect
    
        ' define the destination rectangle bottom part
        Dim destBottomRect As New Rectangle(0, _
            CInt(m_rect.Height - CInt(m_rect.Height * m_Steps / 200)), _
            m_rect.Width, _
            CInt((m_rect.Height * m_Steps / 200)))
        ' define the image's bottom part source rectangle
        Dim srcBottomRect As New Rectangle(0, CInt(bmp.Height / 2), _
                                           bmp.Width, CInt(bmp.Height / 2))
    
        ' draw the bottom part of the image
        e.Graphics.DrawImage(bmp, destBottomRect, srcBottomRect, GraphicsUnit.Pixel)
    
    End Sub
  6. StartTime 例程传递给 Form Load 事件并运行。
  7. 将时间间隔设置为 60 毫秒。
  8. 为了获得更好的性能,我认为间隔值不应超过 100 毫秒。值越小,性能越好。
  9. Private Sub frmTransition_Load(ByVal sender As Object, _
                                   ByVal e As EventArgs) Handles MyBase.Load
        StartTimer(60)
    End Sub

以下代码示例演示了如何应用水平卷帘式过渡。

Private Sub frmTransition_Paint(ByVal sender As Object, _
                                ByVal e As PaintEventArgs) Handles MyBase.Paint

    Dim bmp As New Bitmap(My.Resources.baby_5)
    Dim m_rect As New Rectangle(0, 0, 100, 100)

    ' draw the left part barns effect 
    Dim destTopRect As New Rectangle(0, 0, _
        CInt(m_rect.Width * m_Steps / 200), m_rect.Height)
    Dim srcTopRect As New Rectangle(0, 0, CInt(bmp.Width / 2), bmp.Height)
    e.Graphics.DrawImage(bmp, destTopRect, srcTopRect, GraphicsUnit.Pixel)

    ' draw the right part barns effect
    Dim destBottomRect As New Rectangle(_
        CInt(m_rect.Width - CInt(m_rect.Width * m_Steps / 200)), _
        0, _
        CInt((m_rect.Width * m_Steps / 200)), _
        m_rect.Height)
    Dim srcBottomRect As New Rectangle(CInt(bmp.Width / 2), 0, _
                                       CInt(bmp.Width / 2), bmp.Height)

    e.Graphics.DrawImage(bmp, destBottomRect, srcBottomRect, GraphicsUnit.Pixel)

End Sub

如果我们混合以上两种卷帘式视觉效果(水平和垂直效果)会发生什么……!!!??? 我们会得到不同的效果……您可能称之为“卷帘式爆炸” (Barns Boom)!

以下代码示例演示了如何应用卷帘式爆炸过渡。

Private Sub frmTransition_Paint(ByVal sender As Object, _
                                ByVal e As PaintEventArgs) Handles MyBase.Paint

    Dim bmp As New Bitmap(My.Resources.baby_5)
    Dim m_rect As New Rectangle(0, 0, 100, 100)

    ' ------------------------------------------------------->
    ' draw the left part of the barn
    Dim destLeftRect As New Rectangle(0, 0, _
                        CInt(m_rect.Width * m_Steps / 200), m_rect.Height)
    Dim srcLeftRect As New Rectangle(0, 0, CInt(bmp.Width / 2), bmp.Height)
    e.Graphics.DrawImage(bmp, destLeftRect, srcLeftRect, GraphicsUnit.Pixel)

    ' ------------------------------------------------------->
    ' draw the right part of the barn
    Dim destRightRect As New Rectangle(_
                CInt(m_rect.Width - CInt(m_rect.Width * m_Steps / 200)), _
                0, _
                CInt((m_rect.Width * m_Steps / 200)), _
                m_rect.Height)
    Dim srcRightRect As New Rectangle(CInt(bmp.Width / 2), 0, _
                                       CInt(bmp.Width / 2), bmp.Height)
    e.Graphics.DrawImage(bmp, destRightRect, srcRightRect, GraphicsUnit.Pixel)

    ' ------------------------------------------------------->
    ' draw the top part of the barn
    Dim destTopRect As New Rectangle(0, 0, m_rect.Width, _
                    CInt(m_rect.Height * m_Steps / 200))
    Dim srcTopRect As New Rectangle(0, 0, bmp.Width, CInt(bmp.Height / 2))
    e.Graphics.DrawImage(bmp, destTopRect, srcTopRect, GraphicsUnit.Pixel)

    ' ------------------------------------------------------->
    ' draw the bottom part of the barn
    Dim destBottomRect As New Rectangle(0, _
                        CInt(m_rect.Height - CInt(m_rect.Height * m_Steps / 200)), _
                        m_rect.Width, _
                        CInt((m_rect.Height * m_Steps / 200)))
    Dim srcBottomRect As New Rectangle(0, CInt(bmp.Height / 2), _
                                       bmp.Width, CInt(bmp.Height / 2))

    e.Graphics.DrawImage(bmp, destBottomRect, srcBottomRect, GraphicsUnit.Pixel)

End Sub

旋转、放大和旋转视觉效果 (Rotate, Maximize, and Spin Visual Effect)

Drawin2D.Matrix 类在旋转、放大和旋转图像等过渡效果中起着重要作用,以下步骤重点介绍了最大化视觉效果中使用的主要要点。

  1. 定义过渡位图
  2. 定义过渡矩形
  3. 定义和计算矩阵中使用的过渡缩放因子。
  4. 定义矩阵类并将缩放因子传递给它,效果将从矩形的中点开始。
  5. 将矩阵传递给 graphics 对象并绘制效果。

以下代码示例演示了如何应用放大过渡。

Private Sub frmTransition_Paint(ByVal sender As Object, _
                                ByVal e As PaintEventArgs) Handles MyBase.Paint

    ' draw maximize effect
    Dim bmp As New Bitmap(My.Resources.baby_5)
    Dim m_rect As New Rectangle(0, 0, 150, 150)

    ' define and calculate transition scale factor used in the matrix
    Dim sf As Single = m_Steps / 100
    If sf = 0 Then
        sf = 0.01F
    End If
    ' define the matrix class & pass the scale factor to it
    ' effect will strat from the rectangle mid-point
    Dim mx As New Drawing2D.Matrix(sf, 0, 0, sf, m_rect.Width / 2, m_rect.Height / 2)
    ' pass the matrix to graphics
    e.Graphics.Transform = mx
    Dim destRect As New Rectangle(-m_rect.Width / 2, -m_rect.Height / 2, _
                                  m_rect.Width, m_rect.Height)
    Dim srcRect As New Rectangle(0, 0, bmp.Width, bmp.Height)
    e.Graphics.DrawImage(bmp, destRect, srcRect, GraphicsUnit.Pixel)

End Sub

以下步骤重点介绍了旋转和旋转视觉效果使用的主要要点。

  1. 定义过渡位图
  2. 定义过渡矩形
  3. 定义和计算矩阵中使用的过渡缩放因子。
  4. 定义矩阵类并将缩放因子传递给它,效果将从矩形的中点开始。
  5. 定义旋转因子
  6. 将旋转因子传递给矩阵以旋转矩阵,并将 Drawing2D.MatrixOrder 值设置为 Append(对于旋转效果,只需将 Drawing2D.MatrixOrder 值设置为 Prepend)。
  7. 将矩阵传递给 graphics 对象并绘制效果。
Private Sub frmTransition_Paint(ByVal sender As Object, _
                                ByVal e As PaintEventArgs) _
                                Handles MyBase.Paint

    ' draw maximize effect
    Dim bmp As New Bitmap(My.Resources.baby_5)
    Dim m_rect As New Rectangle(0, 0, 150, 150)

    ' define and calculate transition scale factor used in the matrix
    Dim sf As Single = m_Steps / 100
    If sf = 0 Then
        sf = 0.01F
    End If
    ' define the matrix class & pass the scale factor to it
    ' effect will strat from the rectangle mid-point
    Dim mx As New Drawing2D.Matrix(sf, 0, 0, sf, _
                  m_rect.Width / 2, m_rect.Height / 2)
    ' pass the matrix to graphics
    ' define rotation factor
    Dim rf As Single = m_Steps * 360 / 100

    ' pass the rotation factor to the matrix 
    ' to rotate the matrix and set the matrixorder
    ' for spin set MatrixOrder value to Prepend
    mx.Rotate(rf, Drawing2D.MatrixOrder.Append)

    e.Graphics.Transform = mx

    Dim destRect As New Rectangle(-m_rect.Width / 2, -m_rect.Height / 2, _
                                  m_rect.Width, m_rect.Height)
    Dim srcRect As New Rectangle(0, 0, bmp.Width, bmp.Height)
    e.Graphics.DrawImage(bmp, destRect, srcRect, GraphicsUnit.Pixel)

End Sub

有关其他效果(大约有 28 种效果等着您去尝试)的更多详细信息,您可以下载附加到文章的文件。

动画控件 (The Animation Control)

  • 动画控件文件
    • AnimationTypes.vb:大约 28 种视觉效果/过渡的公共枚举。
    • AnimationControl.vb:扩展 Control 类。
  • 控件属性
    • AnimationSpeed:用于设置动画速度;值越大,速度越慢。
    • AnimationType:用于设置 Animationtypes 枚举。
    • AnimatedImage:用于设置视觉效果所需的图像。
    • AnimatedFadeImage:用于设置将与动画图像一起使用的淡入淡出图像。
    • Opacity, Transparent, TransparenColor:用于设置控件的透明度(有关更多详细信息,您可以参考我关于使用 GDI+ 的 VB.NET 透明控件的上一篇文章,可在 此处 找到)。

使用控件

构建 AnimationControl 并在您的窗体中使用它。以下简单代码演示了如何在 Windows Forms 中使用 AnimationControl

Public Class TestForm

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

    Private Sub TestForm_Load(ByVal sender As System.Object, _
            ByVal e As System.EventArgs) Handles MyBase.Load
        AnimationControl1.AnimatedFadeImage = Panel1.BackgroundImage
        AnimationControl1.AnimatedImage = bmp
    End Sub

    Private Sub btnSpiarlBoom_Click(ByVal sender As System.Object, _
            ByVal e As System.EventArgs) Handles btnSpiarlBoom.Click

        AnimationControl1.AnimationType = AnimationTypes.SpiralBoom
        AnimationControl1.Animate(40)

    End Sub

    ' rest of code 

End Class

下载附件文件,进行尝试,您还可以添加自己的视觉效果……这既简单又有趣。尽情享受吧。

历史

  • 2009 年 11 月 7 日:首次发布。
© . All rights reserved.