kooyee ‘s blog

          開源軟件, 眾人努力的結(jié)晶, 全人類的共同財富
          posts - 103, comments - 55, trackbacks - 0, articles - 66
             :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

          [SWT] SWT簡介

          Posted on 2007-07-13 22:06 kooyee 閱讀(1250) 評論(0)  編輯  收藏 所屬分類: GUI骨衣
           

          Eclipse In Action - 附錄D. 介紹SWT- -

                                                

          《Eclipse In Action》是一本面向Eclipse初學(xué)者的教程,對Java開發(fā)有興趣的人也可以讀一讀。
          筆者參與了該書的翻譯工作,并同步發(fā)布譯稿,希望各位指正。

          附錄D. 介紹SWT


          翻譯:Addone Squid[天堂魷魚](addone@gmail.com


            本附錄介紹了標(biāo)準(zhǔn)窗口小部件工具包(SWT)并特別介紹了:

          • SWT是什么
          • SWT的體系結(jié)構(gòu)
          • SWT和事件、線程
          • 如何運(yùn)行SWT代碼

            SWT是由IBM開發(fā)的,作為抽象窗口工具包(AWT)和Swing的替代品的一種工具包。IBM的目標(biāo)是創(chuàng)建一種GUI工具包,其觀感和行為都像是系統(tǒng)中通常的窗口小部件,并且性能上也具有相同的速度。在本附錄中,我們會觀察AWT和Swing的行為,并和IBM采取的方法相比較。然后,我們將討論如何使用SWT,指出在使用中比較重要的概念和問題。

          D.1 什么是標(biāo)準(zhǔn)窗口小部件工具包?


            Eclipse技術(shù)概述(http://www.eclipse.org/whitepapers/eclipse-overview.pdf)將SWT描述為一種“與本地窗口系統(tǒng)結(jié)合但使用操作系統(tǒng)無關(guān)的API的窗口小部件集及圖形庫”。在深入分析這種表述之前,讓我們來看看在Java 1.0版本中提供的第一個圖形API:抽象窗口工具包(AWT)。AWT提供了一套API來構(gòu)建如標(biāo)簽、文本框、按鈕、列表和菜單之類的圖形組件,并指派操作系統(tǒng)來提供這些組件的特定實(shí)現(xiàn)。當(dāng)你構(gòu)建一個文本框時,操作系統(tǒng)構(gòu)造它自己的文本框并顯示在程序窗體中--Windows上的Java文本框看起來就像一個Windows文本框,而Macintosh上的Java文本框看起來就像一個Macintosh文本框。
            AWT的問題是Sun僅僅實(shí)現(xiàn)了在Java支持的所有平臺中共有的那些窗口小部件。為了解決這個問題,Sun和Netscape合作引入了Swing,這是創(chuàng)建完全跨平臺的窗口小部件集的一次嘗試。為了達(dá)到這個目標(biāo),他們用Java來編寫所有的東西,而不是指派給操作系統(tǒng)。這種方法讓Java在界面方面變得更有用,但代價是:

          • 這些控件和它們運(yùn)行其上的平臺的外觀并不相符。
          • 相對于本地實(shí)現(xiàn)來說,這些控件的性能要差得多。

            Sun試圖通過為每種操作系統(tǒng)都開發(fā)被稱為“可插入式觀感”的東西來解決第一個問題。 然而,盡管這種方法解決了部分問題,Sun卻無法跟上操作系統(tǒng)的更新。比如,一種Windows的觀感在Windows 95、Windows 98、Windows ME、Windows 2000和Windows XP上看起來都一樣,而本地程序則會依賴于運(yùn)行的是哪個版本,看起來會不一樣。
            Sun已經(jīng)在性能問題上取得了很大進(jìn)展,但一個模擬組件終究永遠(yuǎn)也不可能和本地等價組件具有同樣好的性能。在JVM中總會存在一個翻譯過程,以將模擬組件翻譯為一個本地描繪的指令集。
            在Eclipse的開發(fā)過程中,IBM研發(fā)了針對這個問題的一種新方法,這是Sun的兩種方法的某種混合。SWT是一種通過Java本地接口(JNI)來訪問本地控件的窗口小部件集。只有在特定的操作系統(tǒng)上不存在的少數(shù)幾個控件才會進(jìn)行模擬。這種方法的缺陷是,在Eclipse/SWT部署的每個平臺上,都需要有本地庫。然而好處是,程序的外觀和性能都和本地程序一樣。并且,從Eclipse的2.1版開始,在大多數(shù)桌面操作系統(tǒng)和Pocket PC上都支持SWT。

          D.2 SWT體系結(jié)構(gòu)


            在談了一些關(guān)于SWT是什么的問題后,讓我們用圖形來再看看它。如圖D.1所示,SWT由三個基本組件組成:一個本地庫,負(fù)責(zé)與操作系統(tǒng)通訊;一個顯示類,作為SWT與GUI平臺通訊的接口;一個Shell類,作為程序的頂層窗口,可以容納窗口小部件(Widget)(控件組件的另一種說法)。

            在我們繼續(xù)之前,讓我們來研究一下我們剛剛引入的一些術(shù)語:

          • 顯示(Display)--想象顯示類的最好方式是把它當(dāng)作一位管家。它執(zhí)行所有重要的任務(wù)而使得你不必去管他們。這個類所做的最重要的工作之一是將本地平臺事件和適宜在SWT中使用的那些進(jìn)行互譯。在你開發(fā)自己的程序的時候,你通常不需要對顯示類做些什么,只需在創(chuàng)建其他所有窗口前先創(chuàng)建它。
          • Shell--從根本上說,一個用戶看到的窗口是被操作系統(tǒng)的窗口管理器最終控制的。Shell被用作兩種不同類型的窗體。第一種是你的程序的頂層窗體,你的GUI的其它部分在其上構(gòu)建。在這種情況下,Shell是作為顯示類的子類來創(chuàng)建的。另一種類型是一個窗體是其他窗體的子窗體,比如對話框。這種情況下,該Shell作為其父窗體的那個Shell的子類。
          • 窗口小部件(Widget)--這個術(shù)語意指控件(Control)組件(Composite)。你會發(fā)現(xiàn),在SWT文檔的各處,這三個術(shù)語是交替使用的。簡單說來,一個窗口小部件就是可以放置在其他窗口小部件中的一個GUI對象。
          • 控件(Control)--具有操作系統(tǒng)對應(yīng)物的GUI項。例如,一個按鈕,文本區(qū)域,或者菜單。
          • 組件(Composite)--一個可以擁有子窗口小部件的窗口小部件,比如工具欄和樹。最好的例子是canvas,你可以利用它,在使用不同布局的各種子canvas的輔助下構(gòu)造復(fù)雜的用戶界面。

            SWT體系結(jié)構(gòu)是設(shè)計來模擬平臺程序結(jié)構(gòu)的,所以它對于窗口小部件創(chuàng)建和資源清理有很重要的影響。

          D.2.1 窗口小部件創(chuàng)建

            當(dāng)你在SWT中創(chuàng)建一個控件的時候,你還需要考慮它是如何在底層操作系統(tǒng)中被創(chuàng)建的。每個控件都有一個相似的構(gòu)造函數(shù)來接受兩個參數(shù):第一個指定其父窗口小部件,第二個指定此窗口小部件的樣式。這對于許多操作系統(tǒng)的工作方式來說都是必要的。當(dāng)該SWT對象被創(chuàng)建時,操作系統(tǒng)的對應(yīng)對象也被創(chuàng)建了,而它需要知道自己的父對象是哪個。對于許多窗口小部件的樣式設(shè)置來說也是一樣的。一旦它們被創(chuàng)建了,其樣式就不能修改了。(所謂樣式就是一種有關(guān)窗口小部件外觀的對操作系統(tǒng)的示意。比如,當(dāng)你創(chuàng)建了一個按鈕,樣式就定義了其類型:單選按鈕,普通按鈕,復(fù)選按鈕等等。)

          D.2.2 資源清理

            通常,當(dāng)你使用Swing(或AWT)的時候,你只需創(chuàng)建你的窗口小部件、圖像、字體等等而無需關(guān)注它們的清理,因為你知道當(dāng)垃圾回收器運(yùn)行時JVM會處理它們的。然而,當(dāng)你使用SWT時,你必須多加注意你對操作系統(tǒng)GUI資源的使用,因為只有有限的資源可用。
            當(dāng)你在SWT中創(chuàng)建了一個基于資源的對象(例如顏色、鼠標(biāo)指針、字體或圖像)時,你必須清理它。如果你不清理那些你不再需要的東西,就會發(fā)生資源泄漏,而你會在這種狀況下結(jié)束:不管是你的還是操作系統(tǒng)中運(yùn)行著的其他程序,都將無法再創(chuàng)建任何對象。
            以下代碼片段分配了一個顏色(Color)資源然后清理了它:

            
          Color blue = new Color (display, 00255);
            blue.dispose();

          D.3 SWT與事件


            你在所有SWT程序中都會看到的最常用的代碼段如下:

            while (!shell.isDisposed ())
            {
              if (!display.readAndDispatch ())
              display.sleep ();
            }

            這通常被稱為信息泵事件調(diào)度循環(huán)。它的工作是當(dāng)頂層窗口打開時接收來自操作系統(tǒng)的事件(比如,用戶在移動鼠標(biāo)),把它們調(diào)度到合適的SWT窗口小部件中,然后休眠直至有其他事件需要處理。在你的程序中,你需要至少有一個這樣的東西,否則你的程序?qū)o法接收操作系統(tǒng)的任何事件,這會讓用戶不大高興。
            這個方法和AWT和Swing所使用的很不一樣,后者為開發(fā)者隱藏了這種機(jī)制。這在SWT中沒有隱藏,因為如果你編寫SWT代碼并作為Eclipse插件的一部分,你根本不需要一個信息泵--你默認(rèn)使用了由工作臺提供的那個。
            剩余的事件處理機(jī)制和AWT和Swing所用的差不多。大量的基本事件類型以及它們各自的偵聽器(Listener)、適配器(Adapter)都在包org.eclipse.swt.events中定義。參閱在線文檔可以獲得完整列表。以下代碼段演示了如何創(chuàng)建一個事件偵聽器以及如何將其加入到一個對象中:

            Button button = new Button(display, SWT.PUSH);
            button.addSelectionListener(new SelectListener()
            {
              public void widgetDefaultSelected( SelectionEvent e ) {}
              public void widgetSelected( SelectedEvent e )
              {
                System.out.println("Button Pressed");
              }
            });

            不熟悉事件處理的人不必?fù)?dān)心,這很簡單。如前所述,一個事件關(guān)聯(lián)著一個諸如用戶移動鼠標(biāo)或者窗體被最大化之類的動作。對于每種可以接收的事件的類型,都有一個稱為偵聽器的接口。一個偵聽器就是一個類,它知道如何處理特定事件并且還會做些有用的事情。要想創(chuàng)建一個偵聽器類,你需要創(chuàng)建一個類來實(shí)現(xiàn)那個與你要處理的事件相符的特定的偵聽器接口。
            觀察前面的代碼段可知,我們關(guān)注的是SelectionEvent,它在點(diǎn)擊按鈕時發(fā)出。如果你在Javadoc中查看該事件,你會看到正確的偵聽器是SelectionListener。為了將一個偵聽器添加到一個窗口小部件類,你調(diào)用它的一個addXXXListener()方法,正如前面代碼中用到的addSelectionListener()。

          提示
          與其花時間重復(fù)Javadoc中所說的東西,我們建議你查看在線幫助。在那里你可以找到一份關(guān)于可用事件類型的完整清單,并且還包括了它們以及處理(或生成)那些事件的窗口小部件的描述。要查看該幫助,選擇[幫助]->[幫助內(nèi)容]->[平臺插件開發(fā)者指南]->[程序員指南]->[標(biāo)準(zhǔn)窗口小部件工具箱]->[窗口小部件]->[事件]。

          D.4 SWT與線程


            當(dāng)你使用SWT創(chuàng)建一個SWT程序時,要考慮的一個重要因素就是所有的窗口小部件是如何與線程交互的。如果你熟悉Swing和AWT編程,那么以下內(nèi)容會比較熟悉,不過某些重要的差異還是需要注意的。
            一個被稱為用戶界面線程的單一的重要線程負(fù)責(zé)處理事件,調(diào)度它們到合適的窗口小部件,以及進(jìn)行窗體描繪。沒有了它,你的程序?qū)o法做任何事情。你可能認(rèn)為我們過去說過一些這方面的內(nèi)容,我們的確曾經(jīng)說過。
            在AWT和Swing中,用戶界面線程或事件處理線程對開發(fā)者是隱藏的。而在SWT中,創(chuàng)建消息泵的線程就成了用戶界面線程。這個設(shè)計決定使得要將SWT插件插入Eclipse中變得可能。與Sun的方法背離的另一點(diǎn)是,SWT的設(shè)計允許擁有多于一個的事件調(diào)度線程。(這個功能極少用到,我們提到它只是為了完整起見。)
            主線程就是用戶界面線程,所以你不該執(zhí)行任何復(fù)雜的或耗時的任務(wù)(如數(shù)據(jù)庫訪問)或者其他會阻塞線程的任務(wù)。相反的,你應(yīng)該轉(zhuǎn)到其他線程去執(zhí)行那些操作。不這么做的話,將會嚴(yán)重影響你的用戶界面的響應(yīng)能力并且會給用戶帶來不便,這永遠(yuǎn)不是件好事。與此相關(guān)的事實(shí)就是,唯一允許調(diào)用SWT窗口小部件而不會引發(fā)SWTException異常的線程就是用戶界面線程。
            你也許想知道在你轉(zhuǎn)到的線程完成之后如何更新用戶界面。要做到這樣,你要使用兩個輔助方法,它們是顯示類(Display)的一部分:asyncExec()syncExec()。(Swing用戶注意:這些方法和Swing工具包類中的invokeLater()invokeAndWait()方法同義。并且,是的,如果你覺得Sun的方法的命名更為清晰,我們贊同。)這些方法按以下方式工作:

          • asyncExec(Runnable)--當(dāng)你需要更新用戶界面但并不關(guān)心具體何時更新時使用。記住,使用此方法意味著后臺線程和用戶界面間的處理不存在任何可保證的關(guān)聯(lián)。
          • syncExec(Runnable)--當(dāng)你的背景線程需要先進(jìn)行用戶界面更新才能繼續(xù)處理時使用。注意,在用戶界面更新進(jìn)行之前,你的背景線程會被阻塞。

            這些方法都采取了實(shí)現(xiàn)Runnable接口的類。以下代碼顯示了你一般會如何使用這些方法:

            Display.getDefault().asyncExec(new Runnable()
            {
              public void run()
              {
                button.setText(new Date().toString());
              }
            });

            asyncExec()方法是顯示類的一部分,所以你首先需要取得顯示類的當(dāng)前實(shí)例,這樣做就避免了在你的整個程序中傳遞顯示類的引用。你將一個實(shí)現(xiàn)了Runnable接口的類傳遞到asyncExec()方法。通常你創(chuàng)建一個匿名類來進(jìn)行更新,正如前面的例子所示。

          D.5 構(gòu)建和運(yùn)行SWT程序


            你可能想要開始編程了,或者至少也要看一些正確的SWT代碼--很快我們就要這么做。然而,在那之前,讓我們來告訴你如何構(gòu)建和運(yùn)行代碼。
            這本書是有關(guān)Eclipse的使用的,所以我們首先關(guān)注配置Eclipse以使你能進(jìn)行SWT開發(fā)。然后我們來看看需要什么來運(yùn)行代碼。最后,我們會解釋從命令行運(yùn)行你的SWT程序時的步驟。
            要配置Eclipse,請按如下步驟進(jìn)行:

          1. 在[工作空間]視圖中選擇你的項目,選擇右鍵菜單中的[屬性]。
          2. 選擇[Java構(gòu)建路徑],然后點(diǎn)擊[[庫]]標(biāo)簽頁。
          3. 選擇[添加外部Jar]。注意,如果你很可能要經(jīng)常使用SWT,你可能會想要創(chuàng)建一個變量。
          4. 定位到適合你的平臺的swt.jar文件,如圖D.2所示(<eclipse-root>就是Eclipse所在的目錄):
            • Linux GTK --<eclipse-root>/plugins/org.eclipse.swt.gtk_2.1.0/os/linux/x86
            • Linux Motif --<eclipse-root>/plugins/org.eclipse.swt.motif_2.1.0/os/linux/x86
            • Solaris Motif --<eclipse-root>/plugins/org.eclipse.swt.motif_2.1.0/os/solaris/sparc
            • AIX Motif --<eclipse-root>/plugins/org.eclipse.swt.motif_2.1.0/os/aix/ppc
            • HPUX Motif --<eclipse-root>/plugins/org.eclipse.swt.motif_2.1.0/os/hpux/PA_RISC
            • Photon QNX --<eclipse-root>/plugins/org.eclipse.swt.photon_2.1.0/os/qnx/x86
            • Mac OSX --<eclipse-root>/plugins/org.eclipse.swt.carbon_2.1.0/os/macosx/ppc
          5. 點(diǎn)擊[確定]。



          注意
          對于某些平臺,比如GTK,需要不只一個的JAR來運(yùn)行SWT(GTK使用文件swt.jar和swt-pi.jar)。在這種情況下,你必須添加所有需要的JAR到classpath中。要這樣做,請對每個JAR文件重復(fù)以上步驟。所有的JAR文件都定義在同一個目錄(文件夾)中。

            要運(yùn)行你的代碼,你需要按以下步驟進(jìn)行:

          1. 在[工作空間]視圖中,選擇你要運(yùn)行的包含有main的那個類。
          2. 選擇[運(yùn)行]->[運(yùn)行...]。
          3. 在[運(yùn)行]對話框中,選擇[Java Application]并點(diǎn)擊[新建]。
          4. 選擇[自變量]標(biāo)簽頁,并在[VM自變量]文本框中點(diǎn)擊鼠標(biāo)。
          5. 輸入-Djava.library.path=<path>,其中<path>依據(jù)你的操作系統(tǒng)而定,是如下之一(如圖D.3所示):
            • Win32 --<eclipse-root>\plugins\org.eclipse.swt.win32_2.1.0\os\win32\x86
            • Linux GTK --<eclipse-root>/plugins/org.eclipse.swt.gtk_2.1.0/os/linux/x86
            • Linux Motif --<eclipse-root>/plugins/org.eclipse.swt.motif_2.1.0/os/linux/x86
            • Solaris Motif --<eclipse-root>/plugins/org.eclipse.swt.motif_2.1.0/os/solaris/sparc
            • AIX Motif --<eclipse-root>/plugins/org.eclipse.swt.motif_2.1.0/os/aix/ppc
            • HPUX Motif --<eclipse-root>/plugins/org.eclipse.swt.motif_2.1.0/os/hpux/PA_RISC
            • Photon QNX --<eclipse-root>/plugins/org.eclipse.swt.photon_2.1.0/os/qnx/x86
            • Mac OSX --<eclipse-root>/plugins/org.eclipse.swt.carbon_2.1.0/os/macosx/ppc
          6. 點(diǎn)擊[應(yīng)用]然后點(diǎn)擊[調(diào)試]。



            你的程序現(xiàn)在運(yùn)行了。記得中止示例。要這么做,你可以點(diǎn)擊[控制臺]視圖的小方塊。
            從命令行運(yùn)行你的代碼也差不多:

          1. 確保適合你的平臺的JAR文件在classpath中。
          2. 調(diào)用java并帶上-Djava.library.path參數(shù)(如前面的步驟所述)以及你的程序名。

          D.6 使用SWT


            我們已經(jīng)講述了SWT的概念以及如何設(shè)置Eclipse以構(gòu)建及運(yùn)行示例?,F(xiàn)在是看看簡單的SWT示例的時候了。
            我們會帶領(lǐng)你一起瀏覽組成示例的各個類,而不是將這些代碼一下子灌給你。如果你想用Eclipse來照做,確認(rèn)Eclipse已經(jīng)按照D.5節(jié)描述的步驟設(shè)置過了。然后,創(chuàng)建兩個Java類(文件->新建->類):BasicFrameworkMainApp。確認(rèn)你建有包org.eclipseguide.swt,并是在其中創(chuàng)建它們的。

          D.6.1 BasicFramework類

            讓我們首先來看看BasicFramework。第一個部分定義了該類所在的包,然后導(dǎo)入了示例所需的類:

            package org.eclipseguide.swt;
            
            import org.eclipse.swt.SWT;
            import org.eclipse.swt.events.*;
            import org.eclipse.swt.widgets.*;

            BasicFramework定義為抽象類以確保該類的所有子類都提供dispose()和displayHelpAboutDialog()方法的實(shí)現(xiàn)。在這個基礎(chǔ)框架中,這些方法作為提醒來使用,以便你記得要清理資源以及要提供你自己的[關(guān)于]對話框。
            代碼的其它部分是你很快就要用到的窗口小部件的聲明:

            public abstract class BasicFramework
            {
              protected Display display;
              protected Shell shell;
              protected Menu menuBar, fileSubMenu, helpSubMenu;
              protected MenuItem fileSubMenuHeader;
              protected MenuItem fileExit, helpSubMenuHeader;
              protected MenuItem helpAbout;
              public abstract void dispose();
              public abstract void displayHelpAboutDialog();

            下面的內(nèi)部類實(shí)現(xiàn)了SelectionListener以便處理選擇事件。它會被連接到[退出]菜單項(很快就定義)。主要做的是關(guān)閉窗體,也就是中止消息泵,然后調(diào)用dispose()以確保兩個動作銜接在一起:

              class FileExitListener implements SelectionListener
              {
                public void widgetSelected(SelectionEvent event)
                {
                  shell.close();
                  dispose();
                }
                public void widgetDefaultSelected(SelectionEvent event)
                {
                  shell.close(); dispose();
                }
              }

            類似的,下一個內(nèi)部類處理[幫助]菜單的[關(guān)于...]按鈕的選擇事件:

              class HelpAboutListener implements SelectionListener
              {
                public void widgetSelected(SelectionEvent event)
                {
                  displayHelpAboutDialog();       }
                public void widgetDefaultSelected(SelectionEvent event)
                {
                  displayHelpAboutDialog();
                }
              }

          注意
          在這兩個偵聽器類中,widgetSelectedwidgetDefaultSelected這兩個方法處理的事件類型不同。widgetSelected處理用戶用鼠標(biāo)選擇窗口小部件的事件,例如,點(diǎn)擊一個按鈕。widgetDefaultSelected處理當(dāng)按鈕具有焦點(diǎn)時,用戶按[空格]鍵或[回車]鍵所產(chǎn)生的事件。

            下面你要開始建立SWT體系結(jié)構(gòu)的層次結(jié)構(gòu):

              public BasicFramework(String windowTitle)
              {
                display = new Display();
                shell = new Shell(display);
                shell.setText(windowTitle);

            記住,Display窗口小部件是你的程序與操作系統(tǒng)對話的中轉(zhuǎn)對象。隨即創(chuàng)建Shell并傳遞display給它作為其父部件。該Shell就作為你的頂層窗體,其他所有東西都在其上建立。最后,Shell有一系列的輔助方法:setMinimized()setMaximized()、等等。在這里,你設(shè)置了窗口標(biāo)題。
            在SWT中創(chuàng)建一個全功能菜單欄是一個復(fù)雜的過程。設(shè)計者不是只提供一些簡單的類諸如菜單欄、菜單、菜單項、子菜單,而是采用了兩個類,并依據(jù)所傳遞的樣式來充當(dāng)不同的角色:

                menuBar = new Menu(shell, SWT.BAR);
                fileSubMenuHeader = new MenuItem(menuBar, SWT.CASCADE);
                fileSubMenuHeader.setText("文件(&F)");

            第一步是創(chuàng)建菜單欄以供其他所有菜單掛載。你可以通過傳遞樣式參數(shù)SWT.BAR來實(shí)現(xiàn)。然后要創(chuàng)建一個掛載點(diǎn),基本上就是個供菜單掛載的占位符。最后是設(shè)置該占位符顯示在菜單欄上的文字。字母“F”旁的“&”號表明將“F”作為助記符(訪問該菜單的一個鍵盤快捷鍵)。使用時,可以按[Alt]鍵激活菜單然后按[F]鍵來選擇該菜單。然后就可以使用光標(biāo)鍵來瀏覽菜單了。
            菜單創(chuàng)建工作的下一部分要求你創(chuàng)建在點(diǎn)擊文字[文件]時顯示的菜單。通過指定DROP_DOWN樣式來把它創(chuàng)建為下拉菜單。(另一個可用選項是POP_UP,這將會建立彈出菜單,在右鍵點(diǎn)擊選擇或其它方式中很有用。)然后,把菜單連接到占位符:

                fileSubMenu = new Menu(shell, SWT.DROP_DOWN);
                fileSubMenuHeader.setMenu(fileSubMenu);

            在創(chuàng)建菜單的最后階段里,你要創(chuàng)建菜單的項目。就像過去一樣,你需要指定菜單項的樣式,不過你有更多的選擇--除了創(chuàng)建一個普通按鈕式菜單項,你還可以創(chuàng)建復(fù)選項目、單選項目,或者是一個分隔條(用來給你的菜單分段):

                fileExit = new MenuItem(fileSubMenu, SWT.PUSH);
                fileExit.setText("退出(&X)");

            這些和[文件]菜單的寫法一樣:

                helpSubMenuHeader = new MenuItem(menuBar, SWT.CASCADE);
                helpSubMenuHeader.setText("幫助(&H)");
                helpSubMenu = new Menu(shell, SWT.DROP_DOWN);
                helpSubMenuHeader.setMenu(helpSubMenu);
                helpAbout = new MenuItem(helpSubMenu, SWT.PUSH);
                helpAbout.setText("關(guān)于(&A)");

            下面就要把偵聽器類連接到菜單項了。從這里開始,當(dāng)你點(diǎn)擊[文件]菜單的[退出]項或者[幫助]菜單的[關(guān)于]項時,這些事件就會被處理:

                fileExit.addSelectionListener(new FileExitListener());
                helpAbout.addSelectionListener(new HelpAboutListener());

            下面一行將菜單欄連接到頂層的shell

                shell.setMenuBar(menuBar);
              }

            以下是BasicFramework類的最后一段代碼。這段很重要,它不僅使頂層窗體(Shell)顯示在屏幕上,還創(chuàng)建了消息泵--這個示例的核心。當(dāng)你開發(fā)獨(dú)立運(yùn)行的程序時,記住,沒有了這一部分,你的程序所能做的將非常有限:

              public void mainLoop(int hSize, int vSize)
              {
                shell.setSize(hSize, vSize);
                shell.setVisible(true);
                shell.open();
                while (!shell.isDisposed())
                {
                  if (!display.readAndDispatch())
                    display.sleep();
                }
              }
            }

          D.6.2 MainApp類

            現(xiàn)在,我們來看看MainApp類,它擴(kuò)展了BasicFramework類并做了些很有用的工作。像以往一樣,你要將這個類聲明為org.eclipseguide.swt包的成員,然后導(dǎo)入示例需要的所有類:

            package org.eclipseguide.swt;

            import java.util.*;
            import org.eclipse.swt.SWT;
            import org.eclipse.swt.events.*;
            import org.eclipse.swt.layout.FillLayout;
            import org.eclipse.swt.widgets.*;

            要設(shè)置一個計時器,你要使用java.util.Timer類而不是使用一個線程。如果你沒用過Java 1.3及以上版本(1.3版是Eclipse運(yùn)行的最低要求),你可能沒用過這個類。這是一個簡單便捷的類,它提供了一個專用的計時器線程:

            public class MainApp extends BasicFramework
            {
              Timer timer;
              Button button;

            這個按鈕放置在程序的主窗體中并顯示時間。當(dāng)點(diǎn)擊按鈕時,它會將時間打印到控制臺。
            下面的內(nèi)部類擴(kuò)展了抽象類TimerTask?;旧?,一個計時器任務(wù)就是一個傳遞到計時器的Runnable,它會以指定間隔執(zhí)行。在run方法中,你要將一個匿名的runnable增加到事件隊列里,以便用當(dāng)前時間來更新按鈕文本。由于并不關(guān)心用戶界面線程什么時候會處理它,所以要用asyncExec方法來加上它:

              private class ClockUpdateTask extends TimerTask
              {
                public void run()
                {
                  Display.getDefault().asyncExec(new Runnable()
                  {
                    public void run()
                    {
                      button.setText(new Date().toString());
                    }
                  });
                }
              }

            這是MainApp類的構(gòu)造函數(shù)。在這里要調(diào)用其父類BasicFramework的構(gòu)造函數(shù)并傳遞標(biāo)題文字:

              public MainApp()
              {
                super("SWT Example Framework");

            每個窗體都可以有一個布局管理器以控制窗口小部件的位置和大?。?br>
                shell.setLayout(new FillLayout(SWT.VERTICAL));

            有5種已定義好的布局:填充布局(FillLayout)堆布局(StackLayout)網(wǎng)格布局(GridLayout)表單布局(FormLayout)以及行布局(RowLayout)。同時還有一個自定義布局(CustomLayout)供你更好的控制窗口小部件的位置。

          提示
          如果要獲得更多關(guān)于布局的信息,我們建議你閱讀文章“了解SWT中的布局”(Eclipse站點(diǎn)的文章區(qū)載有此文:http://www.eclipse.org/articles/)。

            代碼的下一部分創(chuàng)建了一個普通按鈕并將它加到了shell窗口上。你目前正在使用填充布局,所以無法設(shè)置按鈕大小。它只會簡單的擴(kuò)展到全部可用的空間中:

                button = new Button(shell, SWT.PUSH);

            以下代碼展示了將一個偵聽器連接到一個窗口小部件的另一途徑--將其與一個匿名類連接。對于短小的類來說,應(yīng)該優(yōu)先使用匿名類。 除外,建議使用完全類(作為內(nèi)部類或者友好包):

                button.addSelectionListener(new SelectionListener()
                {
                  public void widgetSelected(SelectionEvent event)
                  {
                    System.out.println( "Button clicked - time is: " + button.getText());
                  }
                  public void widgetDefaultSelected(SelectionEvent event)
                  {
                    System.out.println( "Button pressed with default key - time is: " + button.getText());
                  }
                });

            下面就要創(chuàng)建定時器并安排你的ClockUpdate任務(wù)了,它將在0毫秒的延遲后啟動,之后每隔1000毫秒(1秒)調(diào)用一次:

                timer = new Timer();
                timer.scheduleAtFixedRate(new ClockUpdateTask(), 0, 1000);

            你不需要告訴計時器開始工作--程序一創(chuàng)建,它就立即運(yùn)行了。
            以下代碼調(diào)用了BasicFramework類的mainloop,在那里會進(jìn)入事件循環(huán)直至shell被關(guān)閉。那時,就將會退出程序所運(yùn)行的JVM:

                this.mainLoop(300, 200);
                System.exit(0);
              }

            這些代碼創(chuàng)建MainApp類并開始整個程序的運(yùn)行:

              public static void main(String[] args)
              {
                new MainApp();
              }

            現(xiàn)在你就要實(shí)現(xiàn)父類的抽象方法了,然而,這些代碼沒有用它們來做任何有用的事情。這種設(shè)計是為了讓你能把所有聲明過的資源都放入dispose方法中,以便輕松定位所有需要清理的資源:

              public void dispose()
              {
                System.out.println("Disposing of Resources");
              }
              public void displayHelpAboutDialog()
              {
                System.out.println("Display Help About Dialog");
              }
            }

            我們同樣想象到,你會把創(chuàng)建你的[關(guān)于]窗體所需的一切東西放進(jìn)displayHelpAboutDialog()方法中。

          主站蜘蛛池模板: 禄劝| 东乌| 将乐县| 元朗区| 宣武区| 南漳县| 柯坪县| 徐水县| 开封市| 余庆县| 云阳县| 蓝田县| 乌鲁木齐市| 太白县| 华坪县| 珲春市| 杭州市| 灌南县| 大兴区| 苏尼特右旗| 横峰县| 金华市| 南靖县| 中卫市| 蓬安县| 桐城市| 墨竹工卡县| 德庆县| 新野县| 克拉玛依市| 库尔勒市| 仁怀市| 辉南县| 田林县| 荃湾区| 淮南市| 临邑县| 镇康县| 柳河县| 正镶白旗| 华亭县|