利用GDI+的雙緩衝技術來提高繪圖效率

       進入.NET時代,Windows的繪圖技術也從GDI升級到了GDI+,從名字就能知道GDI+是對以前傳統GDI繪圖技術的一次升級,不過在微軟幾乎把所有的新技術都冠之.NET的情況下,GDI+竟然不叫做GDI.NET,還真讓我感到有點意外了。 :)
GDI+在一種與設備無關的環境下提供了一套統一的繪圖編程模型,極大的提高了Windows繪圖編程的方便性,我們再也不用創建什麼各種各樣複雜的設備環境了,說實話,我現在想起來都頭疼。
題歸正傳,關於如何進行GDI+的基本編程,我不能過多的加以描述,如果有對此概念還不太清楚的朋友,建議先去了解一下相關的資料,我們在這裏主要討論的是一種提高繪圖效率(主要是動畫效率)的雙緩衝技術在GDI+中的應用和實現。
實現目的
爲了能清楚的對比應用雙緩衝技術前後的效果,我編寫了一段程序來進行測試。首先,我創建了一個普通的Windows Application,在主Form中,我放置了一個定時器:timer1,然後將它的Interval屬性設置爲10,然後在Form上放置兩個按紐,分別用來控制定時器的開啓和關閉,最後,我還放置了一個label控件,用來顯示繪圖的幀數。
測試程序
在timer1的timer1_Tick事件中,我寫下了如下的代碼(其中flag是一個bool型標誌變量):
DateTime t1 = DateTime.Now;
Graphics g = this.CreateGraphics();
if(flag)
{
    brush = new LinearGradientBrush(new PointF(0.0f, 0.0f),  
  new PointF(700.0f, 300.0f), Color.Red, Color.Blue);
    flag = false;
}
else
{
    brush = new LinearGradientBrush(new PointF(0.0f, 0.0f),  
  new PointF(700.0f, 300.0f), Color.Blue, Color.Red);
    flag = true;
}
for(int j = 0; j < 60; j ++)
{
    for(int i = 0; i < 60; i++)
    {
  g.FillEllipse(brush, i * 10, j * 10, 10, 10);
    }
}
DateTime t2 = DateTime.Now;
TimeSpan sp = t2 - t1;
float per = 1000 / sp.Milliseconds;
this.label1.Text = "速度:" + per.ToString() + "幀/秒";
運行後,我點擊“開始”按紐,效果如下圖所示:
 
應用雙緩衝以前的效果圖(幀數:5幀/秒)
正如大家所看到的,我在程序中使用循環畫了幾百個圓形,然後在每次的定時器脈衝事件中使用不同方向的線性漸變來對它們進行填充,形成了一個動畫效果。不過不幸的是,程序運行起來閃爍很嚴重,幾乎每次刷新的時候都可以看到一條很明顯的掃描線從上慢慢的刷到下來完成整幅圖形的刷新動作。如果你不是要模擬老式雷達的區域掃描的話,這種速度不會滿足你的要求。
改進代碼
下面是我改進以後的代碼:
DateTime t1 = DateTime.Now;
Bitmap bmp = new Bitmap(600, 600);
Graphics g = Graphics.FromImage(bmp);
if(flag)
{
    brush = new LinearGradientBrush(new PointF(0.0f, 0.0f),  
      new PointF(700.0f, 300.0f), Color.Red, Color.Blue);
    flag = false;
}
else
{
    brush = new LinearGradientBrush(new PointF(0.0f, 0.0f),  
      new PointF(700.0f, 300.0f), Color.Blue, Color.Red);
    flag = true;
}
for(int j = 0; j < 60; j ++)
{
    for(int i = 0; i < 60; i++)
    {
  g.FillEllipse(brush, i * 10, j * 10, 10, 10);
    }
}
this.CreateGraphics().DrawImage(bmp, 0, 0);
DateTime t2 = DateTime.Now;
TimeSpan sp = t2 - t1;
float per = 1000 / sp.Milliseconds;
this.label1.Text = "速度:" + per.ToString() + "幀/秒";
運行後,我點擊“開始”按紐,效果如下圖所示:
 
應用雙緩衝以後的效果圖(幀數:9幀/秒)
經過改進後,畫面刷新速度大大加快,絕對看不到任何的“掃描線”,幀數也從5幀一下就提高到了9幀,幾乎是兩倍於前的速度。這究竟是什麼原因呢?讓我來講述其中的道理。
因爲圓是要一個一個畫上去,所以每畫一個圓,系統就要做一次圖形的繪製操作,圖形的重繪是很佔用資源的,當需要重繪的圖形數量很多的時候,所造成的系統開銷就特別大,造成我們看到的那種刷新緩慢的情況。那麼如何來解決這個問題呢?
答案就是雙緩衝,何謂“雙緩衝”?它的基本原理就是:先在內存中開闢一塊虛擬畫布,然後將所有需要畫的圖形先畫在這塊“虛擬畫布”上,最後在一次性將整塊畫布畫到真正的窗體上。因爲所有的單個圖形的繪製都不是真正的調用顯示系統來“畫”,所以不會佔用顯示系統的開銷,極大的提高的繪圖效率。
實現雙緩衝的具體步驟
我再來詳細解釋一下剛纔實現雙緩衝的具體步驟:
1、在內存中建立一塊“虛擬畫布”:
Bitmap bmp = new Bitmap(600, 600);
2、獲取這塊內存畫布的Graphics引用:
Graphics g = Graphics.FromImage(bmp);
3、在這塊內存畫布上繪圖:
g.FillEllipse(brush, i * 10, j * 10, 10, 10);
4、將內存畫布畫到窗口中
this.CreateGraphics().DrawImage(bmp, 0, 0);
總結
怎麼樣?是不是很簡單?但是正是這個簡單的操作大大提高了繪圖效率,所以如果你需要進行GDI+圖形編程,雙緩衝技術一定要掌握,特別是在進行大量圖形繪製刷新的情況下要儘量採用。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章