5

ちらつきをなくす方法を知っている人はいますか? SO、Web について調査し、OnPaint() で描画していないときに TickerControl をダブル バッファリングのようなダブル バッファ パネルに配置するなど、さまざまなことを試しました。など、他にもたくさんあります。再描画のたびにではなく、毎秒数回ちらつきます。

また、OnPaint で「g.Clear(BackColor)」を削除した後でも、テキストが読みやすいようにスクロールし続けるため、何かがまだ背景をクリアしているに違いありません。

ここに私の TickerControl クラスの関連部分があります:

class TickerControl : Control
{
    private static readonly StringFormat stringFormat = new StringFormat(StringFormatFlags.NoWrap);

    private const int padding = 40;
    private const int scrollSleep = 10;
    private const int scrollAdvancePixels = 1;

    private float textWidth;
    private float currentX;

    private static readonly Timer scrollTimer = new Timer();

    public TickerControl()
    {
        this.SetStyle(ControlStyles.UserPaint |
                      ControlStyles.AllPaintingInWmPaint |
                      ControlStyles.OptimizedDoubleBuffer
                      , true);
        scrollTimer.Tick += AdvanceText;
        scrollTimer.Interval = scrollSleep;
        scrollTimer.Enabled = true;
    }

    private void AdvanceText(object sender, EventArgs e)
    {
        if (IsDisposed)
            return;

        currentX -= scrollAdvancePixels;
        if (currentX <= -textWidth)
            currentX = 0;
        Invalidate();
    }

    protected override void OnPaintBackground(PaintEventArgs pevent)
    {
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        Graphics g = e.Graphics;

        g.Clear(BackColor);

        using (SolidBrush brush = new SolidBrush(ForeColor))
        {
            g.DrawString(Text, Font, brush, currentX, 0, stringFormat);
            g.DrawString(Text, Font, brush, currentX + textWidth, 0, stringFormat);
        }
    }

何か案は?

アップデート:

sallushan が手動のダブル バッファリングを提案したので、以下のコードを使用して以前に試したことを付け加えておきます。しかし、画面上では上記とまったく同じように見えるため、問題は OnPaint メソッド内にあるようには見えません。コントロールのセットアップのどこかにあるに違いないと思います。

    private Bitmap backBuffer;

    protected override void OnPaint(PaintEventArgs e)
    {
        if (backBuffer == null)
            backBuffer = new Bitmap(this.ClientSize.Width, this.ClientSize.Height);

        Graphics g = Graphics.FromImage(backBuffer);

        g.Clear(BackColor);

        using (SolidBrush brush = new SolidBrush(ForeColor))
        {
            g.DrawString(Text, Font, brush, currentX, 0, stringFormat);
            g.DrawString(Text, Font, brush, currentX + textWidth, 0, stringFormat);
        }

        g.Dispose();

        e.Graphics.DrawImageUnscaled(backBuffer, 0, 0);
    }

    protected override void OnPaintBackground(PaintEventArgs pevent)
    {
        // Don't call base!
    }

    protected override void OnSizeChanged(EventArgs e)
    {
        if (backBuffer != null)
        {
            backBuffer.Dispose();
            backBuffer = null;
        }
        base.OnSizeChanged(e);
    }
4

6 に答える 6

5

このコードをフォームに設定します。ちらつきを取り除いてくれます

 protected override CreateParams CreateParams
        {
            get
            {
                CreateParams cp = base.CreateParams;
                cp.ExStyle |= 0x02000000;

                return cp;
            }
        }

それが役に立てば幸い

于 2011-08-19T07:25:50.317 に答える
1

定数ビットマップをフレームとして作成します。そして、そのビットマップに変更を加えてから、そのビットマップをコントロールにレンダリングします。これでちらつきが解消されるはずです。

class MyControl : System.Windows.Forms.Control
{
    Bitmap bmp;
    Graphics g;
    int x = 100;

    public MyControl()
    {
        this.SetStyle(System.Windows.Forms.ControlStyles.AllPaintingInWmPaint | System.Windows.Forms.ControlStyles.UserPaint | System.Windows.Forms.ControlStyles.OptimizedDoubleBuffer , true);

        bmp = new Bitmap(100, 100);
        g = Graphics.FromImage(bmp);
    }        

    protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
    {
        this.g.FillRectangle(Brushes.White, new Rectangle(0, 0, 100, 100));
        this.g.DrawString("Hello", this.Font, Brushes.Black, (float)x, 10);

        e.Graphics.DrawImage(bmp, new Point(0, 0));

        x--;
    }
}
于 2011-08-19T10:23:33.787 に答える
0

率直に言って、カスタムコントロールでは使用したことがなく、非常に複雑なものがあったトリプルバッファリングのアイデアは別として、10ミリ秒ごとにコントロールを無効にすることはそれと関係があると言えます。それは1秒間に100回です。25 fpsの映画は、動きの流動性の点で人間の目に快適ですが、それでもコントロールを4倍塗り直します。

より高い値を試してください:たとえば40。

また、コントロールを再描画すると、その一部だけを再描画できます。つまり、古いテキストの場所と新しいテキストの場所を形成する2つの領域の結合です。まだ配置されている周囲の領域(背景など)を再描画する必要はありません。

DrawString()は、TextRendererのDrawTextと比較してかなり遅いです-約6回、それを使用することをお勧めします。一部の機能が失われますが(GDI +の代わりにGDIを使用)、シナリオに適している可能性があります。

ああ、私はまた、クラスメンバーとして外部のすべてのOnPaint()で再作成するSolidBrushブラシをマイクロ最適化して引き出し、ForeColorが変更されたときにのみ更新します。

于 2011-08-19T11:25:39.413 に答える
0

Hans Passantのコメントを回答に変えて、私がそれを受け入れることができるようにします:

この効果はちらつきとは呼ばれず、ティアリングと呼ばれます。古いビットマップの一部と新しいビットマップの一部が表示されます。これは、移動するオブジェクトで非常に顕著になり、ぎくしゃくして見えます。Winforms では修正できません。グーグルの「垂直ブランキング間隔」。– ハンス・パッサン

于 2011-08-20T00:46:04.787 に答える
0

Invalidate(rectangle) または Invalidate(Region)メソッドを使用して、再描画の量を実際に必要な量に制限してみてください。現在、すべての OnPaint イベント中に完全なコントロールを再描画しています。

于 2011-08-19T07:04:22.987 に答える
0

2 つの文字列を並べて描画しているように見えるので、次のようにします。

g.DrawString(Text, Font, brush, currentX, 0, stringFormat);
g.DrawString(Text, Font, brush, currentX + textWidth, 0, stringFormat);

それは単に、Invalidate変更されたコントロールの部分だけを 'ing するだけの場合です。最も簡単な方法は、文字列の高さをキャッシュ/計算して、これを行うことです。

 Invalidate(new Rectangle((int)currentX, 0, (int)textWidth*2, (int)textHeight));

私のマシンでは、これはコントロール全体を無効にするよりも著しくスムーズです。

于 2011-08-19T11:28:52.953 に答える