自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

雙緩沖原理在awt和swing中實(shí)現(xiàn)消除閃爍的方法

開發(fā) 后端
對(duì)于雙緩沖的分析是在坦克大戰(zhàn)游戲的設(shè)計(jì)時(shí)開始的,由于當(dāng)時(shí)忙于游戲的整體設(shè)計(jì),所以對(duì)這一個(gè)問題沒有進(jìn)行詳細(xì)的研究,現(xiàn)在就這個(gè)問題來談?wù)勛约旱囊恍┛捶ā?/div>

對(duì)于雙緩沖的分析是在坦克大戰(zhàn)游戲的設(shè)計(jì)時(shí)開始的,由于當(dāng)時(shí)忙于游戲的整體設(shè)計(jì),所以對(duì)這一個(gè)問題沒有進(jìn)行詳細(xì)的研究,現(xiàn)在就這個(gè)問題來談?wù)勛约旱囊恍┛捶ā?/P>

分析前提出幾個(gè)問題:

1、為什么當(dāng)想屏幕上添加圖片之后會(huì)有明顯的閃爍現(xiàn)象?

2、在awt中如何實(shí)現(xiàn)雙緩沖?

3、如何理解swing內(nèi)置雙緩沖以及比較他與awt中消除閃爍的方法區(qū)別在哪里?

首先我們來解答第一個(gè)問題:

我們?cè)谄聊簧献岳L圖形或者是添加圖片都是要通過所在畫布的重繪來實(shí)現(xiàn)的,因此閃爍的出現(xiàn)必然與重繪機(jī)制有著一些關(guān)聯(lián)。在awt中對(duì)于窗體畫布的重繪其條用順序是repaint() —>update()—>paint();我們來看看update()的源碼:

Java代碼

  1. /**     
  2.      * Updates the container.  This forwards the update to any lightweight    
  3.      * components that are children of this container.  If this method is    
  4.      * reimplemented, super.update(g) should be called so that lightweight    
  5.      * components are properly rendered.  If a child component is entirely    
  6.      * clipped by the current clipping setting in g, update() will not be    
  7.      * forwarded to that child.    
  8.      *    
  9.      * @param g the specified Graphics window    
  10.      * @see   Component#update(Graphics)    
  11.      */    
  12.     public void update(Graphics g) {     
  13.         if (isShowing()) {     
  14.             if (! (peer instanceof LightweightPeer)) {     
  15.                 g.clearRect(00, width, height);     
  16.             }     
  17.             paint(g);     
  18.         }     
  19. }    

 

從這里我們可以清晰的看到,update中有一個(gè)清屏的作用,即g.clearRect(0, 0, width, height);然后再在下面調(diào)用paint(g),函數(shù)進(jìn)行重繪。因此到這里的話我們可以在一定程度上對(duì)底層的重繪機(jī)制有一個(gè)了解了。

現(xiàn)在我們明白了,屏幕上之所以出現(xiàn)閃爍是因?yàn)樵趗pdate()方法內(nèi)先要嘩嘩的清空屏幕上原有的東西,然后又嘩嘩的往上畫,所以在我們需要不斷重繪的屏幕上出現(xiàn)閃爍是必然的了,哪怕CPU的速度快之又快。

通過上述的分析,在awt中我們解決閃爍問題的思路也因該隨之產(chǎn)生,即重寫update()函數(shù)的代碼,改變它的工作原理。于是我們引進(jìn)一段在坦克大戰(zhàn)中已經(jīng)重寫了的update()方法。其中通過改變重繪函數(shù)paint(g)重繪的畫布對(duì)象,由窗體的畫布變?yōu)榻厝〉膱D片上的畫布gImage,這樣的話就很大程度上改善這個(gè)問題了。具體如下

