3

序文として、目標を達成するためにすでに多くの方法を試しており、現在は「最良の」解決策で休んでいますが、「素晴らしい」と考えるものにはまだほど遠いです...だから私はここで提案を得ることを望んでいました。これは Visual Studio 2010 を使用した C# です。

私のプログラムは、歌詞を含む可能性のあるメタデータを伴うオーディオ ファイルを再生します。歌詞がある場合、ユーザーは歌詞を一度に 1 つのフレーズを表示するか、オーディオと共にスクロールするかを選択できます。これは、1 行のラベルで行われます。フレーズ全体に色を付けたりするようなカラオケ スタイルではなく、文字通り歌詞が音楽に合わせて左から右にスクロールします。

DoubleBuffering を有効にしたり無効にしたりしてみました。有効にすると改善されますが、それでも完全ではありません。

1) 実行時にラベルの Graphics オブジェクトを作成すると、タイマーはその Graphics オブジェクトを使用して Label に直接描画します。グラフィックをクリアすることと、クリアのちらつきを避けるために、グラフィックのサイズの塗りつぶされた長方形を描画することの両方を試みました。これらのいずれかの後、テキスト文字列が描画されます。25 ミリ秒、50 ミリ秒、100 ミリ秒を試してみましたが、ここではほぼ同じ結果が得られました。

2) 実行時にラベルの Graphics オブジェクトを作成すると、タイマーがラベルのサイズのビットマップを作成し、そのビットマップからグラフィック オブジェクトを作成し、塗りつぶされた四角形を描画し、グラフィック オブジェクトに文字列を描画し、それをコピーします。ラベルのグラフィックス オブジェクトに追加し、ビットマップを Label.Image フィールドにコピーしようとしました。

3) 専用の Graphics オブジェクトが作成されていない。代わりに、タイマーでラベルを無効にします。次に、Label の Paint イベントで、e 引数の Graphics オブジェクトを使用して、塗りつぶされた四角形を直接描画し、テキスト文字列を描画します。

すべての場合において、結果として正しくスクロールされるテキストは、スクロールするとぎくしゃくして読みにくくなりますが、再生を一時停止すると完璧に見えます。描かれるタイミングや内容は正確です。#3は、私が試した多くのバリエーションの中で「最高」ですが、私が言うように、テキストを読むのはまだ簡単ではありません. タイマーの値が 40FPS と 10FPS の間で変化し、結果の読みやすさに大きな違いがないことを考えると、これは私の描画方法が非効率的であることに帰着していると思います。

私が犯している明らかな間違いや、この動作を引き起こしている根本的な基盤の欠如はありますか? これをどのように改善できるかについて、いくつかの意見をいただければ幸いです。ありがとう。

4

2 に答える 2

0

これは、少し前に作成したスクロール ラベル コントロールのコードです。微調整が必​​要な場合があり、VB.NET で記述されているため、変換する必要があります。ちらつきもなくスムーズにスクロールします。2つのタイマーコールの番号を変更するか.25Tickサブの を変更することで速度を調整できます。

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
于 2015-02-24T17:58:25.397 に答える