国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書(shū)等14項(xiàng)超值服

開(kāi)通VIP
SWT 全接觸



文檔選項(xiàng)

打印本頁(yè)

將此頁(yè)作為電子郵件發(fā)送


級(jí)別: 初級(jí)

薛 笛 (jxuedi@gmail.com), 研究生,黑龍江大學(xué)信息技術(shù)研究所

2006 年 9 月 28 日

Java 世界的人似乎一直都對(duì) Java 的桌面應(yīng)用程序十分不滿(mǎn),從 AWT 到 SWING,從默認(rèn)的 Theme到第三方的產(chǎn)品,不是太難看(AWT)就是在某些平臺(tái)有 BUG(SWING,Quaqua--一個(gè)Windows平臺(tái)下的仿Mac的主題包),再不就是對(duì)中文支持不好(某些第三方 LookAndFeel)。于是,如果想要獲得和本機(jī)平臺(tái)一致的用戶(hù)界面和比較穩(wěn)定的性能,SWT就成了一個(gè)不可忽視的選擇。SWT 是一個(gè)獨(dú)立于平臺(tái)的,可以脫離 Eclipse 框架單獨(dú)使用的圖形組件,用JNI技術(shù)提供與本機(jī)系統(tǒng)同樣的用戶(hù)界面組件的觀(guān)感,較好的運(yùn)行效率,穩(wěn)定的平臺(tái)表現(xiàn)。

當(dāng)然,雖然這個(gè)專(zhuān)題名叫"全接觸",但畢竟不可能面面俱到,在一篇文章中兼收并蓄SWT的全部?jī)?nèi)容也不現(xiàn)實(shí)。但不管怎么說(shuō),我都將盡力展示SWT的使用細(xì)節(jié),希望能為那些對(duì)SWT感興趣的人提供一些幫助。

1.SWT簡(jiǎn)介

SWT-"Standard Widget Toolkit",它是一個(gè)Java平臺(tái)下開(kāi)放源碼的Native GUI組件庫(kù),也是Eclipse平臺(tái)的UI組件之一。從功能上來(lái)說(shuō),SWT與AWT/SWING是基本等價(jià)的。SWT以方便有效的方式提供了便攜式的(即Write Once,Run Away)帶有本地操作系統(tǒng)觀(guān)感的UI組件:



由于widget系統(tǒng)的固有復(fù)雜性以及平臺(tái)之間微妙的差異,即使在理想情況下,能夠達(dá)到工業(yè)標(biāo)準(zhǔn)的跨平臺(tái)的widget類(lèi)庫(kù)也是很難編寫(xiě)和維護(hù)的。最早的AWT組件現(xiàn)在被認(rèn)為是樣貌丑陋的,而且存在很多問(wèn)題;SWING組件雖然也是缺點(diǎn)多多,但是隨著JDK版本的不斷升高,它仍在不斷進(jìn)行著改進(jìn)。我認(rèn)為,SWT在功能上與AWT/SWING不相伯仲,但是組件更為豐富,平臺(tái)表現(xiàn)穩(wěn)定,BUG也相對(duì)較少。如果你的應(yīng)用程序真的需要在多個(gè)平臺(tái)上運(yùn)行,需要更為美觀(guān)的界面,又不那么依賴(lài)于其他基于AWT/SWING的圖形庫(kù),那么SWT或許是一個(gè)比AWT/SWING更好的選擇。





回頁(yè)首


2. SWT起步

2.1 SWT的HelloWorld

一如介紹其他程序的起始,我們都需要來(lái)一個(gè)HelloWorld來(lái)幫助我們?nèi)腴T(mén),SWT的HelloWorld如下:


import org.eclipse.swt.widgets.*;                                    public class HelloWorld                                    {                                    public static void main(String[] args)                                    {                                    Display display = new Display();                                    Shell shell = new Shell(display);                                    shell.setText("Hello World");                                    shell.setSize(200, 100);                                    shell.open();                                    while (!shell.isDisposed())                                    {                                    if (!display.readAndDispatch())                                    display.sleep ();                                    }                                    display.dispose ();                                    }                                    }                                    

運(yùn)行這個(gè)程序就會(huì)得到如下結(jié)果:



下面我講逐一介紹這個(gè)程序所包含的內(nèi)容。

  • Display
    這是一個(gè)頂層容器組件,類(lèi)似于Container或Component的功能,它主要負(fù)責(zé)與底層的窗口系統(tǒng)之間的連接。在具體含義上,它代表"屏幕"。
    一個(gè)Display可以包含多個(gè)Shell(也是容器組件,下面會(huì)介紹到)。
    通常情況下,一個(gè)應(yīng)用程序只含一個(gè)Display,即Display通常是一個(gè)單例組件(Singleton)。
  • Shell
    它表示位于"屏幕"上面的"窗口",是Composite組件和Control組件構(gòu)成的組件樹(shù)的根。
    在我們的HelloWorld程序中,我們可以設(shè)置標(biāo)題(setText()),設(shè)置大?。╯etSize()),然后通過(guò)open()方法來(lái)顯示這個(gè)窗口。怎么樣,感覺(jué)很像JFrame吧?其實(shí)功能上差不多。
  • Composite
    可以包含其它Composite和Control的容器
  • Control
    這是一個(gè)重量級(jí)(HeavyWeight)系統(tǒng)對(duì)象。像按鈕(Button),標(biāo)簽(Label),表格,工具欄和樹(shù)形結(jié)構(gòu)這些組件都是Control的子類(lèi),Conposite和Shell也不例外。

