在默認GUI外觀、打印和運行性能方面,Java平臺一直在努力縮小本機應用程序和Java應用程序程序是之間的差距。隨著Java SE 6(代碼名為Mustang)的問世,一些新的功能又被加入,包括新的系統托盤功能,更好的打印支持和桌面API(java.awt.Desktop API),從而進一步縮小以上差距。本文中描述的這些新型桌面API允許Java應用程序與主機平臺上的特定文件類型的默認應用程序進行交互。為了更有效地描述這些API,本文還將向你展示一個簡單的示例應用程序DesktopDemo。
一、 桌面概述 這種新功能是由java.awt.Desktop類所提供的。這種API來源于JDesktop集成組件(JDIC)工程。該工程的目的是,使得基于Java技術的應用程序成為桌面平臺上的"第一等公民",并實現與桌面API的無縫集成。具體地說,這種新型桌面API允許你的Java應用程序實現如下功能:
· 使用一個特定的統一資源標志符(URI)啟動主機系統的默認瀏覽器
· 啟動主機系統的默認電子郵件客戶端
· 啟動特定的應用程序以打開、編輯或打印與之相關聯的文件
這些桌面API使用你的主機操作系統的文件關聯以啟動與特定文件類型相關聯的應用程序。例如,如果開放文檔文本(.odt)文件擴展名與OpenOffice書寫器應用程序相關聯,那么你的Java應用程序就可以啟動OpenOffice書寫器以打開、編輯或打印與這種關聯相關的文件。根據你的主機系統的不同,不同的應用程序可能關聯不同的行為。
二、 運行DesktopDemo應用程序 DesktopDemo是一個簡單Java應用程序-它使用了Mustang的桌面API。該應用程序提供了一個主窗口,允許你實現如下三項功能:
1. 以一個特定的URI啟動默認瀏覽器。
2. 用一個郵件接收者啟動默認電子郵件客戶端。
3. 啟動一個相關聯的應用程序以打開、編輯或打印文件。
圖1顯示了這個用戶接口(UI)。
 圖1:DesktopDemo用戶接口 |
你可以通過下載應用程序源代碼及相關的JAR文件來運行這個應用程序-把你的控制臺的活動目錄改變為該應用程序工程的dist目錄,并且使用一個Mustang JDK執行下列命令:
java -jar DesktopDemo.jar
三、 確定是否支持Desktop API 在啟動瀏覽器、電子郵件客戶端或任何應用程序之前,DesktopDemo必須確定是否你的平臺支持這種API。然而,DesktopDemo首先停用所有的圖形化的文本域和按鈕。在確定該平臺支持它們之后它該程序才啟用這些圖形組件。
在實例化這些UI后,該應用程序的構造器快速停用這個應用程序的少數幾個組件,如下列代碼所示:
public DesktopDemo() { //初始化所有的GUI組件. initComponents(); // 停用啟動瀏覽器和電子郵件客戶端的按鈕 // 停用打開,編輯和打印文件的按鈕 disableActions(); ... } /** * 停用所有的圖形組件,直到我們了解 * 是否支持它們的功能. */ private void disableActions() { txtBrowserURI.setEnabled(false); btnLaunchBrowser.setEnabled(false);
txtMailTo.setEnabled(false); btnLaunchEmail.setEnabled(false); rbEdit.setEnabled(false); rbOpen.setEnabled(false); rbPrint.setEnabled(false); txtFile.setEnabled(false); btnLaunchApplication.setEnabled(false); } ... public javax.swing.JTextField txtBrowserURI; public javax.swing.JButton btnLaunchBrowser; public javax.swing.JTextField txtMailTo; public javax.swing.JButton btnLaunchEmail; public javax.swing.JRadioButton rbEdit; public javax.swing.JRadioButton rbOpen; public javax.swing.JRadioButton rbPrint; public javax.swing.JTextField txtFile; public javax.swing.JButton btnLaunchApplication; |
使用Desktop.isDesktopSupported()方法來確定是否桌面API可用。在Solaris操作系統和Linux平臺上,這種API是依賴于Gnome庫的。如果這些庫不可用,那么這個方法將返回false。在確定支持這種API(也就是說,isDesktopSupported()返回true)之后,該應用程序就可以使用靜態方法getDesktop()來檢索一個Desktop實例。
Desktop desktop = null; //在使用更多的Desktop API前,首先檢查 //是否這種API為該特定主機上的特別的虛擬機所支持。 if (Desktop.isDesktopSupported()) { desktop = Desktop.getDesktop(); ... |
如果你的應用程序在調用getDesktop()之前不使用isDesktopSupported()進行API支持檢查,那么它必須準備捕獲一個UnsupportedOperationException異常-當你的應用程序在一個不支持這種特性的平臺上請求一個Desktop實例時將拋出這種異常。另外,如果你的應用程序運行于一種無鍵盤、鼠標和監視器環境下,該getDesktop()方法將拋出一個java.awt.HeadlessException異常。
一旦檢索完畢,該Desktop實例即允許你的應用程序瀏覽、郵寄、打開、編輯或甚至打印一個文件或URI,但是只有在被檢索的Desktop實例支持這些活動的前提下才行。每個這些活動被稱為一個行為(Action),并且每一個行為被描述為一個Desktop.Action枚舉實例:
· BROWSE-描述主機的默認瀏覽器執行的一種瀏覽行為
· MAIL-描述主機的默認電子郵件客戶端執行的一種郵件行為
· OPEN-描述一種與打開一特定的文件類型相關聯的應用程序執行的打開行為
· EDIT-描述一種與編輯一特定的文件類型相關聯的應用程序執行的編輯行為
· PRINT-描述一種與打印一特定的文件類型相關聯的應用程序執行的打印行為
在調用任何這些行為之前,一個應用程序必須確定是否該Desktop實例支持它們。這與確定是否一個Desktop實例可用是有所不同的。這個Desktop.isDesktopSupported()方法告訴你是否能夠創建一個實例。一旦獲得一個Desktop對象,你就可以查詢該對象來確定支持哪些特定類型的行為。如果該Desktop對象不支持特定的行為,或如果該桌面API本身并不被支持,那么DesktopDemo簡單地停用那些受影響的圖形組件。如圖2所示,在停用狀態下,不能使用這些組件來調用桌面特性。
 圖2:當不支持桌面API時圖形組件被停用。 |
