支援透明和不規則視窗已經成為 AWT 和 Swing 團隊長久以來夢寐以求的功能。儘管本機應用程式在主要作業系統上使用這項功能已經為時 已久,但在核心 Java 中還不能使用它。即將發布的 “Consumer JRE”進行中修改,也就是對 Java SE 6 進行重大更新。Java SE 6 將為 建立不規則、全透明和每個像素透明的最上層視窗提供 API。
曆史
本機應用程式的開發人員通常在開發 UI 應用程式中享受了更進階的靈活性。但是為此而付出的代價是將應用程式限制在某一特定平台上, 在許多情況中,這種靈活性不如獲得更為豐富的 UI 體驗和案頭緊密整合那麼重要。從傳統上講,跨平台 UI 工具箱,例如 Swing、SWT、QT 和 wxWidgets 趨向於被動應付眾所周知的兩難問題。當只有某些目標平台支援所要求的功能時怎麼辦?在這種情況下,類比缺失的功能可能只 會讓您南轅北轍。
不規則和透明視窗是跨平台 UI 工具箱局限性的最好例子。如果在特定目標平台不支援此項功能,那麼在該平台上就沒有什麼更多事情要做 了,此項功能可能用作強有力的參數向工具箱添加該項功能。但是,Swing 開發人員社區長久以來一直爭論主要目標平台不久就會提供這些功 能。事實上,Windows 自從 Windows 95 ( 參見 MSDN 上的 SetWindowRgn 文檔 )就已經支援不規則視窗了。在 X11 中匹配功能自從 1989 年 ( 參見 X Nonrectangular Window Shape Extension Library PDF 文檔 )就已經可用了。在 OS X 中您僅能在 JFrame 上設定透明的背 景顏色。
直到現在,對跨平台透明和不規則視窗有興趣的 Swing 應用程式有三種主要可選方式。
在顯示目標視窗之前使用 java.awt.Robot 捕獲案頭。這種方法在 Joshua Marinacci 和 Chris Adamson 編寫的 《 Swing Hacks 》 書中 的 第 41 章 中已經進行了評述。
使用 JNI 封裝目標平台的本機 API。
使用由 Timothy Wall 開發的 JNA 庫。該庫在 2007 年問世,Timothy 對於 不規則視窗 和 字母掩碼透明度 已經發表過部落格。
第一種方法的主要問題是要使用 Robot 類。即使您有許可權獲得螢幕截圖,您也必須在顯示視窗之前完成。此外,如何保持案頭背景同步處理?假 設在後台現正播放 YouTube 視頻。與視窗產生的事件不同( 調整大小,移動 ),AWT 並不在任何交叉視窗的重畫上提供註冊接聽程式的任何方 式。雖然 Chris 和 Joshua 通過在至少每秒內進行快照提供解決方案,這對於覆蓋後台視頻播放還不夠。而且在每次快照前需要對視窗加以隱 藏;這可能導致可見的閃爍。
使用 JNI 和 JNA 導致顯著的視覺保真性改進。純 JNI 會帶來開銷的急劇下降:您必須將目標平台的每一個相關的 API 綁定,還要捆綁本 機庫。JNA 為您分擔這項重任; 它捆綁主機庫並提供能在運行時提取並載入它們的類載入器。它支援 Linux、 OS X、 Windows、 Solaris 和 FreeBSD。
Consumer JRE
Java SE 6 Update N, 通常稱作 Consumer JRE, 是 Sun 公司的努力成果,為重新設定 Java 將其作為開發富傳統型應用程式的可行方法 。在 Consumer JRE 中的新功能和主要改進列表相當廣泛,並將特別閃耀的寶石隱藏在最新一周構建代碼之一的版本資訊中。Bug 6633275 被 簡單地賦予“需要支援不規則/透明視窗”的標題。但是該實現核心 JDK 新功能的可能性所帶給 Swing 開發人員的意義是深遠的。本文的剩餘 部分將顯示能夠實現和如何?該功能的幾個樣本。
在進一步研究之前,有一個非常重要的注意事項。由於 Consumer JRE 被官方認為是對穩定 JDK 發行的一個次要更新,因此在“公用”包 中不能添加任何新的 API( 類、方法等等 ),例如 java.awt 或 javax.swing。在本文中討論的所有 API 在新 com.sun.awt.AWTUtilities 類中出現,該類不是官方支援的部分 API。它在 Java SE 7 中的位置最有可能發生改變,簽名方法可能在現在和最終的 Consumer JRE 發行之 間發生輕微變化。所以當這種改變發生時準備更改您自己的代碼。
AWTUtilities 類
我首先討論 com.sun.awt.AWTUtilities 類,請參見 在核心 Java 中的透明和不規則視窗 部落格條目。首先我們從圖 1 中的簡單視窗入手 :
圖 1. 帶有控制項的視窗
要使視窗透明,您可以使用 AWTUtilities.setWindowOpacity(Window, float) 方法,如圖 2 所示:
圖 2. 相同的視窗,但是有 50% 的不透明度