2.1.1 消息循環(huán)

我們可以看到,上面的代碼中有這樣的語(yǔ)句:


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

如果你像我一樣是由Java語(yǔ)言起步的,那么你會(huì)對(duì)這個(gè)消息循環(huán)的代碼感到比較陌生,畢竟在SWING中我們主要利用事件驅(qū)動(dòng)模型而不這樣利用類(lèi)似于Windows程序設(shè)計(jì)中的消息循環(huán)的方法來(lái)處理事件。但是這段代碼意義還算簡(jiǎn)單明了,就是反復(fù)的讀取和分派(dispatch)事件,并在沒(méi)有事件的時(shí)候把控制權(quán)還給CPU。

2.1.2 資源的釋放

最后一條語(yǔ)句是display.dispose ();,這告訴我們操作系統(tǒng)的資源是由程序員顯示釋放的。資源的釋放遵循以下兩條規(guī)則:

1. 如果你創(chuàng)建了某個(gè)資源,那么你就有責(zé)任釋放它。

2. 釋放父組件資源的同時(shí)也釋放了其子組件的資源。

2.1.3 標(biāo)準(zhǔn)構(gòu)造函數(shù)

窗口組件被創(chuàng)建的時(shí)候必須伴隨一個(gè)他的上層組件,例如,我要建立一個(gè)按鈕就可以采用如下方法:Button button = new Button(shell, SWT.PUSH);

其中,Button的父組件Shell是必不可少的,這樣就限定了我們生成組件的順序。

第二個(gè)參數(shù)被稱(chēng)為"Style Bit",表示了這個(gè)組件的顯示特性,每種特性占一位,如下例所示:


Text test=new Text(group, SWT.SINGLE|SWT.BORDER);                                    

這條代碼生成了一個(gè)單一的,有邊框的文本框。這顯然又與習(xí)慣了JavaBeans模型,總是用setXXX()來(lái)設(shè)置屬性的我們不太適應(yīng)--畢竟是IBM的東西啊,秉承了其產(chǎn)品不易上手的傳統(tǒng)。

2.1.4 錯(cuò)誤與異常



SWTError指的是不能修復(fù)的錯(cuò)誤,以及一些操作系統(tǒng)錯(cuò)誤。

SWTException指的是一些可恢復(fù)的錯(cuò)誤以及無(wú)效的線(xiàn)程訪(fǎng)問(wèn)之類(lèi)的錯(cuò)誤。

IllegalArgumentException指可修復(fù)的錯(cuò)誤或參數(shù)為null之類(lèi)的錯(cuò)誤。

2.1.5 Item

Item類(lèi)是一個(gè)輕量級(jí)的系統(tǒng)對(duì)象,總是作為基本的單位元素與其他一些類(lèi)配合使用。比如Tree中的元素即為T(mén)reeItem,Table的單位元素則是TableItem,而MenuItem就是Menu的基本單位元素了。

2.1.6 SWT的類(lèi)階層體系結(jié)構(gòu)



最后讓我們來(lái)整體認(rèn)識(shí)一下整個(gè)SWT窗口組件的層次結(jié)構(gòu),如下所示:以上的部分給我們以整體的認(rèn)識(shí),即一個(gè)SWT引用程序應(yīng)該怎么創(chuàng)建,其基本的運(yùn)行規(guī)則和相關(guān)類(lèi)的體系結(jié)構(gòu)。我想我就不用再對(duì)每一個(gè)控件的API或使用方面費(fèi)唇舌了,熟悉這些東西是體力勞動(dòng),而網(wǎng)上有很多例子可供參考。下面一節(jié)我將詳細(xì)介紹有關(guān)SWT布局的相關(guān)知識(shí)。

2.2 SWT的布局管理

相信對(duì)于組件的布局(Layout)大家都不會(huì)太陌生,它的存在就是提供給我們一種可以在組件位置移動(dòng)或更改大小時(shí)重新繪制組件的機(jī)制。設(shè)置組件的布局我們可以采用Composite.setLayout()方法來(lái)實(shí)現(xiàn)。

