由一个单独的线程在窗体上绘制 [英] Draw on a form by a separate thread
问题描述
我想建立一个多线程的游戏,我有这不是主线程的形式画上一个单独的线程。这给我们带来哪些我读过很多关于线程articls安全的工艺,但我真的不知道我得到了它正确。
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.
这是我工作的单线程code的一个片段:
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?.
我设法实现我打算做
这该是多么I codeD它
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);
}
}
但我得到了一个ArgumentException:参数是无效的。
but I got an ArgumentException : Parameter is not valid
请你指向误差在code
would you please point to the error in that code
推荐答案
我想你会需要画到一个位图,然后在OnPaint方法,绘制位图的窗口。我将演示在一个时刻。
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.
由于汉斯指出,在OnPaint方法要设置
As Hans pointed out, in the OnPaint method you are setting
formGraphics = e.Graphics;
但在方法e.Graphics的端部设置,所以你不能用它了,如果你的code得
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)
在您的asynced线程,你会调用图形以位图可以使用
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()
,或在其包装
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
修改这是你的工作样本。
我开始了新的形式和扔在一个按钮。我改变了的MainForm backgroundimagelayout无法比拟的。
EDIT Here's your working sample. I started a new form and tossed a button on it. I changed the mainform backgroundimagelayout to none.
我认为你需要使用.NET 4.0或更好,如果不使用这是,让我知道我可以改变它来搭配您的版本......我想。
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();
}
}
}
这篇关于由一个单独的线程在窗体上绘制的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!