尽管双重缓冲,但自动收报机仍在闪烁

Eug*_*sky 5 c# doublebuffered flicker winforms

有没有人知道如何摆脱闪烁?我研究了SO,网络,尝试了很多不同的东西,比如把TickerControl放入双缓冲面板和双缓冲时没有在OnPaint()中绘图:为什么它不起作用?除了许多其他的东西.它仍然闪烁,不是每次重复,而是每秒几次.

此外,即使在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);
        }
    }
Run Code Online (Sandbox Code Playgroud)

有任何想法吗?

更新:

正如sallushan建议的手动双缓冲,让我补充说我之前尝试过,使用下面的代码.但是在屏幕上它看起来与上面完全一样,所以问题似乎并不在我的OnPaint方法中.我想它一定是在我的Control的设置中的某个地方.

    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);
    }
Run Code Online (Sandbox Code Playgroud)

Mar*_*hal 5

在表单中设置此代码.它会消除闪烁

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

                return cp;
            }
        }
Run Code Online (Sandbox Code Playgroud)

希望能帮助到你

  • Russ,尽管你的评论确实引起了一些小小的打击,但是一个没有闪烁的自动收报机甚至会变得更加闪亮. (8认同)
  • 不要争论自动收报机闪烁! (3认同)

Eug*_*sky 0

将 Hans Passant 的评论转化为答案,以便我可以接受它:

\n\n
\n

这种效果不称为闪烁,而称为撕裂。您会看到旧位图的一部分和新位图的一部分。这在移动物体上变得非常明显,它们看起来很紧张。在 Winforms 中无法修复,请谷歌“垂直消隐间隔”。\xe2\x80\x93 汉斯·帕桑特

\n
\n