每種布局都有其相應(yīng)的數(shù)據(jù)(Layout Data),可以通過(guò)Control.setLayoutData()方法來(lái)進(jìn)行關(guān)聯(lián)。以下是一些布局類(lèi)及其顯示效果:

  • FillLayout:讓所有子組件等大小的"填滿(mǎn)"整個(gè)面板空間。
    FillLayout是最簡(jiǎn)單的一個(gè)布局類(lèi),它將所有窗口組件放置到一行或一列中,并強(qiáng)制他們的大小也相等。FillLayout不能外覆(wrap),也不能定制邊框和距離。很顯然這樣的限制讓這個(gè)布局類(lèi)最適合作類(lèi)似于計(jì)算器面板的布局,或者為T(mén)askbar和Toolbar上面的按鈕作布局使用。
  • RowLayout:類(lèi)似于AWT中的FlowLayout,讓所有組件按行排列,一行排不下就放到下一行。
    RowLayout比FillLayout用得更廣泛一些,原因很簡(jiǎn)單,就是RowLayout支持FillLayout所部支持的功能,例如能夠外覆,能夠修改邊框和間距等等。另外,每一個(gè)位于RowLayout中的窗口組件都可以通過(guò)設(shè)定一個(gè)RowData類(lèi)來(lái)指定其在RowLayout中的寬度和高度。
  • GridLayout: GridLayout是3個(gè)標(biāo)準(zhǔn)布局類(lèi)中最有用的,但同時(shí)也是最復(fù)雜的--沒(méi)辦法,強(qiáng)大的功能必定伴隨著一定程度的復(fù)雜性。通過(guò)GridLayout,一個(gè)Composite的子窗口組件被放置在一個(gè)網(wǎng)格(Grid)之中。GridLayout有很多配置字段,并且和RowLayout一樣,每一個(gè)布局于其中的窗口組件都可以有一個(gè)與之相關(guān)聯(lián)的布局?jǐn)?shù)據(jù)類(lèi),稱(chēng)為GridData。GridLayout的強(qiáng)大功能是通過(guò)對(duì)于每一個(gè)窗口組件的GridData的靈活控制來(lái)實(shí)現(xiàn)的。
    鑒于GridLayout的復(fù)雜性(原本我就懷疑它根本就不是為手工書(shū)寫(xiě)代碼而設(shè)計(jì)的),我并不建議各位直接手動(dòng)書(shū)寫(xiě)GridData,最好借助可視化的工具(如VI)來(lái)幫助我們完成用GridLayout進(jìn)行的界面設(shè)計(jì)。這樣我們只需要書(shū)寫(xiě)少量控制代碼,就可以獲得復(fù)雜的界面布局了。
  • FormLayout:如圖所示
  • StackLayout:幾乎完全等同于CardLayout的功能。

在SWT中,位置和大小的變化并非自動(dòng)發(fā)生的。應(yīng)用程序既可以在Composite子類(lèi)的構(gòu)造函數(shù)中指定初始位置和大小,也可以在一個(gè)改變窗口大小的監(jiān)聽(tīng)器中用布局類(lèi)來(lái)定位和改變Composite子類(lèi)的大小。

下面的一幅圖包含了我們將要討論的有關(guān)布局的大部分細(xì)節(jié)。一個(gè)Composite類(lèi)的可顯示區(qū)域分為三個(gè)部分,分別是Location,clientArea和trim。Composite的大小就是clientArea和trim的區(qū)域之和。一個(gè)布局類(lèi)(Layout)的主要功能就是管理Composite子組件的大小和位置。通過(guò)布局類(lèi),我們可以管理子組件之間的距離-即間距(Spaceing),子組件與布局邊緣之間的距離-即邊距(margin)。布局的大小同時(shí)也是Composite的clientArea的大小。



至此,關(guān)于SWT的基礎(chǔ)部分就告一段落,希望能夠給大家以一個(gè)對(duì)于SWT的總體認(rèn)識(shí)。下面的部分將主要介紹SWT的弱項(xiàng)-繪圖。JGraph的一個(gè)作者就表達(dá)了對(duì)SWT/JFace/Draw2D的不滿(mǎn),認(rèn)為SWT在執(zhí)行效率上并沒(méi)有什么改善,而且缺乏一些有用的API實(shí)現(xiàn)。話(huà)雖如此,但SWT的基本繪圖功能還是不錯(cuò)的,如果有足夠的時(shí)間和耐心的話(huà)還是可以繪出想要的圖形的。下面就讓我們看看SWT如何繪制2D和3D圖形。





回頁(yè)首


3. 用SWT繪制2D圖形

用SWT繪圖通常由兩種方法,一種是借助Graphics Context,另一種是利用Draw2D。然而Draw2D是一個(gè)基于SWT Composite的輕量級(jí)組件,于是在效率上,它無(wú)法體現(xiàn)出SWT的Native Code的速度優(yōu)勢(shì)。故其雖然強(qiáng)大,但僅適用于繪圖工作不是系統(tǒng)瓶頸的應(yīng)用程序。所以我在這里只介紹第一種方法。

3.1 Graphics Context

我們可以在任何實(shí)現(xiàn)了org.eclipse.swt.graphics.Drawable接口的類(lèi)上繪制圖形,這包括一個(gè)控件,一幅圖像,一個(gè)顯示設(shè)備或一個(gè)打印設(shè)備。類(lèi)org.eclipse.swt.graphics.GC是一個(gè)封裝了所有可執(zhí)行的繪圖操作的圖形上下文(Graphics Context)。兩種使用GC的方式我們已經(jīng)在本節(jié)前言中提過(guò),稍后會(huì)作詳細(xì)說(shuō)明。

3.2 在一幅圖像上繪制圖形

下面一段代碼創(chuàng)建了一個(gè)帶有圖像的GC并在上面繪制了兩條線(xiàn):


Image image = new Image(display,"C:/music.gif");                                    GC gc = new GC(image);                                    Rectangle bounds = image.getBounds();                                    gc.drawLine(0,0,bounds.width,bounds.height);                                    gc.drawLine(0,bounds.height,bounds.width,0);                                    gc.dispose();                                    image.dispose();                                    



一旦你創(chuàng)建了一個(gè)GC,你就有責(zé)任通過(guò)它的dispose方法釋放它的資源。一個(gè)由應(yīng)用程序創(chuàng)建的GC需要立即被繪制,然后盡快釋放掉。這是因?yàn)槊總€(gè)GC都需要一個(gè)底層的系統(tǒng)資源,而在某些操作系統(tǒng)中這些資源是稀缺的,像Win98就只允許同時(shí)創(chuàng)建五個(gè)GC對(duì)象。

