在 DataGridView 中动画图像 [英] Animate Images in DataGridView

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

问题描述

为了在 DataGridView 中对图像进行动画处理,我编写了下面的帮助程序类,但该类不起作用(图像未设置动画).

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

在此之前,我在文中找到了一些示例代码,但它们也不起作用.

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 本身不包含图像:它们通过其 CellFormatting 处理程序方法分配给代码中其他位置的 DataGridView 单元格.由于此事件也一直触发,因此总是传递一个新的图像对象,因此它始终显示图像的第 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 中对分配给 .FormattedValue 属性的图像进行动画处理CellFormatting 事件处理方法?

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天全站免登陆