Java代碼

  1. // 重寫update方法,先將窗體上的圖形畫在圖片對(duì)象上,再一次性顯示     
  2.     public void update(Graphics g) {     
  3.         if (offScreenImage == null) {     
  4.             // 截取窗體所在位置的圖片     
  5.             offScreenImage = this.createImage(WIDTH, HEIGHT);     
  6.         }     
  7.         // 獲得截取圖片的畫布     
  8.         Graphics gImage = offScreenImage.getGraphics();     
  9.         // 獲取畫布的底色并且使用這種顏色填充畫布(默認(rèn)的顏色為黑色)     
  10. Color c = Color.BLACK;     
  11.         gImage.setColor(c);     
  12.         gImage.fillRect(00, WIDTH, HEIGHT); // 有清除上一步圖像的功能,相當(dāng)于gImage.clearRect(0, 0, WIDTH, HEIGHT)     
  13.         // 將截下的圖片上的畫布傳給重繪函數(shù),重繪函數(shù)只需要在截圖的畫布上繪制即可,不必在從底層繪制     
  14.         paint(gImage);     
  15.         //將接下來的圖片加載到窗體畫布上去,才能考到每次畫的效果     
  16.         g.drawImage(offScreenImage, 00null);     
  17.     }    

 

其實(shí)一言以蔽之就是通過重寫update()方法改變重繪函數(shù)paint(g)重繪的畫布對(duì)象g。

以上的討論我們都是在awt中進(jìn)行,然后大家就想將繼承Frame改為JFrame試試,結(jié)果一試就傻眼了,屏幕上居然又是嘩嘩的閃了,真是辛辛苦苦去改變,一下回到解放前,我們不是在update()中實(shí)現(xiàn)雙緩沖機(jī)制了嗎?請(qǐng)看下面的一個(gè)對(duì)比測(cè)試:

(1)在awt中測(cè)試update():

