在DataGridView中对图像进行动画处理 [英] Animate Images in DataGridView

查看:72
本文介绍了在DataGridView中对图像进行动画处理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在下面编写了帮助程序类,以便为 DataGridView 中的图像设置动画,该类不起作用(图像没有动画效果)。

I wrote the helper class below in order to animate images in a DataGridView, which is not working (images aren't animated).

在此之前,我在wen上找到了一些示例代码,但它们也不起作用。

Before that, I found some sample code on the wen, but they didn't work either.

我想了解其工作原理而不是仅仅因为它起作用而在我的应用程序内简单地插入了一段代码。为什么我的代码没有达到预期的效果?

I want to understand how this works instead of simply shove a piece of code inside my app just because it works. Why does my code not do what it is expected to?

我发现了为什么不这样做没有工作。源 DataTable 本身不包含图像:它们在代码中的其他位置被分配给 DataGridView 的单元格 CellFormatting 处理程序方法。由于此事件也会一直触发,因此始终会传递一个新的图像对象,因此它将始终显示图像的第1帧。当我创建一个新列并在其中存储了本机图像值时,它们便按需要进行了动画处理。

I discovered the reason why it isn't working. The source DataTable itself don't contain images: they are assigned to DataGridView's Cells elsewhere in the code by its CellFormatting handler method. Since this event also triggers all the time, a fresh image object is always passed, so it keeps always showing the image's frame #1. When I created a new column with native image values stored in it, they animated as desired.

现在的问题是:是否可以使分配给 DataGridView CellFormatting .FormattedValue 属性的动画图像c $ c>事件处理程序方法?

The question now is: is it possible to animate images that are assigned to the .FormattedValue property inside DataGridView's CellFormatting event handler method?

Public Class DataGridViewImageAnimator

    Private WithEvents MyDataGridView As DataGridView

    Public Sub New(dataGridView As DataGridView)

        MyDataGridView = dataGridView

    End Sub

    Private MyAnimatedImages As New Dictionary(Of Point, Image)

    Private Sub ImageAnimator_FrameChanged(sender As Object, e As EventArgs)

        Dim imageCells = MyDataGridView.Rows.Cast(Of DataGridViewRow).SelectMany(
            Function(dgvr) dgvr.Cells.OfType(Of DataGridViewImageCell))

        For Each cell In imageCells

            Dim img = TryCast(cell.FormattedValue, Image)

            If img IsNot Nothing AndAlso MyAnimatedImages.ContainsValue(img) Then

                MyDataGridView.InvalidateCell(cell)

            End If
        Next

    End Sub

    Private Sub MyDataGridView_CellPainting(
            sender As Object,
            e As DataGridViewCellPaintingEventArgs
            ) Handles MyDataGridView.CellPainting

        If e.ColumnIndex >= 0 AndAlso e.RowIndex >= 0 Then

            Dim cell = MyDataGridView(e.ColumnIndex, e.RowIndex)

            Dim drawPoint = MyDataGridView.GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex, True).Location

            Dim pt = New Point(e.ColumnIndex, e.RowIndex)

            Dim cellImg = TryCast(cell.FormattedValue, Image)

            If MyAnimatedImages.ContainsKey(pt) AndAlso Equals(MyAnimatedImages(pt), cellImg) Then
                'If image is already registered as animated, and is still in cell

                ImageAnimator.UpdateFrames()

                e.Graphics.DrawImage(cellImg, drawPoint)

            Else

                If MyAnimatedImages.ContainsKey(pt) Then
                    'If image registered as animated is no longer in cell

                    ImageAnimator.StopAnimate(MyAnimatedImages(pt), AddressOf ImageAnimator_FrameChanged)

                    MyAnimatedImages.Remove(pt)

                End If

                If cellImg IsNot Nothing AndAlso ImageAnimator.CanAnimate(cellImg) Then
                    'If cell contains an image not yet registered as animated

                    MyAnimatedImages(pt) = cellImg

                    ImageAnimator.Animate(MyAnimatedImages(pt), AddressOf ImageAnimator_FrameChanged)

                    ImageAnimator.UpdateFrames()

                    e.Graphics.DrawImage(cellImg, drawPoint)

                End If

            End If

        End If

    End Sub

End Class


推荐答案

带有自定义单元格的自定义列具有一些优点。

A custom Column with custom Cells offers some advantages.

所有设计逻辑都局限于一个地方,并且可以在设计时使用 DataGridView 设计器作为列模板选择。

All the design logic is confined in one place and it can be selected as a Column template at design time using the DataGridView designer.


