Despite double buffering, the ticker still flickers

丶灬走出姿态 提交于 2019-12-04 08:44:16

Set this code in your form. It will remove the flicker

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

                return cp;
            }
        }

Hope it helps

Create a constant bitmap as a frame. And make your changes on that bitmap then render that bitmap on the control. This should remove the flickering.

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--;
    }
}

Try using the Invalidate(rectangle) or Invalidate(Region) methods to limit the amount of repainting to that which actually needs to be done. You are currently redrawing the complete control during every OnPaint Event.

Well, apart from the triple buffering idea - which frankly I never used in my custom controls, and I had quite complex ones -, I would say that invalidating the control every 10ms has something to do with it. That is 100 times a second. Movies with 25fps are comfortable for the human eye in terms of fluidity of motion, yet you repaint your control 4 times more than that.

Try a higher value: say 40.

Also, when you repaint the control, you can repaint just a region of it, that parts that changed: the union of the two regions that form the old text location and new text location. You dont need to repaint any surrounding area that is still in place (be it background or whatnot).

DrawString() is pretty slow compared to TextRenderer's DrawText - around 6 times, you might want to use that. You will loose some features (uses GDI, instead of GDI+) but maybe it suits your scenario.

Oh, I would also micro-optimize and pull out that SolidBrush brush you re-create in every OnPaint() outside as a class member, update it only when ForeColor changes.

As it looks like you're drawing 2 of the string next to each other:

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

It should simply be a case of just Invalidate'ing only that part of the control which has changed. The simplest method would be to cache/calculate the height of the string and do this:

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

On my machine, this is noticably smoother than invalidating the whole control.

Turning Hans Passant's comment into an answer so that I can accept it:

This effect is not called flicker, it is called tearing. You see part of the old bitmap and part of the new bitmap. Which becomes very noticeable on moving objects, they appear jittery. Not fixable in Winforms, google "vertical blanking interval". – Hans Passant

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!