国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開(kāi)發(fā)設(shè)計(jì) > 正文

Windows 窗體的.Net 框架繪圖技術(shù)

2019-11-17 02:58:19
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友
Windows 窗體的.Net 框架繪圖技術(shù)

當(dāng)編寫(xiě)一個(gè)典型的Windows 窗體程序時(shí),窗體和控件的繪制、效果等操作是不需要特別加以考慮的。這是為什么呢?因?yàn)橥ㄟ^(guò)使用.Net框架,開(kāi)發(fā)人員可以拖動(dòng)一系列的控件到窗體上,并書(shū)寫(xiě)一些簡(jiǎn)單的與事件相關(guān)聯(lián)的代碼然后在IDE中按F5,一個(gè)完完全全的窗體程序就誕生了!所有控件都將自己繪制自己,窗體或者控件的大小和縮放都調(diào)整自如。在這里經(jīng)常會(huì)用到的,且需要引起一點(diǎn)注意的就是控件效果。游戲,自定義圖表控件以及屏幕保護(hù)程序的編寫(xiě)會(huì)需要程序員額外撰寫(xiě)用于響應(yīng) Paint 事件的代碼。

  本文針對(duì)那些Windows 窗體開(kāi)發(fā)人員并有助于他們?cè)趹?yīng)用程序編制過(guò)程中使用簡(jiǎn)單的繪圖技術(shù)。首先,我們會(huì)討論一些基本的繪圖概念。到底誰(shuí)在負(fù)責(zé)進(jìn)行繪制操作?Windows 窗體程序是如何知道何時(shí)該進(jìn)行繪制的?那些繪制代碼究竟被放置在哪里?之后,還將介紹圖像繪制的雙重緩沖區(qū)技術(shù),你將會(huì)看到它是怎樣工作的,怎樣通過(guò)一個(gè)方法來(lái)實(shí)現(xiàn)緩存和實(shí)際顯示的圖像間的交替。最后,我們將會(huì)探討”智能無(wú)效區(qū)域”,實(shí)際就是僅僅重繪或者清除應(yīng)用程序窗體上的無(wú)效部分,加快程序的顯示和響應(yīng)速度。希望這些概念和技術(shù)能夠引導(dǎo)讀者閱讀完本文,并且有助于更快和更有效的開(kāi)發(fā)Windows 窗體程序。

  Windows 窗體使用GDI+圖像引擎,在本文中的所有繪圖代碼都會(huì)涉及使用托管的.Net 框架來(lái)操縱和使用Windows GDI+圖像引擎。

  盡管本文用于基本的窗體繪圖操作,但是它同樣提供了快速的、有效的且有助于提高程序性能的技術(shù)和方法。所以,在通讀本文之前建議讀者對(duì).Net框架有個(gè)基本的了解,包括Windows 窗體事件處理、簡(jiǎn)單的GDI+對(duì)象譬如Line,Pen和Brush等。熟悉Visual Basic .Net或者C#編程語(yǔ)言。

  概念

  Windows 應(yīng)用程序是自己負(fù)責(zé)繪制的,當(dāng)一個(gè)窗體”不干凈”了,也就是說(shuō)窗體改變了大小,或者部分被其它程序窗體遮蓋,或者從最小化狀態(tài)恢復(fù)時(shí),程序都會(huì)收到需要繪制的信息。Windows把這種”不干凈”狀態(tài)稱(chēng)為”無(wú)效的(Invalidated)”狀態(tài),我們理解為:需要重繪,當(dāng)Windows 窗體程序需要重繪窗體時(shí)它會(huì)從Windows消息隊(duì)列中獲取繪制的信息。這個(gè)信息經(jīng)過(guò).Net框架封裝然后傳遞到窗體的 PaintBackground 和 Paint 事件中去,在上述事件中適當(dāng)?shù)臅?shū)寫(xiě)專(zhuān)門(mén)用于繪制的代碼即可。

  簡(jiǎn)單的繪圖示例如下:

