how to stop flickering C# winforms

前端 未结 16 2115
故里飘歌
故里飘歌 2020-11-28 04:16

I have a program that is essentially like a paint application. However, my program has some flickering issues. I have the following line in my code (which should get rid of

相关标签:
16条回答
  • 2020-11-28 04:31

    Try to insert drawing logic in current form's

    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);
    }
    

    method. In this case you should use parameter e to get Graphics object. Use e.Graphics property. Then you should invoke Invalidate() method for this form whenever form must be redrawn. PS: DoubleBuffered must be set to true.

    0 讨论(0)
  • 2020-11-28 04:33

    Finally solved the flickering. Since I was drawing on a panel instead of the form the line of code below will not solve the flickering:

    this.SetStyle(
        ControlStyles.AllPaintingInWmPaint | 
        ControlStyles.UserPaint | 
        ControlStyles.DoubleBuffer, 
        true);
    

    SetStyle must be of type 'YourProject.YourProject' (or derived from it) hence, you have to create a class as such (so that you can use MyPanel which will be derived from SPaint.SPaint and hence allowing you to use doublebuffering directly for the panel - rather than the form):

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using SPaint; 
    
    namespace YourProject
    {
        public class MyPanel : System.Windows.Forms.Panel
        {
            public MyPanel()
            {
                this.SetStyle(
                    System.Windows.Forms.ControlStyles.UserPaint | 
                    System.Windows.Forms.ControlStyles.AllPaintingInWmPaint | 
                    System.Windows.Forms.ControlStyles.OptimizedDoubleBuffer, 
                    true);
            }
        }
    }
    

    After you've done this(although you should really never edit the designer code unless you truly know what you're doing) you'll have to edit the Form.Designer.cs. Inside this file you will find code that looks like this:

    this.panelArea = new YourProject.MyPanel();
    

    The above line needs to be changed to:

    this.panelArea = new MyPanel(); 
    

    After I completed these steps, my paint program no longer flickers.

    For anyone else having the same issue, the problem is finally solved.

    Enjoy!

    0 讨论(0)
  • 2020-11-28 04:35

    here is the program of moving circle in .net, that doesn't flicker.

    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Windows.Forms;
    using System.Threading;
    namespace CircleMove
    {
        /// <summary>
        /// Description of MainForm.
        /// </summary>
        public partial class MainForm : Form
        {
            int x=0,y=0;
            Thread t;
    
            public MainForm()
            {
    
                //
                // The InitializeComponent() call is required for Windows Forms designer support.
                //
                InitializeComponent();
    
                //
                // TODO: Add constructor code after the InitializeComponent() call.
                //
            }
            void MainFormPaint(object sender, PaintEventArgs e)
            {
                Graphics g=e.Graphics;
                Pen p=new Pen(Color.Orange);
                Brush b=new SolidBrush(Color.Red);
            //  g.FillRectangle(b,0,0,100,100);
                g.FillEllipse(b,x,y,100,100);
            }
            void MainFormLoad(object sender, EventArgs e)
            {
                t=new Thread(  new ThreadStart(
    
                    ()=>{
                        while(true)
                        {
                            Thread.Sleep(10);
                            x++;y++;
                            this.Invoke(new Action(
                                ()=>{
    
                                    this.Refresh();
                                    this.Invalidate();
                                    this.DoubleBuffered=true;
                                    }
                                                )
                                            );
                        }
                        }
                                                )
    
                            );
    
                t.Start();
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-28 04:36

    Copy and paste this into your project

    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams handleParam = base.CreateParams;
            handleParam.ExStyle |= 0x02000000;   // WS_EX_COMPOSITED       
            return handleParam;
        }
    }
    

    This enables double-buffering for all controls from the form level down, otherwise double buffering needs to be individually enabled for each one... you may want to fine tune double bufferring after this because blanketed double buffering may give unwanted side effects.

    0 讨论(0)
  • 2020-11-28 04:36

    I know this is really old question but maybe someone will find it useful.
    I'd like to make little enhancement to viper's answer.

    You can make simple extension to Panel class and hide setting property through reflection.

    public static class MyExtensions {
    
        public static void SetDoubleBuffered(this Panel panel) {
            typeof(Panel).InvokeMember(
               "DoubleBuffered",
               BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetProperty,
               null,
               panel,
               new object[] { true });
        }
    }
    

    If your Panel variable's name is myPanel you can just call
    myPanel.SetDoubleBuffered();
    and that's it. Code looks much cleaner.

    0 讨论(0)
  • 2020-11-28 04:36

    It's a bit of and old question, but just to be complete: There is yet another solution, that worked for me where the double-buffering did not.

    As it turns out Microsoft offers the BufferedGraphics class as a solution. Nice thing about this class is that it enables you to copy one Graphics object to another, so except from setting up a temporary Graphics object and eventually copying it to the final destination, one can use pretty much the same code that one would have done when the flickering should not have been a problem:

    private void Indicator_Paint(object sender, PaintEventArgs e)
    {
        Control pbIndicator = (Control)sender;
        Rectangle targetRect = pbIndicator.ClientRectangle;
    
        Image img = Bitmap.FromFile("bitmap.bmp");
    
        BufferedGraphicsContext ctx = new BufferedGraphicsContext();
        BufferedGraphics bg = ctx.Allocate(e.Graphics, targetRect);
    
        // Do the graphic stuff 
        bg.Graphics.Clear(this.BackColor);
        bg.Graphics.DrawImage(img, 0, 0);
        // etcetera
    
        bg.Render(e.Graphics);
        bg.Dispose();
        ctx.Dispose();
    }
    

    Downside of this solution that it might clutter your code. Furthermore I'm not sure whether it is a good idea to setup the context each time, or whether it would suffice to create one in advance and keep using that context.

    For more information see https://docs.microsoft.com/en-us/dotnet/api/system.drawing.bufferedgraphicscontext?view=dotnet-plat-ext-3.1

    0 讨论(0)
提交回复
热议问题