none
Flimmern trotz DoubleBuffer RRS feed

  • Frage

  • Hallo allerseits,

    wie der Titel bereits sagt habe ich das Problem das die Applikation trotz DoubleBuffered filmmert.

            public DoubleBuffer_Sample()
            {
                InitializeComponent();
                this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.DoubleBuffer, true);
            }


    Ich verwende dazu einen Timer

            private void InitTimer()
            {
                if (ANIM != null) 
                {
                    ANIM.Dispose();
                    ANIM = null; 
                }
                ANIM = new Timer();
                ANIM.Interval = INTERVALL;
                ANIM.Tick += ANIM_Tick;
                ANIM.Start();
            }
            private void ANIM_Tick(object sender, EventArgs e)
            {
                Invalidate();
                ImageAnimator.UpdateFrames();
            }


    Und im OnPaint Event

            protected override void OnPaint(PaintEventArgs e)
            {
                base.OnPaint(e);
                foreach (IObject g in OBJECTS)
                {
                    e.Graphics.DrawEllipse(new Pen(((cObject)g).UlbFarbe), g.Location.X, g.Location.Y, g.Größe.Width, g.Größe.Height);
                    foreach (IObject s in g.Kinder)
                    {
                        e.Graphics.FillPath(s.Farbe, s.FillGröße);
                    }
                }
            }

    s.Farbe = PathGradientBrush

    s.FillGröße = GraphicsPath
    g.UlbFarbe = LinearGradientBrush

    Muss dabei noch was anderes beachtet werden oder mache ich da was falsch?

    Wäre für jede Hilfe sehr dankbar.

    Lg

    GeRi


    • Bearbeitet geRe.LI Montag, 21. August 2017 08:37
    Montag, 21. August 2017 07:18