3.3 在Control上繪圖

類(lèi)org.eclipse.swt.widgets.Control是可繪制的,所以你可以用像在圖像上一樣的方式來(lái)繪制圖形。而和在圖像上繪制所不同的是,如果你使用GC在一個(gè)Control上繪制圖形,你需要知道當(dāng)操作系統(tǒng)自身要繪制這個(gè)control的時(shí)候,它將覆蓋掉你的改動(dòng)。所以在一個(gè)Control上繪制圖形的正確方法是加入其繪制事件的監(jiān)聽(tīng)器。監(jiān)聽(tīng)器類(lèi)為org.eclipse.swt.events.PaintListener,其回調(diào)函數(shù)的參數(shù)是一個(gè)org.eclipse.swt.events.PaintEvent類(lèi)的實(shí)例。這個(gè)PaintEvent實(shí)例中包含一個(gè)GC的引用,你可以向這個(gè)GC發(fā)送消息。下面的代碼示例說(shuō)明了如何建立這種類(lèi)型的繪圖:


Shell shell = new Shell(display);                                    shell.addPaintListener(new PaintListener(){                                    public void paintControl(PaintEvent e){                                    Rectangle clientArea = shell.getClientArea();                                    e.gc.drawLine(0,0,clientArea.width,clientArea.height);                                    }                                    });                                    shell.setSize(150,150)                                    



3.4 剪切(Clipping)

GC的剪切域是可見(jiàn)繪圖發(fā)生的部分。在缺省情況下,一個(gè)GC是一個(gè)被構(gòu)造的可視部分邊界。改變一個(gè)GC的剪切域可以讓我們構(gòu)造出各種圖形效果。其中的一個(gè)例子是如果你想填充一個(gè)缺失了邊緣的矩形。一種方法是繪制多邊形矩形來(lái)組成所需要的圖形,另一種方法就是剪切GC,然后對(duì)其剪切部分進(jìn)行填充。


shell.addPaintListener(new PaintListener() {                                    public void paintControl(PaintEvent e) {                                    Rectangle clientArea = shell.getClientArea();                                    int width = clientArea.width;                                    int height = clientArea.height;                                    e.gc.setClipping(20,20,width - 40, height - 40);                                    e.gc.setBackground(display.getSystemColor(SWT.COLOR_CYAN));                                    e.gc.fillPolygon(new int[] {0,0,width,0,width/2,height});                                    }                                    });                                    

這段代碼在Shell上的顯示的過(guò)程效果如下:



3.5 畫(huà)板(Canvas)

雖然任何Control都可以通過(guò)自身的paintEvent來(lái)繪制圖形,但其子類(lèi)org.eclipse.swt.widgets.Canvas是專(zhuān)門(mén)被設(shè)計(jì)用來(lái)進(jìn)行圖形操作的特殊的繪圖類(lèi)。我們既可以使用一個(gè)Canvas,再加入一個(gè)繪圖監(jiān)聽(tīng)器來(lái)實(shí)現(xiàn)繪圖,也可以通過(guò)繼承來(lái)建立一個(gè)可重用的自定義Control。Canvas有很多style bit,可以在繪圖發(fā)生時(shí)產(chǎn)生作用。

3.6 繪制直線(xiàn)和圖形

我們有很多方法可以在一個(gè)GC上畫(huà)線(xiàn),包括在兩點(diǎn)之間,一系列離散的點(diǎn)之間或一個(gè)預(yù)定義的圖形上都可以。直線(xiàn)是以GC的前景色來(lái)繪制的,我們可以通過(guò)GC繪制擁有不同厚度的各式直線(xiàn)。對(duì)于一個(gè)Paint事件,GC有著與Control組件一樣的屬性,即激發(fā)事件且缺省的直線(xiàn)樣式固定為1個(gè)像素寬。

GC.drawLine(int x1, int y1, int x2, int y2);這條語(yǔ)句在可繪制的面板上的兩點(diǎn)間花了一條直線(xiàn),起始點(diǎn)為(x1,y1),終止點(diǎn)為(x2,y2)。終止點(diǎn)包含在畫(huà)好的直線(xiàn)中。如果起始點(diǎn)等于終止點(diǎn)的話(huà),將會(huì)有一個(gè)獨(dú)立的象素點(diǎn)被繪制出來(lái)。

GC.drawPolyline(int[] pointArray);這條語(yǔ)句繪制了一系列互相連接的線(xiàn)段,作為參數(shù)的數(shù)組用于描述點(diǎn)的位置。語(yǔ)句gc.drawPolyline(new int[] { 25,5,45,45,5,45 });繪制了如下的圖形:



GC.drawPolygon(int[] pointArray);與drawPolyline(int[])是類(lèi)似的,唯一區(qū)別在于最后一個(gè)點(diǎn)和低一個(gè)點(diǎn)是連接的。gc.drawPolygon(new int[] { 25,5,45,45,5,45 });將會(huì)獲得與上圖一樣的結(jié)果。

GC.drawRectangle(int x, int y, int width, int height);這條語(yǔ)句從左上角的(X,Y)點(diǎn),用參數(shù)中的寬和高畫(huà)出了一個(gè)矩形。gc.drawRectangle(5,5,90,45);將會(huì)繪制出如下圖形:



