Click here to Skip to main content
15,886,857 members
Please Sign up or sign in to vote.
1.00/5 (2 votes)
I want to draw on a form from different threads with the same graphics object (sometimes) at the exact same time, for example to draw a fire pixels near the mouse when it moves on my form, OnPaint event gets called rarely and can't animate something like that, is there a better way than the one in the code below?

What I have tried:

public FormThreadsDrawing()
        {
            InitializeComponent();

            System.Windows.Forms.Timer t = new System.Windows.Forms.Timer();
            t.Interval = 10;
            t.Tick += T_Tick;
            t.Start();
        }

        List<Thread> lt = new List<Thread>();

        private void T_Tick(object sender, EventArgs e)
        {
            while (lt.Count > 0)
            {
                lt[0].Start();
                lt[0].Join();
                lt.RemoveAt(0);
            }
        }

        Graphics g;

        private void FormThreadsDrawing_Shown(object sender, EventArgs e)
        {
            g = CreateGraphics();

            lt.Add(new Thread(() =>
            {
                Pen p = new Pen(Color.Red);
                g.DrawLine(p, new Point(100, 60), new Point(200, 50));
                p.Dispose();
            }
            ));

            lt.Add(new Thread(() =>
            {
                using (Pen p = new Pen(Color.Blue))
                {
                    g.DrawLine(p, new Point(200, 600), new Point(200, 50));
                }
            }
            ));
        }
Posted
Updated 28-May-21 15:10pm
v6
Comments
[no name] 28-May-21 1:03am    
https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.control.mousemove?view=net-5.0
john1990_1 28-May-21 1:07am    
Thx but I know about the mouse move and how to make the fire pixels initially, but I want a way to draw them all each in a different thread and an instance of a method at the same time and animate it down and to the sides randomly (each fire pixel) by itself, what I mean is the drawing with a "Graphics g;" at the same time, is there a better way to do what is in my code that I have supplied to this question?
Richard MacCutchan 28-May-21 3:48am    
As I explained yesterday, you cannot do it this way.
john1990_1 28-May-21 12:42pm    
Why? maybe I made it.
I edited the code in the question.
Richard MacCutchan 28-May-21 12:49pm    
Good luck.

You cannot draw on or otherwise access controls from any thread other than the UI thread: the one that is created when your app starts.

The graphics object and it's methods are not thread safe, and you should never try to use them in background threads.

I don't know why you think this will be a good idea, but you cannot do it.
 
Share this answer
 
Elephanting hell... You just won't listen.

Here. This creates a control called "LinesCanvas" you can drop on a Form. It demonstrates everything I've been telling you. There's 2 methods, you can call, Start and Stop.
C#
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;

namespace CsLines
{
    public class LinesCanvas : Panel
    {
        Random RNG;
        int lineCount = 100;
        int stepLimit = 10;

        Timer _timer;
        List<Line> _lines;
        Bitmap _canvas;
        Pen _linePen;

        public LinesCanvas()
        {
            this.DoubleBuffered = true;
            SetupInternals();
        }

        public void Start()
        {
            SetupLines(lineCount);
            _timer.Enabled = true;
        }

        public void Stop()
        {
            _timer.Enabled = false;
        }

        protected void SetupInternals()
        {
            RNG = new Random();

            _linePen = new Pen(Color.LightBlue);

            _timer = new Timer();
            _timer.Enabled = false;
            _timer.Interval = 10;
            _timer.Tick += _timer_Tick;
        }

        protected override void OnResize(EventArgs eventargs)
        {
            base.OnResize(eventargs);

            UpdateCanvasSize();
        }

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

            if (_canvas != null)
                e.Graphics.DrawImageUnscaled(_canvas, 0, 0);
        }

        private void _timer_Tick(object sender, EventArgs e)
        {
            UpdateLinePositions();
            DrawLinesOnCanvas();
            this.Invalidate();
        }

        protected void UpdateLinePositions()
        {
            foreach (Line line in _lines)
            {
                line.UpdatePosition(ClientSize);
            }
        }