以下是引用片段:   using System;   using System.Drawing;   using System.Windows.Forms;   public class BasicX : Form   {   public BasicX()   {   InitializeComponent();   }   PRivate void BasicX_Paint(object sender, PaintEventArgs e)   {   Graphics g = e.Graphics;   Pen p = new Pen(Color.Red);   int width = ClientRectangle.Width;   int height= ClientRectangle.Height;   g.DrawLine(p, 0,0, width, height);   g.DrawLine(p, 0, height, width, 0);   p.Dispose();   }   private void InitializeComponent()   {   this.SetStyle(ControlStyles.ResizeRedraw, true);   this.ClientSize = new System.Drawing.Size(300, 300);   this.Text = "BasicX";   this.Paint += new PaintEventHandler(this.BasicX_Paint);   }   [System.STAThreadAttribute()]   public static void Main()   {   application.Run(new BasicX());   }   }

  上述代碼分成兩個(gè)基本的步驟來(lái)創(chuàng)建示例程序。首先 InitializeComponent 方法包含一些屬性的設(shè)置和附加窗體 Paint 事件的處理過(guò)程。注意,在方法中控件的樣式也同時(shí)被設(shè)置,設(shè)置控件的樣式也是自定義Windows 窗體及控件行為的一種有效途徑,譬如:控件的"ResizeRedraw"屬性指示當(dāng)窗體的大小變化發(fā)生以后需要對(duì)其完全進(jìn)行重繪,也就是說(shuō)重繪時(shí)總是需要對(duì)整個(gè)窗體的客戶(hù)區(qū)域進(jìn)行重繪。窗體的“客戶(hù)區(qū)域”是指除了標(biāo)題欄和邊框的所有窗體區(qū)域。可以進(jìn)行一個(gè)有趣的試驗(yàn),取消該控件的屬性然后再運(yùn)行程序,我們可以很明顯的看出為什么該屬性會(huì)被經(jīng)常的設(shè)置,因?yàn)榇绑w調(diào)整大小后的無(wú)效區(qū)域根本不會(huì)被重繪。

  好了,我們需要注意一下BasicX_Paint方法,正如先前所提到的,Paint 事件在程序需要重繪時(shí)被激活,程序窗體利用Paint事件來(lái)負(fù)責(zé)回應(yīng)需要重繪的系統(tǒng)消息,BasicX_Paint方法的調(diào)用需要一個(gè)對(duì)象 sender 和一個(gè)PaintEventArgs類(lèi)型的變量,PaintEventArgs類(lèi)的實(shí)例或稱(chēng)之為變量 e 封裝了兩個(gè)重要的數(shù)據(jù),第一個(gè)就是窗體的 Graphics 對(duì)象,該對(duì)象表示窗體可繪制的表面也稱(chēng)之為畫(huà)布用于繪制諸如線、文本以及圖像等,第二個(gè)數(shù)據(jù)就是ClipRectangle,該Rectangle對(duì)象表示窗體上無(wú)效的的矩形范圍,或者說(shuō)就是窗體需要重繪的區(qū)域。記住,當(dāng)窗體的ResizeRedDraw設(shè)置后,調(diào)整大小后該ClipRectangle的大小實(shí)際就等于窗體整個(gè)客戶(hù)區(qū)域的大小,或者是被其它程序窗體遮蓋的那部分剪切區(qū)域。關(guān)于部分剪切區(qū)域的用處我們會(huì)在智能重繪章節(jié)作更詳細(xì)的闡述。

  雙重緩沖區(qū)繪圖技術(shù)

  雙重緩沖區(qū)技術(shù)能夠使程序的繪圖更加快速和平滑,有效減少繪制時(shí)的圖像閃爍。該技術(shù)的基本原理是先將圖像繪制到內(nèi)存中的一塊畫(huà)布上,一旦所有的繪制操作都完成了,再將內(nèi)存中的畫(huà)布推到窗體的或者控件的表面將其顯示出來(lái)。通過(guò)這種操作后的程序能使用戶(hù)感覺(jué)其更加快速和美觀。

  下面提供的示例程序能夠闡明雙重緩沖區(qū)的概念和實(shí)現(xiàn)方法,這個(gè)示例所包含的功能已相當(dāng)完整,且完全可以在實(shí)際應(yīng)用中使用。在該章節(jié)后面還會(huì)提及該技術(shù)應(yīng)該配合控件的一些屬性設(shè)置才能達(dá)到更好的效果。

  要想領(lǐng)略雙重緩沖區(qū)繪圖技術(shù)所帶來(lái)的好處就請(qǐng)運(yùn)行SpiderWeb示例程序吧。程序啟動(dòng)并運(yùn)行后對(duì)窗口大小進(jìn)行調(diào)整,你會(huì)發(fā)現(xiàn)使用這種繪圖算法的效率不高,并且在調(diào)整大小的過(guò)程中有大量的閃爍出現(xiàn)。

  不具備雙重緩沖區(qū)技術(shù)的SpiderWeb示例程序

  縱觀程序的源碼你會(huì)發(fā)現(xiàn)在程序Paint事件激活后是通過(guò)調(diào)用LineDrawRoutine方法來(lái)實(shí)現(xiàn)線的繪制的。LineDrawRoutine方法有兩個(gè)參數(shù),第一個(gè)是Graphics對(duì)象是用于繪制線條的地方,第二個(gè)是繪圖工具Pen對(duì)象用來(lái)畫(huà)線條。代碼相當(dāng)簡(jiǎn)單,一個(gè)循環(huán)語(yǔ)句,LINEFREQ常量等,程序從窗體表面的左下一直劃線到其右上。請(qǐng)注意,程序使用浮點(diǎn)數(shù)來(lái)計(jì)算在窗體上的繪制位置,這樣做的好處就是當(dāng)窗體的大小發(fā)生變化時(shí)位置數(shù)據(jù)會(huì)更加精確。