GC.drawRoundedRectangle(int x,int y,int width,int height,int arcWidth,int arcHeight);一個(gè)圓矩形與標(biāo)準(zhǔn)矩形的區(qū)別就在于其四個(gè)角是圓的。圓矩形的每一個(gè)角都可以被想象成為1/4個(gè)橢圓,并且arcWidth和arcHeight由完整的橢圓的寬和高決定。gc.drawRoundedRectangle(5,5,90,45,25,15);繪制了一個(gè)左上角位置為5.5的圓矩形,右邊的圖形是放大后的效果:



GC.drawOval(int x, int y, int width, int height);一個(gè)橢圓是由其相對(duì)應(yīng)的矩形的左上角的位置(x,y)來(lái)確定繪制位置的,其寬和高即為對(duì)應(yīng)矩形的寬和高。對(duì)于圓形來(lái)說(shuō),只需要另寬和高相等即可。



GC.drawArc(int x, int y, int width, int height, int startAngle, int endAngle);曲線(xiàn)的繪制也是與一個(gè)相應(yīng)的矩形有關(guān),即其左上角的位置與寬和高都是相應(yīng)矩形的屬性。StartAntle是從橫向的X開(kāi)始計(jì)算的,所以0度指向的是東而不是北。曲線(xiàn)的繪制是從StartAngle到endAngle以逆時(shí)針?lè)较驁?zhí)行。gc.drawArc(5,5,90,45,90,200);所繪制的圖形如下:



GC.setLineStyle(int style);可以設(shè)置所繪制曲線(xiàn)的樣式,下面列出了一些曲線(xiàn)樣式常量(在org.eclipse.swt.SWT中定義)和與之對(duì)應(yīng)的曲線(xiàn)的圖像:



GC.setLineWidth(int width);可以用于指定所要繪制的曲線(xiàn)的寬度。缺省情況下的曲線(xiàn)寬度為1個(gè)像素。



由于直線(xiàn)的樣式和寬度揮作用到所有的繪圖操作上,所以我們可以作出如點(diǎn)矩形或粗線(xiàn)橢圓這樣的圖形:



3.7 繪制文本

文本可以被繪制在一個(gè)GC上, 字形是用GC的前景色和字體來(lái)繪制的,并且它所占用的區(qū)域是用GC背景色繪制的。要繪制文本,你需要定義要繪制文本的左上角,寬度和高度。有兩組方法可以用來(lái)繪制文本,第一組方法的名字里都帶有一個(gè)Text,并將會(huì)處理直線(xiàn)定界符和制表符。第二組API方法集的名字里都帶有String,它們沒(méi)有制表符或回車(chē)的處理,并主要用于控制像Eclipse的Java編輯器StyledText這樣復(fù)雜的Control。


GC.drawText(String text, int x, int y);                                    Font font = new Font(display,"Arial",14,SWT.BOLD | SWT.ITALIC);                                    // ...                                    gc.drawText("Hello World",5,5);                                    gc.setForeground(display.getSystemColor(SWT.COLOR_BLUE));                                    gc.setFont(font);                                    gc.drawText("Hello\tThere\nWide\tWorld",5,25);                                    // ...                                    font.dispose();                                    



drawText API將控制字符\t處理為制表符,將\n處理為回車(chē)符。


GC.drawString(String text, int x, int y);                                    Font font = new Font(display,"Arial",14,SWT.BOLD | SWT.ITALIC);                                    // ...                                    gc.drawString("Hello World",5,5);                                    gc.setForeground(display.getSystemColor(SWT.COLOR_BLUE));                                    gc.setFont(font);                                    gc.drawString("Hello\tThere\nWide\tWorld",5,25);                                    // ...                                    font.dispose()                                    



當(dāng)使用drawString時(shí),制表符和回車(chē)符將不會(huì)被處理。

在一個(gè)GC上繪制字符的時(shí)候,一個(gè)字符串所占用的大小取決于它的內(nèi)容以及GC的字體。想要確定一個(gè)字符串在被繪制之后所占用的區(qū)域可以使用方法:GC.stringExtent(String text), 或 GC.textExtent(String text)。這兩個(gè)方法都返回一個(gè)Point類(lèi),這個(gè)Point的X和Y是渲染參數(shù)字符串所需要的寬和高。

3.8 圖形填充

直線(xiàn)是用GC前景色繪制的,而圖形的填充用的是GC的背景色。


GC.fillPolygon(int[]);                                    gc.setBackground(display.getSystemColor(SWT.COLOR_BLUE));                                    gc.fillPolygon(new int[] { 25,5,45,45,5,45 })                                    GC.fillRectangle(int x, int y, int width, int height);                                    gc.fillRectangle(5,5,90,45);                                    





需要注意的是,當(dāng)一個(gè)矩形被填充的時(shí)候,右面和下面的邊緣是不被包括在內(nèi)的。


GC.fillRoundedRectangle(int x, int y, int width, int height, int arcWidth, int arcHeight);                                    gc.fillRoundRectangle(5,5,90,45,25,15);                                    



像GC.fillRectangle(...)方法一樣,右面和下面的邊緣不被包含在內(nèi),于是右下角的坐標(biāo)為(94,49)而不是(95,50)。


GC.fillOval(int x, int y, int width, int height);                                    gc.fillOval(5,5,90,45);                                    




GC.fillArc(int x, int y, int widt4h., int height, int startAngle, int endAngle);                                    gc.fillArc(5,5,90,45,90,200);                                    



