AWT和Swing顯示GIF 動畫
很早就知道AWT和Swing組件可以直接通過 Graphics.drawImage() 來顯示 GIF 動畫, 但是一直不太做界面程序, 也就沒有仔細用過.
現在做 WoW Traverser, 因為修改是異步提交到服務器, 所以有必要對正在提交的更改進行界面提示, 打算做個黃色alpha混和的漸變閃動效果來實現, 于是第一反應是做一個透明度不斷變化的純黃色GIF, 畫到界面上去.
但是用GIMP總是做出來效果不對, 于是想干脆自己寫程序實現, 反正就是加個黃色的混和, 利用AWT和Swing顯示GIF相同的機制, 效率和穩定性應該也不會差. 最后花了一天時間研究AWT和Swing的動畫機制.
雖然也了解了一些原本不知道的細節, 但是結果還是讓我很失望, 原來drawImage時就是把當前Component注冊為該圖片的ImageObserver, 這樣GIF的下一幀到了需要顯示的時間時, 通過 imageUpdated() 通知這個組件, 最終是在 java.awt.Component.imageUpdated() 中處理這個問題. 令人非常失望的是, Java都到了1.5了, AWT中這個地方的處理還是那么蹩腳, 它只是檢查了一下更新頻率有沒有超過系統規定的上限, 只要沒超過, 那么它就對Component發一個完全的repaint()請求, 甚至都沒有去計算該圖片的覆蓋區域, 設置一個Clip區域以減少不必要的繪圖操作.
更甚者, 即使之后你不再顯示這個GIF了, AWT也不會自動從這個『曾經』顯示的圖片的ImageObserver列表中去掉這個Component, 最終導致的結果, 就是即使不再顯示那個GIF, 這個Component還是會以那個GIF的刷新頻率不斷的毫無必要的去repaint() !! 這不但蹩腳, 簡直都有點齷齪.
而且費了半天勁, 連手工去取消ImageObserver的接口都沒有找到, 也就是說: 如果不是永久性的顯示一個GIF, 千萬不要通過java.awt.Toolkit.createImage() 構造 GIF 的 java.awt.Image對象然后往你自己的Component上畫, 否則這個GIF圖片將長時間占用內存以及 ImageFetcher 線程的CPU資源, 同時耗費CPU時間和GUI資源用來絲毫沒有必要的反復repaint你的Component.
【編輯推薦】