以下是引用片段:   private void LineDrawRoutine(Graphics g, Pen p)   {   float width = ClientRectangle.Width;   float height = ClientRectangle.Height;   float xDelta = width / LINEFREQ;   float yDelta = height / LINEFREQ;   for (int i = 0; i < LINEFREQ; i++)   {   g.DrawLine(p, 0, height - (yDelta * i), xDelta * i, 0);   }   }

撰寫(xiě)很簡(jiǎn)單的用于響應(yīng)Paint事件SpiderWeb_Paint的代碼,正如前面所提到的,Graphics對(duì)象就是從Paint事件參數(shù)PaintEventArgs對(duì)象中提取出來(lái)的表示窗體的繪制表面。這個(gè)Graphics對(duì)象連同新創(chuàng)建Pen對(duì)象一起傳遞給LineDrawRoutine方法來(lái)畫(huà)出蜘蛛網(wǎng)似的線條,使用完Graphics對(duì)象和Pen對(duì)象后釋放其占用的資源,那么整個(gè)繪制操作就完成了。

以下是引用片段:   private void SpiderWeb_Paint(object sender, PaintEventArgs e)   {   Graphics g = e.Graphics;   Pen redPen = new Pen(Color.Red);   LineDrawRoutine(g, redPen);   redPen.Dispose();   g.Dispose();   }

  那么到底作怎么樣的改動(dòng)才能使上面的SpiderWeb程序?qū)崿F(xiàn)簡(jiǎn)單的雙重緩沖區(qū)技術(shù)呢?原理其實(shí)相當(dāng)簡(jiǎn)單,就是將應(yīng)該畫(huà)到窗體表面的繪制操作改成先畫(huà)到內(nèi)存中的位圖上,LineDrawRoutine向這個(gè)在內(nèi)存中隱藏的畫(huà)布執(zhí)行同樣的蜘蛛網(wǎng)繪制操作,等到繪制完畢再通過(guò)調(diào)用Graphics.DrawImage方法將隱藏的畫(huà)布上內(nèi)容推到窗體表面來(lái)顯示出來(lái),最后,再加上一些小的改動(dòng)一個(gè)高性能的繪圖窗體程序就完成了。

  請(qǐng)比較下面雙重緩沖區(qū)繪圖事件與前面介紹的簡(jiǎn)單繪圖事件間的區(qū)別:

