在DataGridView中对图像进行动画处理 [英] Animate Images in 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屋!