Visual Basic 中学校 掲示板 投稿内容
タグのない投稿を抽出 統計 RSS

Visual Basic 中学校 > 投稿一覧 >

VBの描画の遅さについて 解決済み

カスタムコントロール タグの編集...

投稿者 Tatibanaff   (その他)   投稿日時 2013/4/12 18:16:00
街角で見かける電光掲示板のように文字が左に流れて表示するようにしたいので、文字列を「 、や。」で区切り ラベルコントロールのテキストへフォームの幅の倍くらいまで追加し、先頭が左端へ隠れたら先頭を削除し次の文字列を追加していきます。

左への移動はタイマーで50ミリ秒間隔で 2~15ドットづらしています、移動量が少ないときはうまく流れるのですが多くしたりフォントを大きく(36くらい)にすると描画が追い付かないようで、何回分かを一度に移動するようで「カクカク」してしまいます。
以前 ピクチャボックスに文字をグラフィック表示させることも試しましたが結果は大差ありませんでした。

.NetFrameWorkだけではしょうがないのでしょうか?
まだまだ勉強中で API や CUDAの勉強まで手が回らないのでうまい方法がありましたらご教授お願いいたします。


投稿者 るきお   (社会人)   投稿日時 2013/4/13 00:36:23
詳細が分からないことと、ゼロから自作して試すと骨が折れそうなことから、なんとも回答できないです。
Tatibanaffさんが作成されたプログラムを貼っていただければ、それを見て試したり、何か問題があるか指摘できたりするかもしれません。

投稿者 魔界の仮面弁士   (社会人)   投稿日時 2013/4/13 15:17:28
ためしに作ってみました。

新規にクラス「MarqueeLabel.vb」を作成し、下記のコードを記載してみてください。
コンパイルすると、ツールボックスに MarqueeLabel コントロールが追加されます。

通常のラベルに「Speed As Single」なプロパティを追加しただけのコントロールです。
Speed = 0 でスクロール停止、Speed > 0.0 では、値が大きいほど早くスクロールします。

Imports System.Windows.Forms
Imports System.ComponentModel

Public NotInheritable Class MarqueeLable
    Inherits System.Windows.Forms.Label
    Private components As System.ComponentModel.IContainer
    Private internalTimer As System.Windows.Forms.Timer
    Private internalLocation As Single = 0.0F

    Public Sub New()
        MyBase.UseCompatibleTextRendering = True
        Me.components = New System.ComponentModel.Container()
        Me.internalTimer = New System.Windows.Forms.Timer(components)
        Me.internalTimer.Interval = 50
        AddHandler internalTimer.Tick, AddressOf internalTimer_Tick
        MyBase.SetStyle(ControlStyles.UserPaint, True)
        MyBase.SetStyle(ControlStyles.OptimizedDoubleBuffer, True)
        MyBase.SetStyle(ControlStyles.AllPaintingInWmPaint, True)
        Me.internalTimer.Start()
    End Sub

    ''' <summary> 
    ''' テキストの位置を初期値に戻します。 
    ''' </summary> 
    Public Sub ResetPosition()
        Me.internalLocation = 0.0F
        Me.Invalidate()
    End Sub

    ''' <summary> 
    ''' 流れるスピードを指定します。 
    ''' </summary> 
    <System.ComponentModel.Description("流れるスピードを指定します。")> _
    <System.ComponentModel.Category("Action")> _
    <System.ComponentModel.DefaultValue(20.0F)> _
    Public Property Speed() As Single
        Get
            Return Math.Max(0.0F, Math.Min(CSng(Me.Width), speedValue))
        End Get
        Set(ByVal value As Single)
            If value < 0.0F Then
                Throw New ArgumentOutOfRangeException("Speed", value, "0以上の値を指定してください。")
            End If
            speedValue = Math.Min(Me.Width, value)
            internalTimer.Enabled = (value <> 0)
            If value = 0.0F Then
                internalTimer.Enabled = False
                If Me.DesignMode Then
                    ResetPosition()
                End If
            Else
                internalTimer.Enabled = True
            End If
        End Set
    End Property
    Private speedValue As Single = 20.0F

    Protected Overrides Sub OnPaint(e As PaintEventArgs)
        e.Graphics.TranslateTransform(-internalLocation, 0.0F)
        MyBase.OnPaint(e)
    End Sub

    Private Sub internalTimer_Tick(sender As Object, e As EventArgs)
        If Me.internalLocation > Me.Width Then
            internalLocation = -Me.Width
        Else
            internalLocation += speedValue / 10
        End If
        Me.Invalidate()
    End Sub

    <System.Diagnostics.DebuggerNonUserCode()> _
    Protected Overrides Sub Dispose(ByVal disposing As Boolean)
        Try
            If disposing AndAlso components IsNot Nothing Then
                Me.components.Dispose()
            End If
        Finally
            MyBase.Dispose(disposing)
        End Try
    End Sub
