C#VS2010:如何使用抽绳来绘制滚动文本而不闪烁

时间:2015-02-17 15:46:00

标签: visual-studio-2010 drawstring c3

我在前言中说过我已经尝试了很多方法来实现我的目标,而我现在正在最好的"解决方案,但它仍然远远不是我想的那么好......" ...所以我希望在这里得到一个建议。这是使用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之间变化,并且结果在易读性方面没有太大差异,我假设它是以我自己的方式进行绘图的低效方式。

我是否有一些明显的错误或导致这种行为导致基本缺乏基础?我想知道如何改进这一点。感谢。

2 个答案:

答案 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