Antworten

  • Hallo,

    scheint WindowsForms zu sein.

    Um double-buffering erfolgreich einzusetzen, muss das Control, auf dem gezichnet wird "double-ge-buffered" werden.

    Also, wenn Du etwa ein Panel zur Ausgabe benutzt, dann muss dieses Panel die Eigenschaft gesetzt haben. Am einfachsten per DoubleBuffered = true:

    Ein weiteres Problem kann durch den ImageAnimator entstehen. Man kann dann die Einzelbilder des Gif-Bildes schlichtweg im Timer Tick event selbst zeichnen (wenn die Zeiten stimmen, ansonsten einen extra timer nehmen)

    Außerdem empfehle ich, im Timer-Tick eventHandler den Timer zun stoppen, dann erst alle Aktionen ausführen und erst, wenn diese fertiggestellt sind, den Timer wieder zu starten, so vermeidet man Flickering durch konkurrierende Timer-Ticks (einer noch nicht fertig, abrer der nächste will schon zeichnen etc...)

        public class MyPanel:Panel
        {
            public MyPanel()
            {
                this.DoubleBuffered = true;
            }
    
            protected override void OnPaint(PaintEventArgs e)
            {
                base.OnPaint(e);
    
                //custom drawing (Objekte/Shapes zeichnen)
            }
        }

    Viele Grüße,

      Thorsten


    • Bearbeitet Thorsten Gudera Montag, 21. August 2017 15:36
    • Als Antwort markiert geRe.LI Montag, 21. August 2017 20:15
    Montag, 21. August 2017 14:48
  • ... hier mal ein kleines Bsp (-> neues WindowsFormsProject erstellen, code für Form1 hierdurch ersetzen...)

    Auf das Panel klicken...

        public partial class Form1 : Form
        {
            private MyPanel myPanel1 = new MyPanel();
            Random rnd = new Random();
            private Timer tmr = new Timer();
    
            public Form1()
            {
                InitializeComponent();
                myPanel1.BackColor = SystemColors.ControlDarkDark;
                myPanel1.Dock = DockStyle.Fill;
                myPanel1.Margin = new Padding(24);
                this.Controls.Add(myPanel1);
    
                this.FormClosing += Form1_FormClosing;
    
                tmr.Tick += Tmr_Tick;
    
                this.myPanel1.Click += MyPanel1_Click;
    
                this.Size = new Size(640, 480);
    
                GetShapes();
            }
    
            private void Form1_FormClosing(object sender, FormClosingEventArgs e)
            {
                this.tmr.Dispose();
            }
    
            private void Tmr_Tick(object sender, EventArgs e)
            {
                tmr.Stop();
    
                this.myPanel1.UpdateLocation();
    
                tmr.Start();
            }
    
            private void MyPanel1_Click(object sender, EventArgs e)
            {
                if (tmr.Enabled)
                    tmr.Stop();
                else
                {
                    tmr.Interval = 10;
                    tmr.Start();
                }
            }
    
            private void GetShapes()
            {
                myPanel1.Shapes = new List<MyEllipse>();
                for (int i = 0; i < 15; i++)
                {
                    MyEllipse el = new MyEllipse();
                    el.Color = Color.FromArgb(rnd.Next(256), rnd.Next(256), rnd.Next(256), rnd.Next(256));
                    el.Size = new SizeF(rnd.Next(myPanel1.ClientSize.Width / 2), rnd.Next(myPanel1.ClientSize.Height / 2));
                    el.Location = new PointF(rnd.Next(myPanel1.ClientSize.Width / 2), rnd.Next(myPanel1.ClientSize.Height / 2));
                    el.Speed = rnd.Next(1, 50) / 10f;
    
                    myPanel1.Shapes.Add(el);
                }
    
                myPanel1.Invalidate();
            }
        }
    
        public class MyPanel : Panel
        {
            public List<MyEllipse> Shapes { get; set; }
            public MyPanel()
            {
                this.DoubleBuffered = true;
            }
    
            protected override void OnPaint(PaintEventArgs e)
            {
                base.OnPaint(e);
    
                //custom drawing
                if (this.Shapes != null && this.Shapes.Count > 0)
                    for (int i = 0; i < this.Shapes.Count; i++)
                        this.Shapes[i].Render(e.Graphics);
            }
    
            protected override void OnMouseDown(MouseEventArgs e)
            {
                base.OnMouseDown(e);
    
                if (this.Shapes != null && this.Shapes.Count > 0)
                    for (int i = this.Shapes.Count - 1; i >= 0; i--)
                        if (this.Shapes[i].HitTest(e.X, e.Y))
                        {
                            MessageBox.Show("Shape No.: " + (i + 1).ToString() + " Color: " + this.Shapes[i].Color.ToString());
    
                            //nur oberstes Shape ausgeben, hier wÜrde typischerweise dies Shape nach "vorne" (z-index) gebracht werden..
                            return;
                        }
            }
    
            public void UpdateLocation()
            {
                if (this.Shapes != null)
                    for (int i = 0; i < this.Shapes.Count; i++)
                    {
                        if (!this.Shapes[i].Backwards)
                        {
                            this.Shapes[i].Location = new PointF(this.Shapes[i].Location.X + this.Shapes[i].Speed, this.Shapes[i].Location.Y);
    
                            if (this.Shapes[i].Location.X > this.ClientSize.Width)
                                this.Shapes[i].Backwards = true;
                        }
                        else
                        {
                            this.Shapes[i].Location = new PointF(this.Shapes[i].Location.X - this.Shapes[i].Speed, this.Shapes[i].Location.Y);
    
                            if (this.Shapes[i].Location.X < -this.Shapes[i].Size.Width)
                                this.Shapes[i].Backwards = false;
                        }
                    }
    
                this.Invalidate();
            }
        }
    
        public class MyEllipse
        {
            public PointF Location { get; set; }
            public SizeF Size { get; set; }
            public Color Color { get; set; }
    
            public bool Backwards { get; set; }
            public float Speed { get; set; }
    
            public void Render(Graphics g)
            {
                if (g != null && this.Size.Width > 0f && this.Size.Height > 0f)
                {
                    g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
                    using (Brush b = new SolidBrush(this.Color))
                        g.FillEllipse(b, new RectangleF(this.Location, this.Size));
                }
            }
    
            public bool HitTest(float x, float y)
            {
                bool ret = false;
    
                using (System.Drawing.Drawing2D.GraphicsPath gPath = new System.Drawing.Drawing2D.GraphicsPath())
                {
                    gPath.AddEllipse(new RectangleF(this.Location, this.Size));
                    ret = gPath.IsVisible(x, y);
                }
    
                return ret;
            }
        }

    Viele Grüße,

      Thorsten


    • Bearbeitet Thorsten Gudera Montag, 21. August 2017 15:30
    • Als Antwort markiert geRe.LI Montag, 21. August 2017 20:15
    Montag, 21. August 2017 15:26