Java代碼

  1. // 重寫update方法,先將窗體上的圖形畫在圖片對(duì)象上,再一次性顯示     
  2.     public void update(Graphics g) {     
  3.              
  4.         System.out.println("awt的update()在此...");     
  5.              
  6.         if (offScreenImage == null) {     
  7.             // 截取窗體所在位置的圖片    

 

看看結(jié)果:

 

 

要是沒覺得意外的話就繼續(xù)往下看

在swing中測(cè)試update():

Java代碼

  1. // 重寫update方法,先將窗體上的圖形畫在圖片對(duì)象上,再一次性顯示     
  2.     public void update(Graphics g) {     
  3.              
  4.         System.out.println("Swing的update()在此...");     
  5.              
  6.         if (offScreenImage == null) {     
  7.             // 截取窗體所在位置的圖片    

 

結(jié)果是:

 

 

是不是有點(diǎn)吃驚了,在我沒有故意編出這個(gè)東西忽悠大伙的前提下我們可以得知,在swing中update()方法并沒有像awt的update()那樣隨時(shí)被調(diào)用,所以就很好解釋為什么該為繼承JFrame之后屏幕重繪閃爍了。就是你認(rèn)為自己改寫了update()方法就會(huì)解決這個(gè)問題是一廂情愿的,系統(tǒng)并不買你的帳,調(diào)都沒去調(diào)用吶!

那么怎么通過其他的方法消除swing中的閃爍問題呢,我們此時(shí)再回到出發(fā)點(diǎn),雙緩沖的核心就是改變paint(g)中的畫布,那么好了,我直接在paint(g)函數(shù)里實(shí)現(xiàn)不就得了,下面再來看這一段代碼:

Java代碼

  1. public void paint(Graphics g) {     
  2.         // 在重繪函數(shù)中實(shí)現(xiàn)雙緩沖機(jī)制     
  3.         offScreenImage = this.createImage(WIDTH, HEIGHT);     
  4.         // 獲得截取圖片的畫布     
  5.         gImage = offScreenImage.getGraphics();     
  6.         // 獲取畫布的底色并且使用這種顏色填充畫布,如果沒有填充效果的畫,則會(huì)出現(xiàn)拖動(dòng)的效果     
  7.         gImage.setColor(gImage.getColor());     
  8.         gImage.fillRect(00, WIDTH, HEIGHT); // 有清楚上一步圖像的功能,相當(dāng)于gImage.clearRect(0, 0, WIDTH, HEIGHT)     
  9.     
  10.         // 調(diào)用父類的重繪方法,傳入的是截取圖片上的畫布,防止再從最底層來重繪     
  11.         super.paint(gImage);     
  12.     
  13.         // 當(dāng)游戲沒有結(jié)束的時(shí)候繪出對(duì)戰(zhàn)雙方     
  14.         if (!getGameOver()) {     
  15.             // 畫出自己的坦克     
  16.             paintMyTank(gImage);     
  17.             // 畫出自己坦克發(fā)射的子彈     
  18.             paintMyBullet(gImage);     
  19.             // 畫出敵方坦克     
  20.             paintEnemyTank(gImage);     
  21.             // 畫出敵方坦克發(fā)射的子彈     
  22.             paintEnemyBullet(gImage);     
  23.         }     
  24.     
  25.         // 畫出草地     
  26.         paintGrass(gImage);     
  27.         // 畫出小河     
  28.         paintRiver(gImage);     
  29.         // 畫出石頭     
  30.         paintStone(gImage);     
  31.         // 畫出各種道具     
  32.         paintTool(gImage);     
  33.     
  34.         // 將接下來的圖片加載到窗體畫布上去,才能考到每次畫的效果     
  35.         g.drawImage(offScreenImage, 00null);     
  36.     }   

 

有一些相似的部分吧,其中最重要的是super.paint(gImage)這句,改變畫布在這里,消除閃爍也是在這里!!!

下面我們?cè)偬接懽詈笠粋€(gè)問題,即如何理解swing中內(nèi)置雙緩沖,我們首先從繼承體系來看,JFrame->Frame->Window->Container->Component,在Frame中的update()方法是從Container中繼承而來的,而JFrame中卻重寫了update()方法如下

Java代碼

  1. /**     
  2.  * Just calls paint(g).  This method was overridden to     
  3.  * prevent an unnecessary call to clear the background.    
  4.  *    
  5.  * @param g the Graphics context in which to paint    
  6.  */    
  7. public void update(Graphics g) {     
  8.     paint(g);     
  9. }   

 

與之前的同名方法相比,這里直接調(diào)用了paint()函數(shù)而沒有clearRect(),也就是清屏的方法,這里他試圖不通過清屏來阻止閃爍的發(fā)生。這也就是JFrame本身的一種處理方法。

以上是通過自己對(duì)雙緩沖的一些理解,其中還有很多問題,希望牛人們能夠積極指出來,并且一起討論這個(gè)問題。

【編輯推薦】

  1. 探秘JDK 7之二:半透明和任意形狀的窗口
  2. 探秘JDK 7:將會(huì)出現(xiàn)新的語言特性
  3. 我們真的能沒有Java嗎?
  4. 探秘Java 7:JVM動(dòng)態(tài)語言支持詳解
  5. 探秘Java 7新增垃圾回收器G1特性
責(zé)任編輯:金賀 來源: ITEYE博客
相關(guān)推薦

2009-07-14 15:01:02

AWT和Swing

2009-07-17 10:11:55

AWT和Swing

2009-07-17 09:36:14

SWT和Swing的區(qū)

2009-07-17 09:07:20

2009-07-17 11:13:46

AWT和SwingSwing組件

2009-07-10 17:20:38

Swing構(gòu)件AWT構(gòu)件

2009-07-10 17:03:17

AWT組件Swing組件

2009-07-16 13:37:33

Swing和AWT

2009-07-15 16:39:51

AWT和Swing

2009-07-14 12:58:49

AWT和Swing

2009-07-16 13:50:28

AWT和Swing

2009-07-17 15:30:30

JFaceAWT和SWTSwing

2009-07-14 15:12:36

SwingSWT和AWT

2009-07-17 10:01:14

Swing和AWT

2009-07-10 15:41:27

Swing AWT

2009-07-17 10:25:41

AWT和SwingSWT

2009-07-15 15:57:28

AWT或Swing

2009-07-15 10:06:54

Swing實(shí)現(xiàn)MDI

2011-04-15 17:33:39

SWINGAWT

2009-07-17 09:55:02

事件監(jiān)聽器SWT和SwingAWT
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)