fillArc()的參數(shù)和drawArc()的參數(shù)是類(lèi)似的,偏移量是從右面的軸開(kāi)始填充,然后沿逆時(shí)針?lè)较蛐D(zhuǎn)給定的角度(endAngle-startAngle)。

GC.fillGradientRectangle(int x, int y, int width. int height, vertical boolean);

這個(gè)方法讓我們可以指定圖形在填充時(shí)所用的顏色可以從GC的前景色按梯度變化(漸變)到背景色。梯度既可以是橫向的也可以是縱向的。


gc.setBackgrouind(display,getSystemColor(SWT.COLOR_BLUE));                                    gc.fillGradientRectangle(5,5,90,45,false);                                    

上面兩條語(yǔ)句建立了一個(gè)使用黑色背景的從左至右的橫向梯度填充。和其他填充方法一樣,左面和下面的邊緣不被包括在內(nèi),所以由下角的位置縮小一個(gè)像素。




gc.setBackground(display.getSystemColor(SWT.COLOR_BLUE));                                    gc.setForeground(display.getSystemColor(SWT.COLOR_CYAN));                                    gc.fillGradientRectangle(5,5,90,45,true);                                    

上面這3行代碼的含義為在縱向自頂向下用前cyan(景色)開(kāi)始,并以藍(lán)色(背景色)結(jié)束的填充。



3.9 異或(XOR)

如果你設(shè)置了GC的XOR模式為true的話(huà),將會(huì)發(fā)生如下情況:對(duì)于每一個(gè)像素點(diǎn),原來(lái)被顯示的紅,綠,藍(lán)的值將被已存在的紅,綠,藍(lán)色進(jìn)行異或操作,所得結(jié)果既作為新的目標(biāo)像素。


shell.setBackground(display.getSystemColor(SWT.COLOR_WHITE));                                    // ...                                    gc.setBackground(display.getSystemColor(SWT.COLOR_BLUE));                                    gc.fillRectangle(5,5,90,45);                                    gc.setXORMode(true);                                    gc.setBackground(display.getSystemColor(SWT.COLOR_WHITE));                                    gc.fillRectangle(20,20,50,50);                                    gc.setBackground(display.getSystemColor(SWT.COLOR_RED));                                    gc.fillOval(80,20,50,50);                                    



3.10 繪制圖像(Draw Image)

類(lèi)org.eclipse.swt.graphics.Image被用來(lái)表示準(zhǔn)備要在像打印機(jī),顯示器這樣的設(shè)備上顯示的圖形。建立一個(gè)圖像最簡(jiǎn)單的方法就是從組織好的文件格式中裝載它。SWT所支持的圖像格式有:GIF,BMP,JGP,PNG和TIFF。


Image image = new Image(display,"C:/eclipse_lg.gif");                                    GC.drawImage(Image image, int x, int y);                                    

每幅圖像都有用其邊界決定的尺寸。例如,圖象eclipse_lg.gif的大小為115*164,我們可以通過(guò)image.getBounds()方法來(lái)進(jìn)行設(shè)定。當(dāng)一幅圖像被繪制的時(shí)候,它將會(huì)以自身定義的邊界作為顯示之后的寬和高。gc.drawImage(image,5,5);

至此,SWT在2D繪圖方面的講解告一段落,上面所提到的內(nèi)容涵蓋了SWT的大部分繪圖功能,并在每個(gè)部分都給出了要注意的細(xì)節(jié)。至于具體實(shí)現(xiàn)就要靠各位的聰明才智了。下面讓我們進(jìn)入最后的部分-SWT的3D繪圖。





回頁(yè)首


4 SWT與OpenGL編程

相較于Java3D API來(lái)說(shuō),SWT以前在3D圖形繪制方面一直沒(méi)有什么好的表現(xiàn)。OpenGL的加入會(huì)不會(huì)使SWT在3D領(lǐng)域有所作為還尚未可知,不過(guò)起碼IBM的程序員們給了SWT機(jī)會(huì)。當(dāng)大家了解了這個(gè)正處于試驗(yàn)階段的組合之后,我們?cè)赟WT上繪制3D圖形就不再是噩夢(mèng)。

OpenGL是一個(gè)為創(chuàng)建高性能2D,3D圖形而設(shè)計(jì)的多平臺(tái)的標(biāo)準(zhǔn)。其硬件和軟件的實(shí)現(xiàn)存在于多個(gè)系統(tǒng)之中,包括Windows,Linux和MacOS。OpenGL可以用于渲染簡(jiǎn)單的2D圖形或復(fù)雜的3D游戲圖形(OpenGL最主要的應(yīng)用領(lǐng)域就是游戲)。作為一個(gè)正在處于事件階段的Eclipse插件,我將在下面的小節(jié)中介紹如何在SWT窗口組件上用SWT繪制圖形。在Eclipse最新的3.2版中,對(duì)OpenGL的支持被集成到org.eclipse.swt項(xiàng)目中,所以我們?cè)趯?shí)現(xiàn)的時(shí)候即可以選擇以插件方式進(jìn)行,也可以直接利用已經(jīng)集成好的組件來(lái)進(jìn)行圖形操作。在本節(jié),我們將以插件方式為例對(duì)代碼進(jìn)行說(shuō)明。

4.1 SWT OpenGL插件