Alle Antworten

  • Hallo,

    scheint WindowsForms zu sein.

    Um double-buffering erfolgreich einzusetzen, muss das Control, auf dem gezichnet wird "double-ge-buffered" werden.

    Also, wenn Du etwa ein Panel zur Ausgabe benutzt, dann muss dieses Panel die Eigenschaft gesetzt haben. Am einfachsten per DoubleBuffered = true:

    Ein weiteres Problem kann durch den ImageAnimator entstehen. Man kann dann die Einzelbilder des Gif-Bildes schlichtweg im Timer Tick event selbst zeichnen (wenn die Zeiten stimmen, ansonsten einen extra timer nehmen)

    Außerdem empfehle ich, im Timer-Tick eventHandler den Timer zun stoppen, dann erst alle Aktionen ausführen und erst, wenn diese fertiggestellt sind, den Timer wieder zu starten, so vermeidet man Flickering durch konkurrierende Timer-Ticks (einer noch nicht fertig, abrer der nächste will schon zeichnen etc...)

        public class MyPanel:Panel
        {
            public MyPanel()
            {
                this.DoubleBuffered = true;
            }
    
            protected override void OnPaint(PaintEventArgs e)
            {
                base.OnPaint(e);
    
                //custom drawing (Objekte/Shapes zeichnen)
            }
        }

    Viele Grüße,

      Thorsten


    • Bearbeitet Thorsten Gudera Montag, 21. August 2017 15:36
    • Als Antwort markiert geRe.LI Montag, 21. August 2017 20:15
    Montag, 21. August 2017 14:48
  • ... hier mal ein kleines Bsp (-> neues WindowsFormsProject erstellen, code für Form1 hierdurch ersetzen...)

    Auf das Panel klicken...

        public partial class Form1 : Form
        {
            private MyPanel myPanel1 = new MyPanel();
            Random rnd = new Random();
            private Timer tmr = new Timer();
    
            public Form1()
            {
                InitializeComponent();
                myPanel1.BackColor = SystemColors.ControlDarkDark;
                myPanel1.Dock = DockStyle.Fill;
                myPanel1.Margin = new Padding(24);
                this.Controls.Add(myPanel1);
    
                this.FormClosing += Form1_FormClosing;
    
                tmr.Tick += Tmr_Tick;
    
                this.myPanel1.Click += MyPanel1_Click;
    
                this.Size = new Size(640, 480);
    
                GetShapes();
            }
    
            private void Form1_FormClosing(object sender, FormClosingEventArgs e)
            {
                this.tmr.Dispose();
            }
    
            private void Tmr_Tick(object sender, EventArgs e)
            {
                tmr.Stop();
    
                this.myPanel1.UpdateLocation();
    
                tmr.Start();
            }
    
            private void MyPanel1_Click(object sender, EventArgs e)
            {
                if (tmr.Enabled)
                    tmr.Stop();
                else
                {
                    tmr.Interval = 10;
                    tmr.Start();
                }
            }
    
            private void GetShapes()
            {
                myPanel1.Shapes = new List<MyEllipse>();
                for (int i = 0; i < 15; i++)
                {
                    MyEllipse el = new MyEllipse();
                    el.Color = Color.FromArgb(rnd.Next(256), rnd.Next(256), rnd.Next(256), rnd.Next(256));
                    el.Size = new SizeF(rnd.Next(myPanel1.ClientSize.Width / 2), rnd.Next(myPanel1.ClientSize.Height / 2));
                    el.Location = new PointF(rnd.Next(myPanel1.ClientSize.Width / 2), rnd.Next(myPanel1.ClientSize.Height / 2));
                    el.Speed = rnd.Next(1, 50) / 10f;
    
                    myPanel1.Shapes.Add(el);
                }
    
                myPanel1.Invalidate();
            }
        }
    
        public class MyPanel : Panel
        {
            public List<MyEllipse> Shapes { get; set; }
            public MyPanel()
            {
                this.DoubleBuffered = true;
            }
    
            protected override void OnPaint(PaintEventArgs e)
            {
                base.OnPaint(e);
    
                //custom drawing
                if (this.Shapes != null && this.Shapes.Count > 0)
                    for (int i = 0; i < this.Shapes.Count; i++)
                        this.Shapes[i].Render(e.Graphics);
            }
    
            protected override void OnMouseDown(MouseEventArgs e)
            {
                base.OnMouseDown(e);
    
                if (this.Shapes != null && this.Shapes.Count > 0)
                    for (int i = this.Shapes.Count - 1; i >= 0; i--)
                        if (this.Shapes[i].HitTest(e.X, e.Y))
                        {
                            MessageBox.Show("Shape No.: " + (i + 1).ToString() + " Color: " + this.Shapes[i].Color.ToString());
    
                            //nur oberstes Shape ausgeben, hier wÜrde typischerweise dies Shape nach "vorne" (z-index) gebracht werden..
                            return;
                        }
            }
    
            public void UpdateLocation()
            {
                if (this.Shapes != null)
                    for (int i = 0; i < this.Shapes.Count; i++)
                    {
                        if (!this.Shapes[i].Backwards)
                        {
                            this.Shapes[i].Location = new PointF(this.Shapes[i].Location.X + this.Shapes[i].Speed, this.Shapes[i].Location.Y);
    
                            if (this.Shapes[i].Location.X > this.ClientSize.Width)
                                this.Shapes[i].Backwards = true;
                        }
                        else
                        {
                            this.Shapes[i].Location = new PointF(this.Shapes[i].Location.X - this.Shapes[i].Speed, this.Shapes[i].Location.Y);
    
                            if (this.Shapes[i].Location.X < -this.Shapes[i].Size.Width)
                                this.Shapes[i].Backwards = false;
                        }
                    }
    
                this.Invalidate();
            }
        }
    
        public class MyEllipse
        {
            public PointF Location { get; set; }
            public SizeF Size { get; set; }
            public Color Color { get; set; }
    
            public bool Backwards { get; set; }
            public float Speed { get; set; }
    
            public void Render(Graphics g)
            {
                if (g != null && this.Size.Width > 0f && this.Size.Height > 0f)
                {
                    g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
                    using (Brush b = new SolidBrush(this.Color))
                        g.FillEllipse(b, new RectangleF(this.Location, this.Size));
                }
            }
    
            public bool HitTest(float x, float y)
            {
                bool ret = false;
    
                using (System.Drawing.Drawing2D.GraphicsPath gPath = new System.Drawing.Drawing2D.GraphicsPath())
                {
                    gPath.AddEllipse(new RectangleF(this.Location, this.Size));
                    ret = gPath.IsVisible(x, y);
                }
    
                return ret;
            }
        }

    Viele Grüße,

      Thorsten


    • Bearbeitet Thorsten Gudera Montag, 21. August 2017 15:30
    • Als Antwort markiert geRe.LI Montag, 21. August 2017 20:15
    Montag, 21. August 2017 15:26
  • Hallo Thorsten und vielen Dank für deine Mühe und den Code.

    Ich verwende kein Panel oder oder gleichen. Gezeichnet wird direkt auf die Form.

    Leider werde ich heute nicht mehr dazu kommen aber morgen weiss ich schon wo ich was nachschauen muss.

    Besten Dank nochmals für die Tips u. Lg

    GeRi

    Montag, 21. August 2017 20:15