Windows用戶界面編程中的界面閃爍問題
南京千里獨行版權(quán)所有轉(zhuǎn)載請保留本信息
在Windows圖形化用戶界面編程中,若程序自己繪制用戶界面時,會經(jīng)常碰到界面閃爍,比如其他窗口在上面移動,用戶界面滾動,這些都有可能導(dǎo)致閃爍。在一個容器中繪制特定的文檔,需要相應(yīng)作為繪圖容器的控件的OnPaint事件,需要在OnPaint事件處理中重新繪制文檔,而Windows操作系統(tǒng)一般會在兩種情況下觸發(fā)OnPaint事件:容器控件被其他窗體覆蓋后又顯示,還有就是容器控件的滾動處理。在這些情況下,Windows操作系統(tǒng)會頻繁的觸發(fā)OnPaint事件,而應(yīng)用程序會頻繁的在繪圖容器中重新繪制圖形,若應(yīng)用程序沒有進(jìn)行很好的優(yōu)化,則很有可能導(dǎo)致用戶界面閃爍。
用戶界面出現(xiàn)閃爍自然害處多多,首先它使得你的程序看起來不專業(yè),甚至有不穩(wěn)定的嫌疑,對于追求完美的你這么會容許它的存在呢;其次閃爍會損害用戶的視力,容易讓用戶產(chǎn)生視覺疲勞。
好了,廢話我不多說了,我們就來發(fā)現(xiàn)問題,分析問題,解決問題。
首先說說閃爍的本質(zhì),說到本質(zhì),就不得不提一些計算機(jī)系統(tǒng)結(jié)構(gòu)和Windows圖形用戶子系統(tǒng)的一些知識。我們知道,在計算機(jī)內(nèi)存中有一個區(qū)域叫做顯存,而顯卡則每過一些毫秒就從掃描顯存,然后根據(jù)操作顯示器來繪制一個個象素,因此每過一些毫秒顯示器顯示的內(nèi)容就會重新設(shè)置一遍,由于這是硬件操作,非???,若畫面內(nèi)容沒有變化,則人類肉眼是看不到這個刷新的,此時用戶界面是沒有任何閃爍。
某個時刻,應(yīng)用程序需要繪制用戶界面,首先需要清空繪制容器,因此將顯存一大片區(qū)域設(shè)置為白色,應(yīng)用程序剛完成了清空操作,還每來得及繪制內(nèi)容時,顯卡就刷新了,很快顯示器上顯示了一大片白色。同時,應(yīng)用程序開始繪制內(nèi)容,應(yīng)用程序運(yùn)行緩慢,它化了20毫秒繪制了文檔的上半身,文檔上半身主要為紅色,剛繪制了上半身,顯卡就好不留情的進(jìn)行刷新,很快顯示器上顯示了一半的文檔,剛才一半的白色大半變成了紅色,此時用戶看來,顯示器一下變成一片白,然后很快一半變成紅色,此時顯示器內(nèi)容產(chǎn)生了兩次大面積的內(nèi)容變幻,然后應(yīng)用程序又化了20毫秒顯示了文檔的下半身,文檔下半身主要為綠色,此時顯卡進(jìn)行刷新,顯示器上另一半還殘存的白色又變成綠色。由于應(yīng)用程序繪制文檔完畢,因此不再修改顯存,此時顯示器的顯示的內(nèi)容不再發(fā)生改變。
在上面的描述中,顯示器首先從花花綠綠變成一片白,20毫秒后一半變成紅色,又20毫秒后另一半變成綠色,如此大面積的顯示內(nèi)容短期的改變就是所謂的閃爍,此時計算機(jī)顯示器就是在折磨用戶的眼睛。
其實從廣義上說,計算機(jī)顯示器顯示的內(nèi)容頻繁的發(fā)生大面積的改變都是考驗人類的眼睛。有些人玩一些激烈的3D游戲,比如雷神CS之類的,若玩的時間長點眼睛就受不了。就是因為這些游戲程序?qū)е嘛@示器顯示的內(nèi)容頻繁的發(fā)生大面積的改變。因此游戲程序也算導(dǎo)致用戶界面閃爍。只不過這種閃爍不算難受。
通過上面的討論,知道了閃爍的根源,于是我們發(fā)現(xiàn)了問題,并分析了問題,現(xiàn)在解決問題。在目前的計算機(jī)結(jié)構(gòu)中,我們的應(yīng)用程序只能通過填充顯存來繪制用戶界面,在這種情況下,對付閃爍的不二法則就是快,應(yīng)用程序要非??斓男薷娘@存。對于每20毫秒進(jìn)行刷新操作的顯卡,若我們的應(yīng)用程序能在20毫秒內(nèi)修改顯存完畢,則在很多情況下顯卡就只會導(dǎo)致顯示器顯示的內(nèi)容發(fā)生改變,減少閃爍,應(yīng)用程序填充顯存前后顯存的數(shù)據(jù)進(jìn)行對比,若數(shù)據(jù)前后不一致的字節(jié)數(shù)越少,顯示器中刷新操作前后顏色發(fā)生改變的象素數(shù)就越少,這用戶界面的閃爍就越小。
提高應(yīng)用程序修改顯存的速度的方法有很多中,而且Windows操作系統(tǒng)為我們做了許多底層的操作。我們知道若一個窗體被覆蓋后又顯示了,則Windows操作系統(tǒng)就會向該窗體發(fā)送重繪消息,而且還會傳一個矩形數(shù)據(jù),該矩形表示窗體中需要刷新的區(qū)域,應(yīng)用程序可以根據(jù)這個矩形來重新繪制文檔的某個部分,這樣就不必要繪制所有的內(nèi)容,提高繪制速度,減少繪制時間,這就需要進(jìn)行繪圖代碼的優(yōu)化。
在某些情況下,繪圖速度很難優(yōu)化起來,此時可以采用所謂“雙緩沖”的技術(shù)來減少閃爍,應(yīng)用程序可以在內(nèi)存中創(chuàng)建一個和屏幕相兼容的圖形設(shè)備上下文。該上下文實際上處理一個保存在內(nèi)存中的BMP圖片對象,這樣就容許應(yīng)用程序緩慢地在這個BMP上繪制圖形。應(yīng)用程序繪制完畢,就用WIN32API函數(shù)BitBlt來將BMP圖片填充到顯存中,BitBlt函數(shù)速度非???,足以在屏幕的刷新周期內(nèi)完成繪圖,這樣能基本上避免閃爍。但雙緩沖也有缺點,首先增加程序復(fù)雜度,其次要消耗一些內(nèi)存,還有它讓整個繪圖時間變長,導(dǎo)致用戶進(jìn)行滾動時會產(chǎn)生“界面沉重感”,有“慣性”,此外還讓人偷懶而不注意繪圖操作的優(yōu)化。
俗話說,說得容量做到難,編程也一樣,本文中對付閃爍的說的輕巧,但在實際編程中,閃爍一直是圖形化用戶界面編程的老大難問題,需要精心的設(shè)計程序結(jié)構(gòu),優(yōu)化代碼,提高速度。這需要靠很多的理論知識和深厚的編程功底,這些需要長期的編程實踐。