以下是引用片段:   private void SpiderWeb_DblBuff_Paint(object sender, PaintEventArgs e)   {   Graphics g = e.Graphics;   Pen bluePen = new Pen(Color.Blue);   Bitmap localBitmap = new Bitmap(ClientRectangle.Width,ClientRectangle.Height);   Graphics bitmapGraphics = Graphics.FromImage(localBitmap);   LineDrawRoutine(bitmapGraphics, bluePen);   //把在內(nèi)存里處理的bitmap推向前臺(tái)并顯示   g.DrawImage(localBitmap, 0, 0);   bitmapGraphics.Dispose();   bluePen.Dispose();   localBitmap.Dispose();   g.Dispose();   }

  上面的示例代碼創(chuàng)建了內(nèi)存位圖對(duì)象,它的大小等于窗體的客戶(hù)區(qū)域(就是繪圖表面)的大小,通過(guò)調(diào)用Graphics.FromImage將內(nèi)存中位圖的引用傳遞給Graphics對(duì)象,也就是說(shuō)后面所有對(duì)該Graphics對(duì)象的操作實(shí)際上都是對(duì)內(nèi)存中的位圖進(jìn)行操作的,該操作在C++中等同于將位圖對(duì)象的指針復(fù)制給Graphics對(duì)象,兩個(gè)對(duì)象使用的是同一塊內(nèi)存地址。現(xiàn)在Graphics對(duì)象表示的是屏幕后方的一塊畫(huà)布,而它在雙重緩沖區(qū)技術(shù)中起到至關(guān)重要的作用。所有的線條繪制操作都已經(jīng)針對(duì)于內(nèi)存中的位圖對(duì)象,下一步就通過(guò)調(diào)用DrawImage方法將該位圖復(fù)制到窗體,蜘蛛網(wǎng)的線條就會(huì)立刻顯示在窗體的繪制表面而且絲毫沒(méi)有閃爍出現(xiàn)。

  這一系列的操作完成后還不是特別有效,因?yàn)槲覀兿惹疤岬搅耍丶臉邮揭彩嵌xWindows 窗體程序行為的一條途徑,為了更好的實(shí)現(xiàn)雙重緩沖區(qū)必須設(shè)置控件的Opaque屬性,這個(gè)屬性指明窗體是不負(fù)責(zé)在后臺(tái)繪制自己的,換句話說(shuō),如果這個(gè)屬性設(shè)置了,那么必須為清除和重繪操作添加相關(guān)的代碼。具備雙重緩沖區(qū)版本的SpiderWeb程序通過(guò)以上的設(shè)置在每一次需要重繪時(shí)都表現(xiàn)良好,窗體表面用其自己的背景色進(jìn)行清除,這樣就更加減少了閃爍的出現(xiàn)。

以下是引用片段:   public SpiderWeb_DblBuff()   {   SetStyle(ControlStyles.ResizeRedraw | ControlStyles.Opaque, true);   }   private void SpiderWeb_DblBuff_Paint(object sender, PaintEventArgs e)   {   Bitmap localBitmap = new Bitmap(ClientRectangle.Width,   ClientRectangle.Height);   Graphics bitmapGraphics = Graphics.FromImage(localBitmap);   bitmapGraphics.Clear(BackColor);   LineDrawRoutine(bitmapGraphics, bluePen);   }

  結(jié)果怎么樣?圖像的繪制平滑多了。從內(nèi)存中將蜘蛛網(wǎng)的線條推到前臺(tái)以顯示出來(lái)是完全沒(méi)有閃爍的,但是我們還是稍微停頓一下,先將內(nèi)存中的位圖修整一下再顯示出來(lái),可以添加一行代碼以便使線條看上去更加平坦。