        protected void DrawLinesOnCanvas()
        {
            if (_canvas != null)
            {
                using (Graphics g = Graphics.FromImage(_canvas))
                {
                    g.Clear(Color.Black);

                    foreach (Line line in _lines)
                    {
                        g.DrawLine(_linePen, line.EndPoint1, line.EndPoint2);
                    }
                }
            }
        }

        protected void UpdateCanvasSize()
        {
            if (_canvas != null)
                _canvas.Dispose();

            _canvas = new Bitmap(ClientSize.Width, ClientSize.Height, System.Drawing.Imaging.PixelFormat.Format32bppRgb);
        }

        protected void SetupLines(int count)
        {
            _lines = new List<Line>(lineCount);

            for (int i = 0; i < count; ++i)
            {
                Line newLine = new Line(
                    RNG.Next(ClientSize.Width),
                    RNG.Next(ClientSize.Height),
                    RNG.Next(ClientSize.Width),
                    RNG.Next(ClientSize.Height),
                    RNG.Next(stepLimit) - 5,
                    RNG.Next(stepLimit) - 5,
                    RNG.Next(stepLimit) - 5,
                    RNG.Next(stepLimit) - 5
                );

                _lines.Add(newLine);
            }
        }

        protected override void Dispose(bool disposing)
        {
            _linePen.Dispose();

            base.Dispose(disposing);
        }
    }
}

Another class this needs, called "Line":
C#
using System.Drawing;

namespace CsLines
{
    public class Line
    {
        public Point EndPoint1;
        public Point EndPoint2;

        public Point Velocity1;
        public Point Velocity2;

        public Line(int x1, int y1, int x2, int y2, int vx1, int vy1, int vx2, int vy2)
        {
            EndPoint1 = new Point(x1, y1);
            EndPoint2 = new Point(x2, y2);

            Velocity1 = new Point(vx1, vy1);
            Velocity2 = new Point(vx2, vy2);
        }

        public void UpdatePosition(Size clientSize)
        {
            EndPoint1.X += Velocity1.X;
            EndPoint1.Y += Velocity1.Y;

            EndPoint2.X += Velocity2.X;
            EndPoint2.Y += Velocity2.Y;

            if (EndPoint1.X < 0)
            {
                EndPoint1.X = 0;
                Velocity1.X = -Velocity1.X;
            }

            if (EndPoint1.X > clientSize.Width)
            {
                EndPoint1.X = clientSize.Width;
                Velocity1.X = -Velocity1.X;
            }



            if (EndPoint1.Y < 0)
            {
                EndPoint1.Y = 0;
                Velocity1.Y = -Velocity1.Y;
            }

            if (EndPoint1.Y > clientSize.Height)
            {
                EndPoint1.Y = clientSize.Height;
                Velocity1.Y = -Velocity1.Y;
            }




            if (EndPoint2.X < 0)
            {
                EndPoint2.X = 0;
                Velocity2.X = -Velocity2.X;
            }

            if (EndPoint2.X > clientSize.Width)
            {
                EndPoint2.X = clientSize.Width;
                Velocity2.X = -Velocity2.X;
            }



            if (EndPoint2.Y < 0)
            {
                EndPoint2.Y = 0;
                Velocity2.Y = -Velocity2.Y;
            }

            if (EndPoint2.Y > clientSize.Height)
            {
                EndPoint2.Y = clientSize.Height;
                Velocity2.Y = -Velocity2.Y;
            }

        }
    }
}

Oh, and not a single goddamn thread anywhere.
 
Share this answer
 
Comments
john1990_1 28-May-21 21:25pm    
Thanks a lot.

I understood only 60%, I will watch what seems to be a decent 35 hours playlist of C# and then take another look.

youtube.com/playlist?list=PLLWMQd6PeGY12yNE714jffLFnMVZCwvvZ
Dave Kreskowiak 28-May-21 21:58pm    
Cute. None of that is going to help you with this.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900