2012-05-23 48 views
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:參數無效

會您請指向該代碼中的錯誤

+0

那麼,你想在這個代碼中插入線程? – Tudor

+0

@Tudor回答你的問題,請參閱編輯段落 –

+0

哪一行會拋出'ArgumentException'? – Tudor

回答

6

我認爲您需要繪製到位圖,然後在OnPaint方法中繪製該bi tmap到窗口。我會在一會兒演示。

正如漢斯指出,在OnPaint方法要設置

formGraphics = e.Graphics; 

,但在方法e.Graphics的端部設置,所以你不能再使用它,如果你的代碼一定要

Engine.Draw(formGraphics); 

你會得到一個異常。

所以基本上你需要有一個全球性的

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

在asynced線程,你會調用你的繪圖到該位圖,你可以使用

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

} 

}

+0

非常感謝..它真的幫了 –

+0

很高興我能幫上忙。 –