c# - 通过单独的线程在表单上绘制

标签 c# winforms multithreading

我正在尝试构建一个多线程游戏,其中我有一个单独的线程用于在不是主线程的窗体上绘画。这将我们带到了线程安全技术,我已经阅读了很多关于它的文章,但我不确定我是否理解正确。

我的问题是我有一个结构,其中每个数据对象都在表单上自行绘制,所以我不知道如何实现它。

这是我的工作单线程代码片段:

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);
            }
    }

所以请任何人给我提示或好文章的链接,帮助我学习如何在另一个线程上分离绘图?

[编辑]

我设法实现了我打算做的事情 这就是我的编码方式

    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:参数无效

请指出该代码中的错误

最佳答案

我认为您需要绘制位图,然后在 OnPaint 方法中将该位图绘制到窗口。我稍后会演示。

正如 Hans 所指出的,在您设置的 OnPaint 方法中

formGraphics = e.Graphics;

但是在方法的末尾 e.Graphics 被释放,所以你不能再使用它了,如果你的代码必须

Engine.Draw(formGraphics);

你会得到一个异常(exception)。

所以基本上你需要有一个全局

Bitmap buffer = new Bitmap(this.Width, this.Height)

在您的异步线程中,您将调用您可以使用的位图的绘图

Graphics g=Graphics.FromBitmap(buffer);//

要获取图形对象,但请记住您必须

g.Dispose()

它或将它包裹在

using (Graphics g=Graphics.FromBitmap(buffer))
{
//do something here

}

我要试一试,看看能不能给你一个工作样本

编辑 这是您的工作示例。 我开始了一个新表格并在上面扔了一个按钮。我将 mainform backgroundimagelayout 更改为 none。

我认为您需要使用 .net 4.0 或更高版本,如果不使用它,请告诉我我可以更改它以匹配您的版本...我认为。

//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();
    }

}

关于c# - 通过单独的线程在表单上绘制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10714358/

相关文章:

c# - 在C#中,有没有办法始终如一地获取当前焦点窗口的选定文本内容?

c# - 线程池行为 : not growing from minimum size

c++ - 通过 shared_ptr : ThreadSanitzier false positive? 同步

ruby-on-rails - 多进程VS多线程服务器最受益于什么?

c# - Canvas.GetTop() 返回 NaN

c# - ActionFilterAttribute 的 Ninject 2 属性注入(inject)不起作用

c# - ASP.NET 身份验证允许/阻止页面访问并同时显示/隐藏链接

C# 运算符 ==、StringBuilder.Equals、Object.Equals 和 Object.ReferenceEquals 之间的区别

mysql - 我应该使用哪一个 : MySQL Lite or SQLite?

c# - 在 C# win Form 中创建维恩图