SWT實(shí)現(xiàn)了OpenGL1.1全部功能。包括三個(gè)核心類(lèi)和一個(gè)數(shù)據(jù)類(lèi)。核心類(lèi)為GLContext,GL和GLU。GLContext架起了SWT和OpenGL之間的橋接。一個(gè)Context必須用Drawable,通常是用Canvas來(lái)創(chuàng)建,OpenGL可以在Drawable上渲染場(chǎng)景。需要注意的是,當(dāng)context不再被使用的時(shí)候就應(yīng)該將它釋放掉。同樣,一旦某個(gè)context被釋放掉之后,就不應(yīng)該再次試圖去渲染它。每次Drawable改變大小的時(shí)候,context都需要通過(guò)調(diào)用其resize方法在通知這一事件。這個(gè)方法的調(diào)用讓context調(diào)整自己的view port和視圖參數(shù)。在下一節(jié)中將描述一個(gè)處理這一部分任務(wù)的類(lèi)。

當(dāng)context可用的時(shí)候,我們就可以通過(guò)定義在GL和GLU的一系列方法調(diào)用來(lái)繪制場(chǎng)景。一個(gè)GL類(lèi)大概有超過(guò)330條命令。在GL和GLU中定義的這些函數(shù)和他們的Native實(shí)現(xiàn)幾乎是一一對(duì)應(yīng)的。下圖給出了一個(gè)繪制矩形的例子,我們可以看到用C寫(xiě)成的API和SWT OpenGL API是何其相似:



4.2 SWT OpenGL編程基礎(chǔ)

在下面的小節(jié)中,我將描述一個(gè)顯示四幅3D圖像的應(yīng)用程序。應(yīng)用程序采用了GLSense,這是一個(gè)用于顯示OpenGL場(chǎng)景的工具類(lèi)。它和SWT的Canvas很像,所區(qū)別的是它所展現(xiàn)的內(nèi)容是用OpenGL命令渲染的,而不是使用GC來(lái)繪制。要做到這一點(diǎn),我們需要將一個(gè)GLContext類(lèi)和一個(gè)SWT Canvas相關(guān)聯(lián),并且無(wú)論何時(shí),當(dāng)前上下文中的內(nèi)容都應(yīng)該是由在drawScene中定義的命令來(lái)渲染的。



在構(gòu)造函數(shù)中,一個(gè)SWT Canvas被創(chuàng)建出來(lái)。這就是那個(gè)要和一個(gè)GLContext相關(guān)聯(lián)的Canvas實(shí)例。緊接著,這個(gè)Canvas又注冊(cè)了兩個(gè)監(jiān)聽(tīng)器。第一個(gè)監(jiān)聽(tīng)器的作用是確保這個(gè)Canvas無(wú)論何時(shí)被改變大小,其相應(yīng)的GLContex也會(huì)收到通知并適當(dāng)?shù)母淖兇笮?。第二個(gè)監(jiān)聽(tīng)器主要用于確保一旦Canvas被釋放之后,其相對(duì)應(yīng)的GLContext的也同時(shí)被釋放。為了確保渲染區(qū)域是一個(gè)非零大小的區(qū)域,父組件的客戶(hù)矩形區(qū)被取出來(lái)用于設(shè)置該Canvas的初始大小。這個(gè)初始大小可以在稍后用布局管理器或用戶(hù)Action來(lái)修改。



