我在前言中说过我已经尝试了很多方法来实现我的目标,而我现在正在最好的"解决方案,但它仍然远远不是我想的那么好......" ...所以我希望在这里得到一个建议。这是使用Visual Studio 2010的C#。
我的程序播放伴随可能包含歌词的元数据的音频文件。当我有歌词时,用户可以选择让歌词一次显示一个短语,或者与音频一起滚动。这发生在一行标签上。它不是卡拉OK风格,你有整个短语,它被着色或其他东西,字面上歌词从左到右随着音乐滚动。
我尝试启用和禁用DoubleBuffering。启用它后,它会更好,但仍然不完美。
1)在运行时为标签创建Graphics对象,然后计时器将使用其Graphics对象直接绘制到Label。我尝试清除图形,而只是绘制一个填充的矩形图形大小,以避免清除闪烁。在其中任何一个之后,绘制文本字符串。我已经尝试了25ms,50ms和100ms,结果大致相同。
2)在运行时为标签创建一个Graphics对象,然后计时器将创建一个标签大小的位图,从该位图创建一个图形对象,绘制填充的矩形并在图形对象中绘制字符串,然后将其复制到Label的图形对象,我也尝试将位图复制到Label.Image字段。
3)没有创建专用的Graphics对象。相反,让计时器使标签无效。然后在Label的Paint事件中,使用e参数的Graphics对象直接绘制填充的矩形并绘制文本字符串。
在所有情况下,结果都是正确滚动的文本,在滚动时抖动且难以阅读,但在暂停播放时看起来很完美。绘制的时间和内容是准确的。 #3是最好的"我试过的很多变化,但正如我所说,它仍然不容易阅读文本。鉴于计时器值在40FPS和10FPS之间变化,并且结果在易读性方面没有太大差异,我假设它是以我自己的方式进行绘图的低效方式。
我是否有一些明显的错误或导致这种行为导致基本缺乏基础?我想知道如何改进这一点。感谢。
答案 0 :(得分:0)
当你尝试以某种方式绘制控件时,控件将会“帮助”#34;为你画上它的背景。不幸的是,这会导致闪烁。
我过去所做的是创建一个继承自您实际想要绘制的控件的新类。这个类应该用空子覆盖OnPaintBackground
。然后在表单上使用此子类而不是库存类。
我只使用相框来完成此操作,因此您使用其他类型控件的结果可能会有所不同。
您可能还有一些运气设置这样的控件样式(在这种情况下AllPaintingInWmPaint
是最重要的一种。):
this.SetStyle(
ControlStyles.AllPaintingInWmPaint |
ControlStyles.UserPaint |
ControlStyles.DoubleBuffer,
true);
答案 1 :(得分:0)
这是我刚刚创建的滚动标签控件的代码。它可能需要一些调整,并且它是用VB.NET编写的,你必须转换它。它没有闪烁地顺利滚动我。您可以通过更改2个计时器呼叫中的号码或在.25
子分区中Tick
进行转换来调整速度。
Imports System.ComponentModel
Public Class ScrollingLabel
Inherits Label
Private _buffer As Bitmap
Private _textX As Double
Private _brush As Brush
Private _timer As Threading.Timer
Private _textWidth As Integer
Public Sub New()
MyBase.New()
If Not IsDesignMode() Then
_timer = New Threading.Timer(AddressOf Tick, Nothing, 25, Threading.Timeout.Infinite)
End If
_brush = New SolidBrush(Me.ForeColor)
_textX = Me.Width
End Sub
Protected Overrides Sub OnPaint(e As PaintEventArgs)
Using g As Graphics = Graphics.FromImage(_buffer)
g.Clear(Me.BackColor)
g.DrawString(Me.Text, Me.Font, _brush, New PointF(CSng(_textX), 0))
End Using
e.Graphics.DrawImage(_buffer, 0, 0)
End Sub
Private Sub ScrollingLabel_Resize(sender As Object, e As EventArgs) Handles Me.Resize
If _buffer IsNot Nothing Then
_buffer.Dispose()
End If
_buffer = New Bitmap(Me.Width, Me.Height, Imaging.PixelFormat.Format32bppArgb)
End Sub
Public Overrides Property ForeColor As Color
Get
Return MyBase.ForeColor
End Get
Set(value As Color)
MyBase.ForeColor = value
If _brush IsNot Nothing Then
_brush.Dispose()
End If
_brush = New SolidBrush(Me.ForeColor)
End Set
End Property
Public Overrides Property Text As String
Get
Return MyBase.Text
End Get
Set(value As String)
MyBase.Text = value
Using g As Graphics = Graphics.FromImage(_buffer)
_textWidth = CInt(g.MeasureString(Me.Text, Me.Font).Width)
End Using
End Set
End Property
Private Sub Tick(state As Object)
If Me.Parent.InvokeRequired Then
Me.BeginInvoke(New Action(Of Object)(AddressOf Tick), New Object() {state})
End If
_textX -= 0.25
If Math.Abs(_textX) > _textWidth Then
_textX = Me.Width
End If
_timer.Change(25, Threading.Timeout.Infinite)
Me.Invalidate()
End Sub
Private Function IsDesignMode() As Boolean
If DesignMode Then
Return True
End If
Return CBool(LicenseManager.UsageMode = LicenseUsageMode.Designtime)
End Function
End Class