End Class



もし、コンパイルしてもツールボックスにコントロールが表示されない場合には、
メニューから[ツール]-[オプション]画面を開き、[Windows フォームデザイナー]-[全般]タブで
「AutoToolboxPopulate(ツールボックスを自動取得する)」を True にしてからビルドしてみてください。

投稿者 バーバラ   (社会人)   投稿日時 2013/4/13 15:22:57
VBでも滑らかな動きをさせることは可能なはずですが、
どのようにオーナードローをしているか、描画のタイミングをどのように設定しているかにもよります。

投稿者 魔界の仮面弁士   (社会人)   投稿日時 2013/4/13 16:54:53
MarqueeLabel と書いたつもりだったのですが、改めて見直してみたら、
MarqueeLable に typo っていますね…先のコードは適宜読み替えてください。

投稿者 Tatibanaff   (社会人)   投稿日時 2013/4/14 15:43:38
るきおさん、 魔界の仮面弁士さん、バーバラさん 回答くださり有難うございます。
私が考えたのは下のようなものです。

    Private Sub スタート(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Call SrtingSet(0)
        Timer1.Enabled = True   '初回文字セット、タイマースタート
    End Sub

    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
        Label1.Left -=  変数         '左へ移動
        If Label1.Left < pLength Then
            Label1.Left += pLength       '1行分右へ移動
            Call SrtingSet(pCount)
            pCount += 1
        End If
    End Sub

    Private Sub SrtingSet(ByVal pCount)
        Label1.Text = ""
        For Idx = pCount To Sample.Length - 1
            Label1.Text &= Sample(Idx)
            If Idx = pCount Then
                pLength = Label1.Width                      '先頭行の長さ
            End If
            If Label1.Height > Me.Width + pLength Then  '全体の長さ
                Exit For
            End If
        Next
    End Sub

バーバラさん オーナードローはまだ習得していないので使っておりません。
参考になるサイトなどありましたら是非お知らせください。

魔界の仮面弁さんの方法は
System.Windows.Forms.Design.ISlectionUIServiceは既にサービスコンテナに存在します。
というメッセージでMarqueeLableは追加されません。
何回か全く新しいフォームを作って試したのですがうまくいきません、もう少し頑張ってみますが取り急ぎ報告いたします。
Tatibanafff


投稿者 魔界の仮面弁士   (社会人)   投稿日時 2013/4/16 19:30:48
自分のコードは、オーナードローの一種です。既定の描画処理の直前に、
e.Graphics.TranslateTransform メソッドを呼び出すことで、原点座標を
左方向に少しずつずらすことで、描画位置を変わるようにしています。

一応、VB2005、2008、2010、2012 の各バージョンで動くことを確認済みです。


> ISlectionUIServiceは既にサービスコンテナに存在します。
「ISlectionUIService」ではなく
「ISelectionUIService」であろうとは思いますが、
今のところ、そのエラーの再現方法が分かりませんでした。
Tatibanaff さん以外の方でも、同様のエラーが発生するようであれば教えてください。

> もう少し頑張ってみますが取り急ぎ報告いたします。
Tatibanaff さんがお使いの VB バージョンは何でしょうか。
ByVal が記載されているので、少なくとも VB2010SP1 以降では無いようですが。

お使いの開発環境が分かれば、そのバージョン向けに
実際の動作するサンプルコードを ZIP ファイルで提供します。

投稿者 Tatibanaff   (社会人)   投稿日時 2013/4/19 22:02:16
返事が遅くなり申し訳ありません!
foamを作成し作っていただいたコードを貼り付けたのですが貼り付けた場所がForm1の前だったので
デザイナーウィンドからForm1が消えプロパティウィンドにはMarqueeLable1しかなくなってしまいあれこれと悩まされました。
スタートフォームのコードは先頭になければならないことは全く知りませんでした、
クラス内のイベントやプロシージャはどこにあっても関係ないのでスタートクラスも同じだと思ってしまったのが大きな間違いでした。


オーナードローはどう動いているのか教えていただいたコードを見て勉強します。
本当にありがとうございました。