Draw on a form by a separate thread
I think you will need to draw to a Bitmap, then in the OnPaint Method, draw that bitmap to the window. I will demonstrate in a moment.
As Hans pointed out, in the OnPaint method you are setting
formGraphics = e.Graphics;
but at the end of the method e.Graphics is disposed, so you can't use it anymore, if your code got to
Engine.Draw(formGraphics);
you would get an exception.
So basically you need to have a global
Bitmap buffer = new Bitmap(this.Width, this.Height)
in your asynced thread you would invoke your drawing to that Bitmap you can use
Graphics g=Graphics.FromBitmap(buffer);//
To get a graphics object, but remember you have to
g.Dispose()
it or wrap it in a
using (Graphics g=Graphics.FromBitmap(buffer))
{
//do something here
}
I am going to play with it for a few moments and see if I can get you a working sample
EDIT Here's your working sample. I started a new form and tossed a button on it. I changed the mainform backgroundimagelayout to none.
I think you need to be using .net 4.0 or better, if not using this, let me know I can change it to match your version... I think.
//you need this line to use the tasks
using System.Threading.Tasks;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public void Draw()
{
Bitmap buffer;
buffer = new Bitmap(this.Width, this.Height);
//start an async task
Task.Factory.StartNew( () =>
{
using (Graphics g =Graphics.FromImage(buffer))
{
g.DrawRectangle(Pens.Red, 0, 0, 200, 400);
//do your drawing routines here
}
//invoke an action against the main thread to draw the buffer to the background image of the main form.
this.Invoke( new Action(() =>
{
this.BackgroundImage = buffer;
}));
});
}
private void button1_Click(object sender, EventArgs e)
{
//clicking this button starts the async draw method
Draw();
}
}
}
Alaa Arori
Updated on July 22, 2022Comments
-
Alaa Arori almost 2 years
I'm trying to build a multithreaded game where I have a separate thread for painting on the form which is not the main thread. this brings us to thread-safe technics which I've read many articls about, but I'm not really sure I got it correctly.
my problem is that I have a structure where every data object is painting it self on the form so I didn't figure out how to implement it.
this is a snippet of my working mono-thread code:
public partial class Form1 : Form { GameEngine Engine; public Form1() { InitializeComponent(); Engine = new GameEngine(); } protected override void OnPaint(PaintEventArgs e) { Engine.Draw(e.Graphics); }
}
class GameEngine { Maze Map; List<Player> Players; public void Draw(Graphics graphics) { Map.Draw(graphics); foreach (var p in Players) { p.Draw(graphics); } }
}
so please can anyone give me a hint or a link to good article helping me to learn how to separate the drawing on an another thread?.
[Edit]
I managed to implement what I intended to do and this is how I coded it
protected override void OnPaint(PaintEventArgs e) { formGraphics = e.Graphics; DisplayThread = new Thread(new ThreadStart(Draw)); DisplayThread.Start(); } private void Draw() { if (this.InvokeRequired) { this.Invoke(new DrawDelegate(this.Draw)); } else { Engine.Draw(formGraphics); } }
but I got an ArgumentException : Parameter is not valid
would you please point to the error in that code