以下是引用片段:   bitmapGraphics.SmoothingMode = SmoothingMode.AntiAlias;

  在將內(nèi)存中的位圖對(duì)象賦給Graphics后通過(guò)放置這行代碼,我們?cè)诋?huà)布上所畫(huà)的每一個(gè)線條都使用了反鋸齒,使凹凸不平的線條顯得更加平坦。

  具備雙重緩沖區(qū)技術(shù)的且使用AntiAliasing(反鋸齒)屬性的SpiderWeb_DblBuff示例程序

  完成了簡(jiǎn)單的雙重緩沖區(qū)應(yīng)用后有兩個(gè)問(wèn)題需要向讀者闡明,.Net中的某些控件例如:Button、PictureBox、Label還有PropertyGrid都已經(jīng)很好的利用了該技術(shù)!這些控件在默認(rèn)狀態(tài)下會(huì)自動(dòng)啟用雙重緩沖區(qū)技術(shù),用戶(hù)可以通過(guò)對(duì)“DoubleBuffer”屬性的設(shè)置來(lái)就可以實(shí)現(xiàn)雙重緩沖區(qū)技術(shù)。所以,用戶(hù)若使用PictureBox來(lái)繪制蜘蛛網(wǎng)將會(huì)更有效率一些,而且也使程序變得更加簡(jiǎn)單了。

  我們?cè)谶@里討論的雙重緩沖區(qū)技術(shù)既不是完全被優(yōu)化但也沒(méi)有什么太大的負(fù)面影響。雙重緩沖區(qū)技術(shù)是減少Windows 窗體繪制時(shí)閃爍的一條重要途徑,但是它也確實(shí)消耗不少內(nèi)存,因?yàn)樗鼘?huì)使用雙倍的內(nèi)存空間:應(yīng)用程序所顯示的圖像和屏幕后方內(nèi)存中的圖像。每次Paint事件被激活時(shí)都會(huì)動(dòng)態(tài)的創(chuàng)建位圖對(duì)象,這種機(jī)制會(huì)相當(dāng)耗費(fèi)內(nèi)存。而自帶雙重緩沖區(qū)技術(shù)的控件在使用DoubleBuffer屬性后執(zhí)行起來(lái)的優(yōu)化程度則會(huì)更好一些。

  使用GDI+的DIB(與設(shè)備無(wú)關(guān)的位圖)對(duì)象來(lái)實(shí)現(xiàn)這種畫(huà)面以外的內(nèi)存緩沖,自帶雙重緩沖區(qū)機(jī)制的控件則能好的利用該位圖對(duì)象。DIB是底層Win32的對(duì)象用于高效的屏幕繪制。同樣,值得注意的是GDI+的第一個(gè)版本GDI中僅與硬件加速有關(guān)以及一些簡(jiǎn)單功能可以直接使用,由于這樣的限制,像反鋸齒和半透明等屏幕繪制方法執(zhí)行起來(lái)的速度則相當(dāng)慢。盡管雙重緩沖區(qū)機(jī)制消耗了一些內(nèi)存但是它的使用不容置疑的增強(qiáng)了程序的執(zhí)行性能。

  智能重繪,在繪制前需要斟酌一下

  “智能無(wú)效”(智能重繪)就是在暗示程序員應(yīng)該明白僅應(yīng)對(duì)程序中無(wú)效的區(qū)域進(jìn)行重繪,對(duì)Regions對(duì)象所對(duì)應(yīng)的無(wú)效區(qū)

發(fā)表評(píng)論 共有條評(píng)論
用戶(hù)名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 潜江市| 丹棱县| 肥东县| 银川市| 中超| 黄山市| 赤水市| 金昌市| 垦利县| 平武县| 高雄市| 合水县| 灵武市| 拉萨市| 毕节市| 高青县| 呈贡县| 河东区| 安义县| 阿勒泰市| 唐河县| 大方县| 昌吉市| 大石桥市| 左贡县| 眉山市| 舟山市| 康平县| 兴城市| 桃园市| 定陶县| 繁峙县| 香河县| 石门县| 武夷山市| 泸定县| 平凉市| 长汀县| 舞阳县| 长汀县| 饶阳县|