通過使用一個新的Desktop實例,下列代碼檢查負責是否支持Desktop.Action并且啟用適當的圖形組件:
public DesktopDemo() { ... //在使用更多的桌面API前,首先檢查 //是否這種API為該特定主機上的特別的虛擬機所支持。 if (Desktop.isDesktopSupported()) { desktop = Desktop.getDesktop(); // 現在,啟用按鈕以實現被支持的行為 enableSupportedActions(); } ... } /** *啟用在該主機上被支持的行為。 *這些行為有:打開瀏覽器, *打開電子郵件客戶端,和使用它們相關聯的應用程序打開,編輯與打印文件。 */ private void enableSupportedActions() { if (desktop.isSupported(Desktop.Action.BROWSE)) { txtBrowserURI.setEnabled(true); btnLaunchBrowser.setEnabled(true); }
if (desktop.isSupported(Desktop.Action.MAIL)) { txtMailTo.setEnabled(true); btnLaunchEmail.setEnabled(true); } if (desktop.isSupported(Desktop.Action.OPEN)) { rbOpen.setEnabled(true); } if (desktop.isSupported(Desktop.Action.EDIT)) { rbEdit.setEnabled(true); } if (desktop.isSupported(Desktop.Action.PRINT)) { rbPrint.setEnabled(true); }
if (rbEdit.isEnabled() || rbOpen.isEnabled() || rbPrint.isEnabled()) { txtFile.setEnabled(true); btnLaunchApplication.setEnabled(true); } } |
一旦該應用程序確定了被支持的行為,它即啟用適當的圖形組件。如果所有的組件都被啟用,那么相應的UI應該看上去如圖3所示。
 圖3:當支持桌面API時,啟用組件。 |