性能相当好(经过200次测试

The performace is quite good (tested with 200 animated cells) and I didn't notice any flickering.

可以使用设计器设置,代码或手动方式照常拉伸或缩放动画Gif。调整行/列的大小。

The animated Gifs can be Stretched or Zoomed as usual, using the designer settings, by code or manually resizing the Rows/Columns.

但是,我不能认为它是完整的,因为我找不到一种好的方法使用此自定义Column类的方法或属性开始所有动画。

However, I can't consider it complete, because I couldn't find out a good way to start all the animations using this custom Column class methods or properties.

编辑:

添加了扩展 DataGridView DataGridView.Animate())的方法。
这可以隐藏无效过程。

DataGridView 数据绑定完成后,只需调用扩展方法:


Added an Extension method to the DataGridView (DataGridView.Animate()).
This allows to hide the invalidating procedure.
After the DataGridView Data Binding is complete, simply call the extension method:

DataGridView1.DataSource = [DataSource]
DataGridView1.Animate()

包含扩展方法的模块:

The Module containing the Extension method:

Imports System.Runtime.CompilerServices

Module DGVExtesions

    <Extension()>
    Public Sub Animate(ByVal AnimatedGrid As DataGridView)
        Try
            For Each row As DataGridViewRow In AnimatedGrid.Rows
                For Each cell As DataGridViewCell In row.Cells.OfType(Of AnimatedDGVColumn.AnimatedCell)()
                    AnimatedGrid.InvalidateCell(cell)
                Next
            Next
        Catch ex As Exception
            Trace.WriteLine("Exception: {0}", ex.Message)
        End Try

    End Sub

End Module

当然这还不够好。需要更多研究。

Of course this is still not good enough. Some more research is needed.

这是自定义动画列类:

This is the custom Animated Column class:

Imports System.ComponentModel
Imports System.Windows.Forms

Public Class AnimatedDGVColumn
    Inherits System.Windows.Forms.DataGridViewColumn

    Private custCellTemplate As AnimatedCell

    Public Sub New()
        Me.custCellTemplate = New AnimatedCell
        Me.custCellTemplate.ImageLayout = DataGridViewImageCellLayout.Zoom
        MyBase.CellTemplate = custCellTemplate
        Me.AutoSizeMode = DataGridViewAutoSizeColumnMode.None
        Me.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter
    End Sub

    <Description("The ImageLayout in the Cells for this Column"), Category("Appearance")> _
    <EditorBrowsable(EditorBrowsableState.Always), Browsable(True)>
    Public Property ImageLayout As DataGridViewImageCellLayout
        Get
            Return Me.custCellTemplate.ImageLayout
        End Get
        Set(ByVal value As DataGridViewImageCellLayout)
            Me.custCellTemplate.ImageLayout = value
        End Set
    End Property

    Public Overloads Property CellTemplate As AnimatedCell
        Get
            Return Me.custCellTemplate
        End Get
        Set(value As AnimatedCell)
            Me.custCellTemplate = value
            MyBase.CellTemplate = value
        End Set
    End Property

    Public Class AnimatedCell
        Inherits System.Windows.Forms.DataGridViewImageCell

        Private Animation As Image
        Private IsAnimating As Boolean

        Public Sub New()
            Me.Animation = Nothing
            Me.IsAnimating = False
        End Sub

        Public Overloads Property ImageLayout() As DataGridViewImageCellLayout
            Get
                Return MyBase.ImageLayout
            End Get
            Set(ByVal value As DataGridViewImageCellLayout)
                MyBase.ImageLayout = value
            End Set
        End Property

        Protected Overrides Sub Paint(graphics As Graphics, clipBounds As Rectangle, cellBounds As Rectangle, rowIndex As Integer, elementState As DataGridViewElementStates, value As Object, formattedValue As Object, errorText As String, cellStyle As DataGridViewCellStyle, advancedBorderStyle As DataGridViewAdvancedBorderStyle, paintParts As DataGridViewPaintParts)
            If (IsDBNull(value)) OrElse (value Is Nothing) Then Return
            If Me.Animation Is Nothing Then
                Me.Animation = CType(formattedValue, Image)
            End If
            Animate()
            ImageAnimator.UpdateFrames()

            MyBase.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, Nothing, Me.Animation, errorText, cellStyle, advancedBorderStyle, paintParts)
        End Sub

        Private Sub Animate()
            If Me.IsAnimating = True Then Return
            If (Me.Animation IsNot Nothing) AndAlso ImageAnimator.CanAnimate(Me.Animation) = True Then
                ImageAnimator.Animate(Me.Animation, AddressOf Me.RotateFrame)
                Me.IsAnimating = True
            End If
        End Sub

        Private Sub RotateFrame(o As Object, e As EventArgs)
            If Me.RowIndex > -1 Then
                Me.DataGridView.InvalidateCell(Me)
            End If
        End Sub

        Public Overrides Function Clone() As Object
            Dim result As AnimatedCell = New AnimatedCell With {
                        .IsAnimating = False,
                        .Animation = Nothing,
                        .ImageLayout = Me.ImageLayout
                        }
            Return result
        End Function

    End Class

End Class

这篇关于在DataGridView中对图像进行动画处理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