2

メインスレッドではないフォームにペイントするための別のスレッドがあるマルチスレッドゲームを構築しようとしています。これは、私が多くの記事を読んだことのあるスレッドセーフな技術につながりますが、それが正しく理解できたかどうかはよくわかりません。

私の問題は、すべてのデータオブジェクトがフォーム上でそれ自体をペイントしている構造を持っているため、それを実装する方法がわかりませんでした.

これは、私の作業モノスレッド コードのスニペットです。

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 を受け取りました: パラメータが無効です

そのコードのエラーを指摘してください

4

1 に答える 1

9

ビットマップに描画してから、OnPaintメソッドでそのビットマップをウィンドウに描画する必要があると思います。すぐにデモンストレーションします。

ハンスが指摘したように、OnPaintメソッドでは設定しています

formGraphics = e.Graphics;

ただし、メソッドの最後にe.Graphicsが破棄されるため、コードが

Engine.Draw(formGraphics);

例外が発生します。

だから基本的にあなたはグローバルを持っている必要があります

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

非同期スレッドでは、使用できるビットマップへの描画を呼び出します

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

グラフィックスオブジェクトを取得するには、ただし、

g.Dispose()

それまたはそれを包む

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

}

少しの間それで遊んで、あなたに実用的なサンプルを手に入れることができるかどうか見るつもりです

編集これ があなたの作業サンプルです。私は新しいフォームを開始し、その上にボタンを投げました。メインフォームの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();
    }

}

}

于 2012-05-23T11:15:43.117 に答える