四、 打開瀏覽器 調用下列實例方法將打開你的主機的默認瀏覽器:
public void browse(URI uri) throws IOException |
因為僅當支持相關聯的Desktop.ActionDesktopDemo時,UI組件才被啟用,所以,在實際調用browse()方法之前,這個簡單的演示應用程序不需要進行行為支持檢查。然而,在每一種調用之前檢查行為支持在實際中將增加程序的健壯性:
if (desktop.isSupported(Desktop.Action.BROWSE)) { //啟動瀏覽器 ... } |
DesktopDemo把一個java.awt.event.ActionListener添加到每一個按鈕上。當被啟用時,"Launch Browser"按鈕通過它的ActionListener調用下列方法:
private void onLaunchBrowser(java.awt.event.ActionEvent evt) { URI uri = null; try { uri = new URI(txtBrowserURI.getText()); desktop.browse(uri); } catch(IOException ioe) { ioe.printStackTrace(); } catch(URISyntaxException use) { use.printStackTrace(); } ... } |
這個browse()方法可能拋出各種類型的異常,這包括:當該URI為null時拋出一個NullPointerException異常;如果不支持BROWSE行為將拋出一個UnsupportedOperationException異常;如果不能發現或啟動一個缺省的瀏覽器或應用程序則拋出一個IOException異常;如果一個安全管理器否定一次調用則拋出一個SecurityException異常。
然而,如果一切順利,那么聽取器(Listener)將從圖4中相聯系的文本域中檢索文本,創建一個URI并且調用browse()方法。上面的代碼將啟動你的系統的默認瀏覽器并且指示該瀏覽器裝載該URI,如圖5所示。
 圖4:使用一個特定URI啟動默認瀏覽器。  圖5:使用桌面API啟動默認瀏覽器。 |
五、 發送電子郵件 如果支持該行為的話,該應用程序能夠啟動主機的默認電子郵件客戶端-通過調用這個Desktop實例方法:
public void mail(URI uri) throws IOException DesktopDemo為"Launch Mail"按鈕提供了一個ActionListener。在這種情況中,該聽取器調用下列方法: private void onLaunchMail(java.awt.event.ActionEvent evt) { String mailTo = txtMailTo.getText(); URI uriMailTo = null; try { if (mailTo.length() > 0) { uriMailTo = new URI("mailto", mailTo, null); desktop.mail(uriMailTo); } else { desktop.mail(); } } catch(IOException ioe) { ioe.printStackTrace(); } catch(URISyntaxException use) { use.printStackTrace(); } ... } |
該onLaunchMail()方法從相關的文本域中檢索電子郵件接收者,并且在存在一位接收者時使用一種mailto模式的參數創建URI,然后調用mail()方法。這個mail()方法被重載,這樣你可以使用(或不使用)一個描述其mailto接收者的URI(見圖6)來調用這個方法。
 圖6:使用一個電子郵件接收者啟動默認電子郵件客戶端。 |
當創建這個URI時,你可以使用多個電子郵件接收者。這個mailto模式支持CC,BCC,SUBJECT和BODY域。例如,可以使用下列文本來創建一個mailto URI:
mailto:duke@sun.com?SUBJECT=Happy New Year!&BODY=Happy New Year, Duke!
圖7顯示出相應的結果。
 圖7:桌面API使用多個mailto參數啟動默認電子郵件客戶端。 |
當然,你也可以不使用參數來調用mail()。在這種情況中,你的電子郵件客戶端將啟動一個新的沒有指定接收者、主題或郵件正文的電子郵件窗口。
六、 打開、編輯和打印文件 Java應用程序可以分別使用一個Desktop對象的open(),edit()和print()方法來從與其相聯系的應用程序中打開,編輯和打印文件(見圖8)。同樣,僅在該Desktop實例支持它們時,DesktopDemo才允許這些行為,因此在本應用程序環境下,不必再次進行這種支持檢查。
 圖8:啟動與一特定的文件類型相聯系的應用程序。 |
DesktopDemo中的每一個單選按鈕也都有它自己的ActionListener。在這種情況中,每一個單選按鈕都設置一個實例變量,以便描述最近選擇的按鈕的相關聯Desktop.Action:
Desktop.Action action; private void onPrintAction(java.awt.event.ActionEvent evt) { action = Desktop.Action.PRINT; } private void onEditAction(java.awt.event.ActionEvent evt) { action = Desktop.Action.EDIT; } private void onOpenAction(java.awt.event.ActionEvent evt) { action = Desktop.Action.OPEN; } |
當你按下"Launch Default Application"按鈕時,它調用它自己的聽取器-這將調用下列方法:
private void onLaunchDefaultApplication(java.awt.event.ActionEvent evt) { String fileName = txtFile.getText(); File file = new File(fileName); try { switch(action) { case OPEN: desktop.open(file); break; case EDIT: desktop.edit(file); break; case PRINT: desktop.print(file); break; } } catch (IOException ioe) { ioe.printStackTrace(); } ... } |
這個方法決定選擇哪個Desktop.Action并且調用適當的Desktop實例方法-open(),edit()或print()。每個方法都需要一個File參數-它被用于執行要求的行為。
有趣的是,不同的應用程序可以針對甚至相同的文件類型上的這些不同的行為進行注冊。例如,可以使用OPEN行為啟動Firefox瀏覽器,使用EDIT行為啟動Emacs,甚至使用PRINT行為啟動另外不同的應用程序。你的主機桌面的關聯用來決定應該調用什么樣的應用程序。
注意 使用Mustang中現有桌面API來操作桌面文件關聯是不可能的,而且目前只能使用平臺依賴的工具來創建或改變這些關聯。
七、 總結 桌面集成是Mustang的一個重要主題。Mustang支持這種主題的一種方式是提供一組java.awt.Desktop API。這種API允許Java應用程序啟動主機的默認瀏覽器和電子郵件客戶端。另外,Java應用程序能夠啟動與特定的文件類型相關聯的應用程序以打開,編輯和打印文件。盡管Java應用程序不能操作,創建,或改變文件關聯,但是這些桌面API確定允許Java應用程序啟動默認的相關聯的應用程序.