GLScene將Canvas的全部區(qū)域用于繪圖。無(wú)論Canvas何時(shí)調(diào)整其尺寸,我們都要獲取客戶(hù)區(qū)并將新的寬度和高度傳遞給Contex,而context將根據(jù)新的寬度和高度適當(dāng)?shù)恼{(diào)整視圖。


XML error: The image is not displayed because the width is greater than the maximum of 572 pixels. Please decrease the image width.

GLScene被分割為兩個(gè)部分:初始化Context和初始化OpenGL的狀態(tài)機(jī)。對(duì)于Context來(lái)說(shuō),我們只是簡(jiǎn)單的建立一個(gè)新的GLContext并使它成為當(dāng)前被使用的Context。OpenGL的渲染總是在當(dāng)前的context上進(jìn)行繪制,因此如果你有超過(guò)一個(gè)活動(dòng)的GLScene,很重要的一點(diǎn)是要在所有繪制動(dòng)作發(fā)生之前將它的Context設(shè)置為當(dāng)前的Context。initGL方法最開(kāi)始提供清除顏色緩存顏色,隨后建立了一個(gè)深度緩存(depth buffer).第47行指出了深度值如何進(jìn)行比較。這一比較函數(shù)主要用于拒絕或接受正在引用的像素。GL.GL_LEQUAL選項(xiàng)指定接受那些在視圖上更接近或有相同距離的像素。第48行啟動(dòng)了深度測(cè)試(depth test),緊接的一行設(shè)定陰影模型為GL.GL_SMOOTH,這一設(shè)定的效果是如果表面上的兩個(gè)頂點(diǎn)顏色不同的話(huà),系統(tǒng)將對(duì)顏色進(jìn)行插值。最后,第50行要求渲染引擎在計(jì)算顏色和紋理協(xié)調(diào)插值運(yùn)算的時(shí)候起到關(guān)鍵的作用。


XML error: The image is not displayed because the width is greater than the maximum of 572 pixels. Please decrease the image width.

GLScene類(lèi)的最后兩個(gè)方法用于處理重繪和場(chǎng)景繪制。當(dāng)場(chǎng)景何時(shí)需要重繪的時(shí)候,第一個(gè)方法為其他類(lèi)提供重繪操作的接口。第二個(gè)方法主要用于讓繼承GLScene的子類(lèi)覆寫(xiě)。其缺省實(shí)現(xiàn)只是簡(jiǎn)單的清除了顏色和深度緩存,通過(guò)裝在鑒別矩陣(identify matrix)重新恢復(fù)調(diào)整系統(tǒng)。

4.3 3D Chart

利用上一節(jié)的準(zhǔn)備,我們已經(jīng)將主應(yīng)用程序進(jìn)行了劃分。這個(gè)圖像顯示了4組數(shù)據(jù)。每一組數(shù)據(jù)都是由相同的固定點(diǎn)所組成,每個(gè)點(diǎn)都是從0.0到10.0之間的一個(gè)正值。

示例程序運(yùn)行在一個(gè)非常簡(jiǎn)單的Eclipse view上,唯一值得注意的是Refresher,這個(gè)線(xiàn)程將強(qiáng)迫OpenGL場(chǎng)景被周期性的重繪。通過(guò)這種方法,當(dāng)視圖被移動(dòng)或旋轉(zhuǎn)的時(shí)候,component總能進(jìn)行有效的更新渲染效果。run()方法調(diào)用的時(shí)間間隔為100毫秒,所以理論上的圖像速度能達(dá)到每秒10幀。



每個(gè)數(shù)據(jù)集合的點(diǎn)的值是用圓柱體來(lái)表示的。通過(guò)執(zhí)行3個(gè)GLU調(diào)用,我們就能夠繪制圓柱體:其中的兩個(gè)用于渲染圓柱體兩頭的圓盤(pán)部分,另外一個(gè)用于渲染圓柱體的四周。例如,要渲染兩個(gè)單元高的圓柱體,你可以用下面的代碼來(lái)實(shí)現(xiàn):



第一行申請(qǐng)了繪制圓盤(pán)和圓柱所需的二次曲面。然后整個(gè)場(chǎng)景被逆時(shí)針旋轉(zhuǎn)了90度,以便圓柱體可以被垂直繪制。下一步,底部的圓盤(pán)被渲染,然后是圓柱體的四周。在我們能夠繪制頂部圓盤(pán)的時(shí)候,通過(guò)場(chǎng)景轉(zhuǎn)換(scene translation),我們可以在Z軸移動(dòng)兩個(gè)單元。最后一個(gè)圓盤(pán)隨后被繪制出來(lái),調(diào)整系統(tǒng)通過(guò)向回移動(dòng)兩個(gè)單元來(lái)進(jìn)行恢復(fù)。最后,由第一行申請(qǐng)的二次曲面被釋放掉。

按照上述方法運(yùn)行程序是很費(fèi)時(shí)間的。當(dāng)僅繪制一個(gè)圓柱體的時(shí)候,效率低下不是一個(gè)很?chē)?yán)重的問(wèn)題,但如果要繪制成百個(gè)對(duì)象的話(huà)就會(huì)嚴(yán)重影響程序的執(zhí)行性能。對(duì)于這種情況,OpenGL給出了一個(gè)解決這個(gè)問(wèn)題的技巧,就是使用顯示列表(display list)。

一個(gè)顯示列表是一組已編譯的OpenGL命令。定義命令集合的列表被放在glNewList(int list, int mode) 和 glEndList()方法調(diào)用之間。第一個(gè)參數(shù)必須是一個(gè)正整數(shù),可以用來(lái)唯一的表示一個(gè)被創(chuàng)建的顯示列表。你可以讓GL用glGenLists(int n)方法為你生成多個(gè)列表標(biāo)識(shí)符。第二個(gè)參數(shù)用于指定列表是否被編譯或編譯之后立即被執(zhí)行。大多數(shù)情況下你都需要編譯這個(gè)列表。然后,你可以使用glCallList(int list)方法來(lái)顯示整個(gè)列表。





回頁(yè)首


5 結(jié)束語(yǔ)

至此,有關(guān)于SWT與OpenGL圖形有關(guān)的粗略功能就介紹完了,有鑒于3D圖形對(duì)象和OpenGL的復(fù)雜性,一篇這樣篇幅的文章肯定不能覆蓋其每一個(gè)角落,我只能給各位一個(gè)動(dòng)手嘗試機(jī)會(huì)。希望整篇專(zhuān)題沒(méi)有讓你枯燥得睡著,并因此有了一個(gè)不錯(cuò)的SWT的基礎(chǔ),我的目的就達(dá)到了。



關(guān)于作者

 

薛笛,是黑龍江大學(xué)研究生。他目前在黑龍江大學(xué)信息技術(shù)研究所工作,從事傳感器網(wǎng)絡(luò)和分布式數(shù)據(jù)庫(kù)的研究,對(duì)Java技術(shù)特別感興趣??梢酝ㄟ^(guò) jxuedi@gmail.com 與他聯(lián)系。






本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶(hù)發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
SWT 圖形繪畫(huà)接口詳解 (SWT Graphics)
Taking a look at SWT Images
SWT 繪圖技術(shù)
讓 Eclipse 插件程序具有二維作圖能力
JAVA.SWT/JFace: SWT高級(jí)控件之SWT系統(tǒng)資源
[SWT] Canvas scroll 滾動(dòng)條
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服