本文通過對 Eclipse 的 SWT 和 Java Swing、Abstract Windows Toolkit(AWT)GUI 工具包進行比較,可以幫助新應用程序的開發人員從中選擇適當的工具。您可以通過本文了解對每個工具包的基本特性的介紹,以及使用每個工具包的優缺點。
簡介
developerWorks 上另外一些作者已經展示了如何在 Swing 和 SWT 之間很好地進行遷移(參見 參考資料)。本文的目標是幫助您在開始開發項目之前確定選擇使用哪個 GUI 工具包。
但是首先我們要弄清一個問題:為什麼會有多個 Java™ GUI 工具包呢?最好的答案是,一個工具包並不能滿足所有的要求,最近也不會開發一個可以滿足所有要求的 GUI 工具包。每個工具包都有各自的優缺點,這樣就可以根據自己的需求和目標用戶來選擇適當的工具包。
下面就讓我們來學習有關這些工具包的知識。
AWT 概述
Abstract Windows Toolkit(AWT)是最原始的 Java GUI 工具包。AWT 的主要優點是,它在 Java 技術的每個版本上都成為了一種標准配置,包括早期的 Web 浏覽器中的 Java 實現;另外它也非常穩定。這意味著我們不需要單獨安裝這個工具包,在任何一個 Java 運行環境中都可以使用它,這一點正是我們所希望的特性。
AWT 是一個非常簡單的具有有限 GUI 組件、布局管理器和事件的工具包(參見 清單 1、清單 2 和 清單 3)。這是因為 Sun 公司決定為 AWT 使用一種最小公分母(LCD)的方法。因此它只會使用為所有 Java 主機環境定義的 GUI 組件。最終的結果非常不幸,有些經常使用的組件,例如表、樹、進度條等,都不支持。對於需要更多組件類型的應用程序來說,我們需要從頭開始創建這些組件。這是一個很大的負擔。
清單 1. 基本的 AWT Class 樹(全部在 java.awt 包中, “*” 表示抽象)
Object CheckboxGroup *Component Button Canvas CheckBox Choice Container Panel Applet ScrollPane Window Dialog Frame Label List TextComponent TextArea TextField MenuComponent MenuItem CheckboxMenuItem Menu PopupMenu
注意:另外幾個包中還有其他一些 AWT 組件,但是這是基本的組件集。
清單 2. AWT 提供了下面的布局管理器(全部在 java.awt 包中,“*” 表示接口)
*LayoutManager FlowLayout GridLayout *LayoutManager2 BorderLayout CardLayout GridBagLayout
注意:另外幾個包中還有一些 AWT 布局管理器,很多都是為它們進行布局的容器專門定制的,但是這是基本的布局管理器集。
清單 3. AWT 提供了以下事件(大部分在 java.awt.events 包中)
Object EventObject AWTEvent ActionEvent AdjustmentEvent ComponentEvent ContainerEvent FocusEvent InputEvent KeyEvent MouseEvent MouseWheelEvent PaintEvent WindowEvent HierarchyEvent InputMethodEvent InvocationEvent ItemEvent TextEvent
注意:其他幾個包中還有另外一些 AWT 事件,但是這是基本的事件集。這些是從更通用的事件生成的具體事件。
通常對於 AWT 來說(也適用於 Swing 和 SWT),每個事件類型都有一個相關的 XxxListener 接口(XxxAdapter 的實現可能為空),其中 Xxx 是去掉 Event 後綴的事件名(例如,KeyEvent 事件的接口是 KeyListener),用來把事件傳遞給處理程序。應用程序會為自己感興趣處理的事件的事件源(GUI 組件或部件)進行注冊。有時監聽接口要處理多個事件。
AWT 的一個很好的特性是它通常可以對 GUI 組件自動進行銷毀。這意味著您幾乎不需要對組件進行銷毀。一個例外是高級組件,例如對話框和框架。如果您創建了耗費大量主機資源的資源,就需要手動對其進行銷毀。
AWT 組件是 “線程安全的(thread-safe)”,這意味著我們不需要關心在應用程序中是哪一個線程對 GUI 進行了更新。這個特性可以減少很多 GUI 更新的問題,不過使 AWT GUI 運行的速度更慢了。
AWT 讓我們可以以自頂向下(top-down) 或自底向上(bottom-up) 或以任意組合順序來構建 GUI。自頂向下的意思是在創建子組件之前首先創建容器組件;自底向上的意思是在創建容器(或父)組件之前創建子組件。在後一種情況中,組件的存在並不依賴於父容器,其父容器可以隨時改變。
通常來說,AWT GUI 都是不可訪問的。系統並沒有為 AWT 程序員提供 API 來指定可訪問性信息。可訪問性(accessibility)處理的是殘疾人可以怎樣使用應用程序的問題。一個應用程序要想有很好的可訪問性,必須與運行平台一起,讓殘疾人可以通過使用適當的輔助技術(提供其他用戶接口的工具)來使用這些應用程序。很多政府和企業都有一些強制要求應用程序為實現可訪問性而采用的標准。
Sun 希望 Java 語言能夠成為一種 “編寫一次就可以隨處運行(write once, run everywhere,即 WORE)” 的環境。這意味著可以在一台機器上開發和測試 Java 代碼(例如在 Windows® 上),然後不經測試就可以在另外一個 Java 主機上運行同樣的 Java 代碼。對於大部分情況來說,Java 技術都可以成功實現這種功能,但是 AWT 卻是一個弱點。由於 AWT 要依賴於主機 GUI 的對等體(peer)控件(其中每個 AWT 組件都有一個並行的主機控件或者對等體)來實現這個 GUI,這個 GUI 的外觀和行為(這一點更重要)在不同的主機上會有所不同。這會導致出現 “編寫一次隨處測試(write once, test everywhere,即 WOTE)” 的情況,這樣就遠遠不能滿足我們的要求了。
AWT 提供了一個豐富的圖形環境,尤其是在 Java V1.2 及其以後版本中更是如此。通過 Graphics2D 對象和 Java2D、Java3D 服務,我們可以創建很多功能強大的圖形應用程序,例如畫圖和制表包;結合使用 JavaSound,我們還可以創建非常有競爭力的交互式游戲。
Swing 概述
Java Swing 是 Java Foundation Classes(JFC)的一部分,它是試圖解決 AWT 缺點的一個嘗試。在 Swing 中,Sun 開發了一個經過仔細設計的、靈活而強大的 GUI 工具包。不幸的是,這意味著我們又要花一些時間來學習 Swing 了,對於常見的情況來說,Swing 有些太復雜了。
Swing 是在 AWT 組件基礎上構建的。所有 Swing 組件實際上也是 AWT 的一部分。Swing 使用了 AWT 的事件模型和支持類,例如 Colors、Images 和 Graphics。Swing 組件、布局管理器以及事件總結如下(參見 清單 4、清單 5 和 清單 6)。正如您可以看到的一樣,這些組件集比 AWT 提供的組件集更為廣泛,與 SWT 組件集相比也毫不遜色。
清單 4. 基本的 Swing Class 樹(全部在 javax.swing 包或其子包中,“*” 表示抽象類)
Object *Component Container *JComponent *AbstractButton JButton JMenuItem JCheckBonMenuItem JMenu JRadioButonMenuItem *JToggleButton JCheckBox JRadioButton Box Filler JColorChooser JComboBox JDesktopIcon JFileChooser JInternalFrame JLabel JLayeredPane JDesktopPane JList JMenuBar JOptionPane JPanel JPopupMenu JProgressBar JRootPane JScrollBar JScrollPane JSeparator JSlider JSplitPane JTabbedPane JTable JTableHeader *JTextComponent JEditorPane FrameEditorPane JTextPane JTextArea JtextField JPasswordField JToolBar JToolTip JTree JViewport ScrollableTabViewport Panel Applet JApplet Window Dialog JDialog Frame JFrame JWindow
注意:在另外幾個包中還有其他一些 Swing 組件,但是這是基本的組件集。
清單 5. Swing 提供了以下 LayoutManagers(全部在 javax.swing 包或其子包中,“*” 表示接口)
*LayoutManager CenterLayout *LayoutManager2 BoxLayout OverlayLayout SpringLayout
注意:在另外幾個包中還有其他一些 Swing 布局管理器,很多都是為它們所布局的容器而專門定制的,但是這是基本的布局管理器集。
清單 6. Swing 提供了以下事件(大部分在 javax.swing.events 包及其子包中)
Object EventObject AWTEvent AncestorEvent ComponentEvent InputEvent KeyEvent MenuKeyEvent MouseEvent MenuDragMouseEvent InternalFrameEvent
注意:在另外幾個包中還有其他一些 AWT 事件,但是這是基本的事件集。這些是從更通用的事件生成的 “高級” 事件。
為了克服在不同主機上行為也會不同的缺點,Swing 將對主機控件的依賴性降至了最低。實際上,Swing 只為諸如窗口和框架之類的頂層 組件使用對等體。大部分組件(JComponent 及其子類)都是使用純 Java 代碼來模擬的。這意味著 Swing 天生就可以在所有主機之間很好地進行移植。因此,Swing 通常看起來並不像是本地程序。實際上,它有很多外觀,有些模擬(盡管通常並不精確)不同主機的外觀,有些則提供了獨特的外觀。
Swing 對基於對等體的組件使用的術語是重量級(heavyweight),對於模擬的組件使用的術語是輕量級(lightweight)。實際上,Swing 可以支持在一個 GUI 中混合使用重量級組件和輕量級組件,例如在一個 JContainer 中混合使用 AWT 和 Swing 控件,但是如果組件產生了重疊,就必須注意繪制這些控件的順序。
Swing 無法充分利用硬件 GUI 加速器和專用主機 GUI 操作的優點。結果是 Swing 應用程序可能比本地 GUI 的程序運行速度都慢。Sun 花費了大量的精力來改進最近版本的 Swing (Java V1.4 和 1.5)的性能,這種缺點正在變得日益微弱。由於 Swing 的設計更加健壯,因此其代碼基礎也更堅實。這意味著它可以在一台健壯的機器上比 AWT 和 SWT 上運行得更好。
除了具有更多的組件、布局管理器和事件之外,Swing 還有很多特性使得自己比 AWT 的功能更加強大。下面是更為重要的幾個特性:
模型與視圖和控件分離 對於這個模型中的所有組件(例如按鈕、列表、表、樹、富文本)來說,模型都是與組件分離的。這樣可以根據應用程序的需求來采用模型,並在多個視圖之間進行共享。為了方便起見,每個組件類型都提供有默認的模型。可編程外觀 每個組件的外觀(外表以及如何處理輸入事件)都是由一個單獨的、可動態替換的實現來進行控制的。這樣我們就可以改變基於 Swing 的 GUI 的部分或全部外觀。呈現器和編輯器 大部分顯示模型內容的組件,例如列表、表和樹,都可以處理幾乎所有類型的模型元素。這可以通過為每種組件類型和模型類型映射一個渲染器或編輯器來實現。例如,一個具有包含 java.util.Date 值的列的表可以有一些專用的代碼來呈現數據值和編輯數據值。每一列都可以有不同的類型。可訪問性 創建一個殘疾人可以訪問的 GUI 是非常重要的。Swing 為實現具有可訪問性的 GUI 提供了豐富的基礎設施和 API。這種支持是單獨的,但是如果主機上具有可訪問性支持,那麼它們應該集成在一起。
與 AWT 一樣,Swing 可以支持 GUI 組件的自動銷毀。Swing 還可以支持 AWT 的自底向上和自頂向下的構建方法。
與 AWT 不同,Swing 組件不是線程安全的,這意味著您需要關心在應用程序中是哪個線程在更新 GUI。如果在使用線程時出現了錯誤,就可能會出現不可預測的行為,包括用戶界面故障。有一些工具可以幫助管理線程的問題。
與 AWT 類似,Swing 的一個優點是,它也是 Java 技術的一種標准配置。這意味著您不需要自己來安裝它了。不幸的是,Swing 已經有了很大的變化,因此它很容易變得依賴於最新版本的 Java 語言所提供的特性,這可能會強制用戶更新自己的 Java 運行時環境。
SWT 概述
與 AWT 的概念相比,SWT 是一個低級的 GUI 工具包。JFace 是一組用來簡化使用 SWT 構建 GUI 的增強組件和工具服務。SWT 的構建者從 AWT 和 Swing 實現中學習了很多經驗,他們試圖構建一個集二者優點於一體而沒有二者的缺點的系統。從很多方面來說,他們已經成功了。
SWT 也是基於一個對等體實現的,在這一點上它與 AWT 非常類似。它克服了 AWT 所面臨的 LCD 的問題,方法如下:定義了一組控件,它們可以用來構建大部分辦公應用程序或開發者工具,然後可以按照逐個主機的原則,為特定主機所沒有提供的控件創建模擬控件(這與 Swing 類似)。對於大部分現代主機來說,幾乎所有的控件都是基於本地對等體的。這意味著基於 SWT 的 GUI 既具有主機外觀,又具有主機的性能。這樣就避免了使用 AWT 和 Swing 而引起的大部分問題。特定的主機具有一些低級功能控件,因此 SWT 提供了擴充(通常是模擬的)版本(通常使用 “C” 作為名字中的第一個字母),從而可以產生更一致的行為。
在對等體工作方式上,SWT 與 AWT 不同。在 SWT 中,對等體只是主機控件上的一些封裝程序而已。在 AWT 中,對等體可以提供服務來最小化主機之間的差異(就是在這裡,AWT 碰到了很多行為不一致的問題)。這意味著 SWT 應用程序實際上就是一個主機應用程序,它必然會全部繼承主機的優點和缺點。這還意味著 SWT 不能完全實現 WORE 的目標;它更像是一種 WOTE 解決方案。這就是說,SWT 盡管不如 Swing 那麼優秀,但是它在創建可移植解決方案方面是很傑出的。
SWT 部件、布局和事件總結如下(參見 清單 7、清單 8 和 清單 9)。正如您可以看到的一樣,這些組件集比 AWT 提供的組件集更為廣泛,與 Swing 組件集相比也毫不遜色。
清單 7. 基本的 SWT Class 樹(大部分在 org.ecipse.swt.widgets 或 org.eclipse.swt.custom 包或子包中,“*” 表示抽象類,“!” 表示在 custom 包中,“~” 表示在其他包中)
Object *Dialog ColorDialog DirectoryDialog FileDialog FontDialog MessageDialog PrintDialog *Widget Menu *Item CoolItem !CTabItem MenuItem TabItem TableColumn TableItem TableTreeItem ToolItem TrayItem TreeColumn TreeItem *Control Button Label ProgressBar Sash Scale Scrollable Composite ~Browser Canvas *~AbstractHyperlink ~Hyperlink ~ImageHyperlink *~ToggleHyperline ~TreeNode ~Twistie AnimatedProgress !CLabel Decorations Shell FormText StyledText TableCursor !CBanner !CCombo Combo CoolBar !CTabFolder ~ExpandableComposite ~Section ~FilteredList ~FilteredTree ~Form Group ~PageBook ProgressIndicator !SashForm !ScrolledComposite TabFolder Table TableTree ToolBar Tray Tree ViewForm List Text Slider
注意:在另外幾個包中還有其他一些 SWT 部件,但是這是基本的部件集。
與 AWT 和 Swing 布局管理器類似,SWT 也提供了非常豐富的布局部件集。布局系統與嵌套容器一起使用,可以生成所需要的任何布局算法。所有這 3 個 GUI 庫也可以支持對部件的定位實現絕對控制。SWT 沒有等效的 BorderLayout 部件,這一點非常令人失望。FormLayout 對於創建表單基本輸入來說非常好用。我認為 SWT 的布局機制比 AWT/Swing 布局部件集的使用更難學習。
清單 8. SWT 提供了以下布局管理器(大部分在 org.eclipse.swt.layout 和 org.eclipse.swt.custom 包或子包中,“*” 表示接口,“!” 表示在 custom 包中)
*Layout FillLayout FormLayout GridLayout RowLayout !StackLayout
注意:在另外幾個包中還有其他一些 SWT 布局管理器,很多都是為它們所布局的容器而專門定制的,但是這是基本的布局管理器集。
與 AWT 和 Swing 事件系統一樣,SWT 提供了非常豐富的事件集。盡管這些事件並不能與 AWT/Swing 的事件一一對應(例如 AWT 和 Swing 的按鈕都會產生 ActionEvent 事件,而 SWT 的按鈕產生的則是 SelectionEvent 事件),但是它們通常都是等價的。
清單 9. SWT 提供了以下事件(大部分在 org.eclipse.swt.events 包或 org.eclipse.swt.custom 包或其子包中,“*” 表示抽象,“!” 表示在 custom 包中)
Object EventObject SWTEventObject TypedEvent AimEvent !BidiSegmentEvent ControlEvent !CTabFlolderEvent DisposeEvent DragSourceEvent DragTargetEvent !ExtendedModifyEvent focusEvent HelpEvent KeyEvent TraverseEvent VerifyEvent !LineBackgroundEvent !LineStyleEvent MenuEvent ModifyEvent MouseEvent PaintEvent SelectionEvent TreeEvent ShellEvent !TextChangedEvent !TextChangingEvent
注意:在另外幾個包中還有其他一些 SWT 事件,但是這是基本的事件集。這些是從更通用的事件生成的具體事件。
很多 Swing 組件,例如 JTable,都有自己的模型。對應的 SWT 控件(例如 Table)則沒有;不過它們有自己的條目。條目通常用來限制顯示文本或通常很小的圖像(例如圖標)。為了提供一種類 Swing 的模型接口,SWT 使用了 JFace ContentProviders。這些組件可以在應用程序提供的模型(例如 List 或 Table 使用的 java.util.Array )和用作視圖的控件之間充當一個橋梁。為了將任意模型對象格式化成條目,SWT 使用了 JFace LabelProviders,它們可以為任何模型對象生成一個文本或圖標格式。這可以對復雜模型對象的混合顯示進行限制。其他類似組件,例如 ColorProviders 和 LabelDecorators,可以增強對這些條目的顯示。對於 Tables 的特例來說,SWT 提供了 CellEditor,它可以臨時將任意 SWT 控件鏈接到一個 Table 單元格上,從而當作這個單元格的編輯器使用。
SWT 不支持 GUI 控件的自動銷毀。這意味著我們必須顯式地銷毀所創建的任何控件和資源,例如顏色和字體,而不能利用 API 調用來實現這種功能。這種工作從某種程度上來說得到了簡化,因為容器控制了其子控件的自動銷毀功能。
使用 SWT 只能自頂向下地構建 GUI。因此,如果沒有父容器,子控件也就不存在了;通常父容器都不能在以後任意改變。這種方法不如 AWT/Swing 靈活。控件是在創建時被添加到父容器中的,在銷毀時被從父容器中刪除的。而且 SWT 對於 style 位的使用只會在構建時進行,這限制了有些 GUI 控件的靈活性。有些風格只是一些提示性的,它們在所有平台上的行為可能並不完全相同。
與 Swing 類似,SWT 組件也不是線程安全的,這意味著您必須要關心在應用程序中是哪個線程對 GUI 進行了更新。如果在使用線程時發生了錯誤,就會拋出異常。我認為這比不確定的 Swing 方法要好。有一些工具可以幫助管理線程的問題。
如果所支持的操作系統提供了可訪問性服務,那麼 SWT GUI 通常也就具有很好的可訪問性。當默認信息不夠時,SWT 為程序員提供了一個基本的 API 來指定可訪問性信息。
SWT 提供了一個有限的圖形環境。到目前為止,它對於 Java2D 和 Java3D 的支持還不怎麼好。Eclipse 使用一個名為 Draw2D 的組件提供了另外一種單獨的圖形編輯框架(Graphical Editing Framework,GEF),它可以用來創建一些繪圖應用程序,例如 UML 建模工具。不幸的是,GEF 難以單獨(即在整個 Eclipse 環境之外)使用。
與 AWT 和 Swing 不同,SWT 和 JFace 並不是 Java 技術的標准配置。它們必須單獨進行安裝,這可以當作是 Eclipse 安裝的一部分,也可以當作是單獨的庫進行安裝。Eclipse 小組已經使它的安裝變得非常簡單,並且 SWT 可以與 Eclipse 分開單獨運行。所需要的 Java 檔案文件(JAR)和動態鏈接庫(DLL)以及 UNIX 和 Macintosh 上使用的類似庫可以從 Eclipse Web 站點上單獨下載。JFace 庫需要您下載所有的 Eclipse 文件,並拷貝所需要的 JAR 文件。在下載所需要的文件之後,我們還需要將這些 JAR 文件放到 Java CLASSPATH 中,並將 DLL 文件放到系統 PATH 中。
特性的比較
下表對 AWT、SWT 和 Swing 庫的很多特性進行了比較,這種比較並沒有按照任何特定順序來進行。盡管沒有完全列出所有特性,但是列出了很多最重要的特性。
表 1. SWT 、AWT 和 Swing 特性的比較
結束語
本文對 Eclipse 的 Standard Windows Toolkit with JFace、Java 的 Swing 和 Abstract Windows Toolkit GUI 工具包進行了比較。通過此處提供的比較,您可以確定在自己的新應用程序中應該使用哪個 GUI 工具包。
在大部分情況中,決定都是在 Swing 與結合了 JFace 的 SWT 之間進行的。通常來說,每個工具包都非常完整且功能強大,足以構建功能完善的 GUI,但是 Swing 通常要比單獨使用 SWT(不使用 JFace 時)更好。Swing 具有內嵌於 Java 技術的優點,是完全可移植的,無可爭議地是一種更好的架構。Swing 也具有高級圖形應用程序所需要的優點。SWT 具有可以作為本地應用程序實現的優點,這可以提高性能,並利用基於 SWT 的 GUI 來實現本地兼容性。
如果您只為一種平台來開發系統,那麼 SWT 就具有主機兼容性方面的優點,包括與主機特性的集成,例如在 Windows 上對 ActiveX 控件的使用。