2011-11-26 21 views
0

我已經寫一個事件處理程序方法,它附連到Paint事件Form(就在主窗口)的。此事件發送一個PaintEventArgs,其中包含一個名爲Graphics的屬性,該屬性是System.Drawing.Graphics的一個實例。爲什麼PaintEventArgs.Graphics的行爲與Control.CreateGraphics不同?

這裏是我使用的代碼:

private void Form1_Paint(object sender, PaintEventArgs e) { 

    Bitmap bm = new Bitmap("fruit-dealer-full.jpg"); 

    Graphics g1 = this.CreateGraphics(); 
    Graphics g2 = e.Graphics; 

    // g1.DrawImage(bm, 0, 0, this.Width, this.Height); 
    // g1.DrawRectangle(
    //  Pens.White, 10.0f, 10.0f, this.Width - 200, this.Height - 200); 

    g2.DrawImage(bm, 0, 0, this.Width, this.Height); 
    g2.DrawRectangle(
      Pens.White, 10.0f, 10.0f, this.Width - 200, this.Height - 200); 

} 

最終,我只是想更好地瞭解這裏發生了什麼,但具體我有以下三個問題:

  1. 爲什麼g1重繪圖像中的整個窗口,而只g2吸引新的部分,即使我繪製之前調用g2.Clear()
  2. 爲什麼,無論是與對象Graphics,是圖像僅在調整窗口大小的增加,而不是當它是由更小的重繪?
  3. 如果PaintEventArgs.Graphics可以(或應該)不能用於繪圖,它是幹什麼用的呢?如果表單不需要重新繪製,我會想象它會阻止您創建新的實例Graphics;我錯過了嗎?
+0

只注意到了ResizeRedraw控制風格標誌,它可能會在一個情況下使用這樣的,但我仍然想要了解上面的內容! –

回答

3

你的.NET WinForms的孩子真的應該學習Win32 API。已經拿起Petzold的副本了!

爲什麼g1會在整個窗口中重新繪製圖像,而g2只會繪製新的部分,即使我在繪圖之前調用g2.Clear()?

推測g2是從BeginPaint收到的設備上下文的包裝。我想象WinForms爲你包裝PAINTSTRUCT::rcPaint - 這個變量描述了要繪的區域。這是預期的行爲 - 而不是刻錄CPU週期重新繪製整個窗口每一次窗口重疊一個像素,你可以重繪...只是一個像素!

g2.Clear推測是受rcPaint的限制。

g1可能是一個用於窗口的GetDC--它爲您提供了整個表面。

爲什麼在任何一個圖形對象中,圖像只在窗口大小增加時重繪,而不是在縮小圖像時重繪圖像?

底層窗口類可能沒有CS_HREDRAWCS_VREDRAW窗口樣式。如果沒有這些,沒有理由讓默認行爲請求您在窗口變小時重新繪製窗口:Windows知道整個窗口的外觀,它可以剪掉不需要的位。這與窗戶變大時不同,它不知道在新區域中繪製什麼。

如果PaintEventArgs.Graphics可以(或不應該)用於繪圖,那麼它的用途是什麼?我會想象它只是防止你不必重新繪製表單而不必創建一個新的Graphics實例;我錯過了嗎?

它用於繪圖。除非您有一些複雜的繪圖要求,否則您可以使用PaintEventArgs.Graphics來減少進入窗口的繪畫量。 (如上 - 這是CPU週期的一個巨大的保護,它可能是一個簡單的包裝上BeginPaintEndPaint - 這是how drawing to the client area is meant to be done

+0

謝謝 - 在思考問題的同時,我在最後一個小時基本得出了這些結論。爲什麼重新繪製表單,如果它將成爲已經繪製的子集? CreateGraphics的Graphics對象不知道已經繪製了什麼,所以它繪製了整個事物。謝謝:) –

+0

@jburbage感謝您的接受。 –

1
  1. 爲什麼G1重繪圖像中的整個窗口,而G2僅汲取新的部分,即使我繪製之前調用g2.Clear()?
    我不明白這一點,你正在繪製完整的形式在這兩種情況下。因此,無論應該引起整個窗體,也許你曾在不同的代碼這種行爲

  2. 爲什麼,有兩種圖形對象,是圖像只重繪時調整窗口大小的增加,而不是當它是由更小?
    因爲你應該在Form.Resize事件調用invalidate()啓動重繪

  3. 如果PaintEventArgs.Graphics可以(或應該)不能用於繪圖,它是幹什麼用的呢?我會想象它只是防止你不必重新繪製表單而不必創建一個新的Graphics實例;我錯過了嗎?
    他們是不同的,的createGraphics的是,應立即使用後丟棄(或內使用塊使用)的臨時對象,它用於簡單的任務不需要圖紙,如MeasureString或獲取上下文信息。對於繪圖,你總是應該使用PaintEventArgs.Graphics。一個很好的場景,其中顯而易見的區別是使用雙緩衝時,如果使用CreateGraphics獲得Graphics對象,則將獲得控件的Graphics對象,而從PaintEventArgs獲取它將獲得緩衝位圖。
+0

該應用程序是一個默認的Windows窗體應用程序,只添加了上述圖像並註冊了事件。沒有其他代碼;你可以嘗試一下,看看自己。我感謝你在2和3的幫助;我相信我讀的MCTS書是做錯了。 –

+0

我做了,它給了我在第一點的兩種情況下(g1,g2)相同的結果。也許這些是我們錯過的東西。 – 2011-11-26 01:16:23

+0

我相信你在Form_Load中設置DoubleBuffering爲true:this.SetStyle(ControlStyles.DoubleBuffer,true)這就是爲什麼我們有不同的結果.. – 2011-11-26 01:19:33

相關問題