轉(zhuǎn)帖|其它|編輯:郝浩|2008-09-01 10:38:02.000|閱讀 2004 次
概述:JavaFX 是 Sun 推出的一套基于 Java 技術(shù)的產(chǎn)品家族。 JavaFX Script 可以用來(lái)高效的創(chuàng)建富媒體和交互性很強(qiáng)的應(yīng)用。 JavaFX 是 Adobe Flex 和 Microsoft Silverlight 的有力競(jìng)爭(zhēng)者。本文通過(guò)具體的實(shí)例介紹了 JavaFX Script 語(yǔ)言本身的一些高級(jí)特性并討論了 JavaFX Script 中的一些高級(jí)話題,包括創(chuàng)建復(fù)雜的用戶界面、實(shí)現(xiàn)動(dòng)畫效果、JavaFX Script 應(yīng)用的部署和在一個(gè)獨(dú)立的 Java 應(yīng)用程序中嵌入 JavaFX Script 等。
# 界面/圖表報(bào)表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
JavaFX Script 語(yǔ)言簡(jiǎn)介
JavaFX 是 Sun 推出的一套基于 Java 技術(shù)的產(chǎn)品家族,其目的是為從桌面機(jī)、移動(dòng)設(shè)備、機(jī)頂盒到藍(lán)光光盤等提供一致的用戶體驗(yàn)。 JavaFX 目前包含 JavaFX Script 和 JavaFX Mobile 。 JavaFX Script 可以用來(lái)高效的創(chuàng)建富媒體和交互性很強(qiáng)的應(yīng)用。 JavaFX 是 Adobe Flex 和 Microsoft Silverlight 的有力競(jìng)爭(zhēng)者。本文通過(guò)具體的例子介紹了 JavaFX Script 語(yǔ)言本身的一些高級(jí)特性。這些特性包括塊表達(dá)式、范圍(Range)表達(dá)式、序列的修改、觸發(fā)器(Trigger)和數(shù)據(jù)綁定。另外還結(jié)合具體的應(yīng)用,討論了 JavaFX Script 中的一些高級(jí)話題,包括創(chuàng)建復(fù)雜的用戶界面、實(shí)現(xiàn)動(dòng)畫效果、JavaFX Script 應(yīng)用的部署和在一個(gè)獨(dú)立的 Java 應(yīng)用程序中嵌入 JavaFX Script 等。
目前 JavaFX Script 語(yǔ)言本身在不斷的變化之中,本文中對(duì) JavaFX Script 語(yǔ)法的說(shuō)明和實(shí)例,均基于 JavaFX Script 在 2008 年 7 月 21 號(hào)的版本。開(kāi)發(fā)環(huán)境采用 NetBeans 6.1,并安裝 JavaFX Script 插件。請(qǐng)從 參考資源 中下載相關(guān)的工具。
JavaFX Script 高級(jí)特性
下面具體介紹 JavaFX Script 語(yǔ)言的一些高級(jí)特性。
塊表達(dá)式
JavaFX Script 中的塊表達(dá)式是包含在 {} 中的一系列用分號(hào)分隔的語(yǔ)句。如果塊表達(dá)式中的最后一個(gè)語(yǔ)句是表達(dá)式的話,那么這個(gè)塊表達(dá)式的值就是最后這個(gè)表達(dá)式的值;否則該塊表達(dá)式的值是 Void 類型。塊表達(dá)式適合于那些在代碼中只出現(xiàn)一次的計(jì)算邏輯。因?yàn)橹怀霈F(xiàn)一次,可以不用把這樣的邏輯封裝在一個(gè) function 中。而塊表達(dá)式又可以把這部分邏輯的代碼與其它部分區(qū)別開(kāi)來(lái)。在 代碼清單 1 中,對(duì)于薪水的計(jì)算邏輯被封裝在一個(gè)塊表達(dá)式中。
清單 1. 塊表達(dá)式示例
var baseSalary = 10000;
var salary = {
12 * (baseSalary + 1000) + 2 * baseSalary
};
System.out.println(salary);
范圍表達(dá)式
熟悉其他動(dòng)態(tài)語(yǔ)言,如 Python、Ruby 和 Groovy 的人對(duì)于范圍(Range)表達(dá)式可能并不陌生。 JavaFX Script 也引入了同樣的范圍表達(dá)式,可以用來(lái)定義一個(gè)序列。不過(guò)在使用方式與其他語(yǔ)言有些不同。
在 JavaFX Script 中可以通過(guò) [number1..number2] 來(lái)定義一個(gè)序列。這里需要注意的是兩個(gè)邊界數(shù)字 number1 和 number2 都是包含在序列里面的。如 [0..5] 包含 0,1,2,3,4,5 這六個(gè)數(shù)字。這點(diǎn)和 Ruby 里面的 number1...number2 和 Groovy 里面的 number1..number2 是一樣的。默認(rèn)情況下,范圍中的數(shù)字之間的間隔是 1,可以通過(guò)在 number2 后面加上顯式的 step 來(lái)聲明間隔。比如 [0..9 step 3] 包含的數(shù)字是 0,3,6,9 。
當(dāng) number1 大于 number2 的時(shí)候,可以通過(guò)指定值為負(fù)數(shù)的 step 來(lái)生成降序排列的序列。如 [5..0 step -1] 包含的數(shù)字是 5,4,3,2,1,0 ;如果不指定 step,或是 step 的值為正數(shù)的話,生成的序列實(shí)際上是空的。如 [5..0] 是個(gè)空的序列。
序列的修改
JavaFX Script 提供了兩個(gè)強(qiáng)大的操作符 insert 和 delete 來(lái)對(duì)序列進(jìn)行操作。
insert 語(yǔ)句的語(yǔ)法如 代碼清單 2 中所示。
清單 2. insert 語(yǔ)句的語(yǔ)法
insert x into seq
insert x before seq[idx]
insert x after seq[idx]
從代碼清單 2 列出的語(yǔ)法中可以看到,insert 語(yǔ)句可以往序列中的指定位置插入新元素。使用 insert x into seq 會(huì)把 x 添加到序列末尾。而 insert x before seq[idx] 和 insert x after seq[idx] 則分別可以把新元素插入到 seq[idx] 所對(duì)應(yīng)的元素的前面和后面。
delete 的語(yǔ)法如 代碼清單 3 中所示。
清單 3. delete 語(yǔ)句的語(yǔ)法
delete seq
delete x from seq
delete seq[idx]
delete seq[a..b]
在 代碼清單 3 列出的四種用法中,第一種會(huì)刪除整個(gè)序列;第二種和第三種都會(huì)刪除指定元素,不同的是第二種需要指定元素的值,而第三種需要指定其序號(hào);第四種是用來(lái)刪除序列中給定范圍之內(nèi)的全部元素的。
觸發(fā)器
JavaFX Script 提供類似 SQL 中觸發(fā)器的機(jī)制來(lái)處理數(shù)據(jù)的變化。如果在某個(gè)屬性上聲明了觸發(fā)器,那么當(dāng)它的值發(fā)生變化的時(shí)候,觸發(fā)器就會(huì)被觸發(fā),預(yù)先定義的邏輯就會(huì)被執(zhí)行。代碼清單 4 中給出了觸發(fā)器的一個(gè)實(shí)例。
清單 4. 觸發(fā)器示例
class Person {
attribute address : String
on replace oldAddress = newAddress {
System.out.println(" 地址已經(jīng)從 {oldAddress} 改為 {newAddress} 。 ");
};
}
var person = Person {
address : " 北京市朝陽(yáng)區(qū) "
};
person.address = " 北京市海淀區(qū) "; [SPAN]
從代碼清單 4 中可以看到,當(dāng)屬性 address 的值發(fā)生改變時(shí),會(huì)輸出相應(yīng)的提示信息。該屬性的舊值和新值都可以得到,并在相應(yīng)的處理邏輯代碼中使用。觸發(fā)器不僅可以用于單值屬性,也可以用于序列上。代碼清單 5 和 代碼清單 6 中給出的兩個(gè)例子分別演示了如何在序列中插入和刪除元素之后得到通知。
清單 5. 序列中插入新元素的觸發(fā)器
class Company {
attribute employees : String[]
on replace oldEmployees = newEmployees {
if (sizeof employees - sizeof oldEmployees == sizeof newEmployees) {
System.out.println(" 歡迎新員工 {newEmployees} 加入! ");
}
};
}
var company = new Company();
insert " 張三 " into company.employees;
insert " 李四 " into company.employees;
清單 6. 序列中刪除元素的觸發(fā)器
class Student {
attribute courses : String[]
on replace oldCourses = newCourses {
if (sizeof newCourses == 0) {
System.out.println(" 你已經(jīng)成功退選了課程 {oldCourses} 。 ");
}
}
}
var student = new Student();
insert " 網(wǎng)絡(luò)信息體系結(jié)構(gòu) " into student.courses;
insert " 編譯原理 " into student.courses;
delete student.courses[0];
數(shù)據(jù)綁定
JavaFX Script 中,屬性初始化的時(shí)候,可以通過(guò) bind 將屬性的值和某個(gè)表達(dá)式綁定起來(lái),當(dāng)該表達(dá)式所引用的對(duì)象發(fā)生變化時(shí),該屬性的值也會(huì)自動(dòng)更新。方法也可以通過(guò) bound 來(lái)設(shè)成綁定的。以 代碼清單 7 為例,方法 getPercent 在其內(nèi)部的變量的值發(fā)生改變的時(shí)候,會(huì)自動(dòng)重新求值。屬性 currentValue 的值的改變首先使得方法 getPercent 的值發(fā)生改變,然后再使得 percent 的值發(fā)生變化。這一切都是自動(dòng)的。
清單 7. 數(shù)據(jù)綁定示例
class Stock {
attribute currentValue : Number on replace oldValue = newValue {
lastValue = oldValue;
}
attribute lastValue : Number;
bound function getPercent() : Number {
return (currentValue - lastValue) / lastValue;
}
}
var stock = Stock {
currentValue : 100
lastValue : 98.6
}
let percent = bind stock.getPercent();
System.out.println(percent);
stock.currentValue = 101;
System.out.println(percent);
上面介紹了 JavaFX Script 語(yǔ)言本身的一些高級(jí)特性,下面將以實(shí)例的方式討論 JavaFX Script 開(kāi)發(fā)中的幾個(gè)重要的主題。
創(chuàng)建復(fù)雜用戶界面
用過(guò) Swing 的人可能都有個(gè)感覺(jué),那就是用 Swing 創(chuàng)建用戶界面的時(shí)候,不僅編寫起來(lái)麻煩,代碼也比較冗長(zhǎng)。使用 JavaFX Script,可以幫助你更快更簡(jiǎn)單的創(chuàng)建用戶界面。 JavaFX Script 簡(jiǎn)化用戶界面的創(chuàng)建的能力主要體現(xiàn)在三個(gè)方面:
在 JavaFX Script 中使用 Swing 的 GUI 組件是很容易的。 JavaFX Script 在 javafx.ext.swing 包中提供了很多常用的 Swing 組件的封裝。這些組件可以在 JavaFX Script 代碼中直接以聲明式的方式使用。另外一些復(fù)雜的組件,如 JTable 和 JTree,目前在 JavaFX Script 中還不可以直接使用。在這種情況下,需要繼承 javafx.ext.swing.Component 類并實(shí)現(xiàn)該類的抽象方法 createJComponent()。該方法返回一個(gè) JComponent 對(duì)象。[SPAN]
下面以一個(gè)具體的實(shí)例來(lái)說(shuō)明如何創(chuàng)建復(fù)雜用戶界面。該應(yīng)用是一個(gè) RSS 訂閱源(Feed)的閱讀器,它可以解析 OPML 文件并在左側(cè)以一個(gè)樹形結(jié)構(gòu)來(lái)顯示所有的訂閱源。當(dāng)點(diǎn)擊某個(gè)訂閱源時(shí),可以在右側(cè)看到該訂閱源的內(nèi)容。顯示所有訂閱源的是左側(cè)的 OmplViewer,顯示訂閱源內(nèi)容的是右側(cè)的 FeedViewer。該應(yīng)用的截圖見(jiàn) 圖 1。
圖 1. RSS 訂閱源閱讀器
由于 RSS 訂閱源閱讀器的代碼比較多,在本文中將只介紹其中的重點(diǎn),完整的代碼請(qǐng)下載。
繼承javafx.ext.swing.Component
在上面提到,一些復(fù)雜的 Swing 組件,目前需要通過(guò)繼承 javafx.ext.swing.Component 的方式來(lái)使用。在 RSS 訂閱源閱讀器中,左側(cè)顯示所有訂閱源的組件是 JTree。類 OpmlViewer 繼承自 javafx.ext.swing.Component,并實(shí)現(xiàn)其createJComponent()方法,該方法創(chuàng)建了一個(gè)JTree 對(duì)象,并包裝在一個(gè) JScrollPane 中。該類中的其它代碼都與 JTree 對(duì)象交互。具體見(jiàn) 代碼清單 8。
清單 8. 繼承 javafx.ext.swing.Component 示例
public class OpmlViewer extends Component {
private attribute tree : JTree;
protected function createJComponent(): JComponent {
tree = new JTree();
return new JScrollPane(tree);
}
} [SPAN]
觸發(fā)器的使用
類 OpmlViewer 有一個(gè)屬性 opmlFilePath 用來(lái)表示 OPML 文件的路徑。當(dāng)該屬性的值發(fā)生改變的時(shí)候,OpmlViewer 就需要顯示該 OPML 文件中的所有訂閱源。這是通過(guò)在屬性 opmlFilePath 上創(chuàng)建一個(gè)觸發(fā)器來(lái)實(shí)現(xiàn)的。具體見(jiàn) 代碼清單 9。
清單 9. OpmlViewer 中的觸發(fā)器使用
public attribute opmlFilePath : String on replace
oldPath = newPath {
if (newPath != null and not "".equals(newPath.trim())) {
setOpmlFilePath(newPath);
}
}
數(shù)據(jù)綁定的使用
數(shù)據(jù)綁定在這個(gè)應(yīng)用中主要用來(lái)協(xié)調(diào)左側(cè)的 OmplViewer 和右側(cè)的 FeedViewer。FeedViewer 的屬性 feedUrl 綁定到 OmplViewer 的屬性 selectedFeedUrl。這樣當(dāng)用戶選擇了某個(gè)訂閱源的時(shí)候,OmplViewer 的屬性 selectedFeedUrl 的值會(huì)發(fā)生變化,F(xiàn)eedViewer 的屬性 feedUrl 的值也會(huì)隨之變化。FeedViewer 就會(huì)去加載新的訂閱源內(nèi)容了。具體見(jiàn) 代碼清單 10。
清單 10. OpmlView 和 FeedViewer 之間的數(shù)據(jù)綁定
var opmlViewer = OpmlViewer {
opmlFilePath : "c:\\google-reader-subscriptions.xml",
hmax : 200
hmin : 100
};
var feedViewer = FeedViewer {
feedUrl : bind opmlViewer.selectedFeedUrl
};
上面介紹了如何在 JavaFX Script 中創(chuàng)建復(fù)雜的用戶界面,下面將涉及 JavaFX Script 中一個(gè)有趣的話題,那就是實(shí)現(xiàn)動(dòng)畫效果。
創(chuàng)建動(dòng)畫
使用 JavaFX Script 來(lái)創(chuàng)建動(dòng)畫是一件非常容易的事情。 JavaFX Script 所采用的動(dòng)畫方式叫“關(guān)鍵幀動(dòng)畫(key frame animation)”。這種動(dòng)畫是通過(guò)一系列的場(chǎng)景的轉(zhuǎn)換來(lái)完成的,而場(chǎng)景則是由特定時(shí)間點(diǎn)上的關(guān)鍵幀來(lái)表示的。程序員只需要以聲明式的方式定義這些關(guān)鍵幀,系統(tǒng)會(huì)自動(dòng)的完成剩下的工作。“關(guān)鍵幀動(dòng)畫”又分成兩種,離散型和插值型。兩者的區(qū)別在于:對(duì)于后者,系統(tǒng)會(huì)用特定的插值函數(shù)來(lái)計(jì)算每個(gè)關(guān)鍵幀之間的中間狀態(tài)。 JavaFX Script 中的動(dòng)畫主要是依靠 javafx.animation.Timeline、javafx.animation.KeyFrame、javafx.animation.KeyValue 這三個(gè)類來(lái)完成的。
這三個(gè)類的基本說(shuō)明如下:
KeyValue 的用法
下面用一個(gè)例子來(lái)具體說(shuō)明 KeyValue 的用法,見(jiàn) 代碼清單 11。
清單 11. KeyValue 的用法
var simpleVar = 0;
function output() : Void {
System.out.println("The value of simpleVar is {simpleVar}.");
}
Timeline {
repeatCount: Timeline.INDEFINITE
keyFrames : [
KeyFrame {
time : 1s
action: output
},
KeyFrame {
time : 1.5s
action : output
},
KeyFrame {
time : 2s
values : [
simpleVar => 200 tween Interpolator.LINEAR
]
action: output
}
]
}.start()
代碼清單 11 中創(chuàng)建了一個(gè)無(wú)限運(yùn)行的 Timeline,該 Timeline 包含 3 個(gè)關(guān)鍵幀,所關(guān)聯(lián)的時(shí)間點(diǎn)分別是 1 秒、1.5 秒和 2 秒。在這 3 個(gè)關(guān)鍵幀所關(guān)聯(lián)的時(shí)間點(diǎn)到達(dá)的時(shí)候,都會(huì)執(zhí)行 output 方法,該方法會(huì)打印出 simpleVar 的值。需要說(shuō)明的是在第三個(gè)關(guān)鍵幀上,通過(guò) values 聲明了 simpleVar 在該關(guān)鍵幀中的值是 200,并且是通過(guò)線性插值(Interpolator.LINEAR)的方式來(lái)計(jì)算中間值。因此,在 1 秒和 1.5 秒的關(guān)鍵幀中,simpleVar 的值就是根據(jù)線性插值的方式計(jì)算出來(lái)的。[SPAN]
動(dòng)畫實(shí)例
下面通過(guò)一個(gè)實(shí)例來(lái)說(shuō)明如何使用 JavaFX Script 來(lái)編寫動(dòng)畫。在這個(gè)動(dòng)畫實(shí)例中,將演示地球自轉(zhuǎn)和月球圍繞地球的轉(zhuǎn)動(dòng)。動(dòng)畫的演示效果見(jiàn) 圖 2 所示。需要說(shuō)明的是 圖 2 中的地球和月球的大小以及月球的運(yùn)行軌道均為示意。
圖 2. 地球自轉(zhuǎn)和月球圍繞地球運(yùn)轉(zhuǎn)的動(dòng)畫
該動(dòng)畫的源代碼如代碼清單 12所示。
清單 12. 地球和月球運(yùn)行示意動(dòng)畫的源代碼
var earthImages = for (i in [1..7]) {
Image {url : "file:images/earth{i}.png"}
}
var moonImage = Image {url : "file:images/moon.gif"};
var currentEarthImage = earthImages[0];
var earthTimeline = Timeline {
keyFrames: for (image in earthImages) {
KeyFrame {
time: 300ms* indexof image
action: function(){currentEarthImage=image;}
}
},
repeatCount : Timeline.INDEFINITE
}
var moonX = 525;
var moonY = 260;
var moonTimeline = Timeline {
var top_right = at (300ms) {
moonX => 425 tween Interpolator.LINEAR;
moonY => 425 tween Interpolator.LINEAR;
}
var right = at (600ms) {
moonX => 260 tween Interpolator.LINEAR;
moonY => 515 tween Interpolator.LINEAR;
}
var right_bottom = at (900ms) {
moonX => 110 tween Interpolator.LINEAR;
moonY => 425 tween Interpolator.LINEAR;
}
var bottom = at (1.2s) {
moonX => 5 tween Interpolator.LINEAR;
moonY => 260 tween Interpolator.LINEAR;
}
var bottom_left = at (1.5s) {
moonX => 110 tween Interpolator.LINEAR;
moonY => 110 tween Interpolator.LINEAR;
}
var left = at (1.8s) {
moonX => 260 tween Interpolator.LINEAR;
moonY => 5 tween Interpolator.LINEAR;
}
var left_top = at (2.1s) {
moonX => 425 tween Interpolator.LINEAR;
moonY => 110 tween Interpolator.LINEAR;
}
var top = at (2.4s) {
moonX => 515 tween Interpolator.LINEAR;
moonY => 260 tween Interpolator.LINEAR;
}
keyFrames:
[top_right, right, right_bottom, bottom, bottom_left, left, left_top, top],
repeatCount : Timeline.INDEFINITE
}
Frame {
title: "Earth and Moon"
width: 560
height: 580
closeAction: function() {
earthTimeline.stop();
moonTimeline.stop();
java.lang.System.exit( 0 );
}
visible: true
stage: Stage {
fill : Color.BLACK
content: [
ImageView {
image: bind currentEarthImage,
transform : Transform.translate(110, 110);
},
ImageView {
image : moonImage
transform : bind Transform.translate(moonX, moonY)
}
]
}
}
earthTimeline.start();
moonTimeline.start();
代碼中創(chuàng)建了兩個(gè) Timeline,一個(gè)用來(lái)表示地球的自轉(zhuǎn),另外一個(gè)用來(lái)表示月球圍繞地球的轉(zhuǎn)動(dòng)。表示地球自轉(zhuǎn)的動(dòng)畫使用的是離散型“關(guān)鍵幀動(dòng)畫”。該 Timeline earthTimeline 包含 7 個(gè)關(guān)鍵幀,每個(gè)幀的間隔是 300 毫秒。當(dāng)每個(gè)幀所關(guān)聯(lián)的時(shí)間點(diǎn)到達(dá)的時(shí)候,所執(zhí)行的動(dòng)作是將 currentEarthImage 的值設(shè)成該幀對(duì)應(yīng)的地球的一張圖片。當(dāng) currentEarthImage 的值發(fā)生改變的時(shí)候,ImageView 就會(huì)顯示那張圖片。[SPAN]
表示月球圍繞地球轉(zhuǎn)動(dòng)的動(dòng)畫使用的是插值型“關(guān)鍵幀動(dòng)畫”。該 Timeline moonTimeline 的效果是使得代表月球的圖片按照一個(gè)圓形來(lái)變換位置。該 Timeline 包含 8 個(gè)關(guān)鍵幀,分別表示圓周上的 8 個(gè)位置。當(dāng)每個(gè)幀所關(guān)聯(lián)的時(shí)間點(diǎn)到達(dá)的時(shí)候,所執(zhí)行的動(dòng)作是 moonX 和 moonY 的值設(shè)成計(jì)算出來(lái)的月球的圖片在窗口中的位置。通過(guò) Transform.translate(moonX, moonY) 這樣的一個(gè)變換來(lái)改變圖片的位置。插值型“關(guān)鍵幀動(dòng)畫”指的是,程序中聲明了 8 個(gè)關(guān)鍵幀,系統(tǒng)會(huì)自動(dòng)按照指定的函數(shù)來(lái)計(jì)算圖片在中間狀態(tài)的位置。這里使用的插值函數(shù)是線性插值。
值得注意的是,如果使用 代碼清單 12 中的方式,運(yùn)行起來(lái)之后,月球的圖片的運(yùn)動(dòng)并不是一個(gè)圓形,而是一個(gè)正八邊形。這是由于以線性插值的方式計(jì)算出來(lái)的中間狀態(tài)的位置與實(shí)際需要的弧形有較大的偏差。而目前 JavaFX Script 并沒(méi)有提供弧形的插值函數(shù)。所以一個(gè)更好的選擇是使用離散型“關(guān)鍵幀動(dòng)畫”,并且提供更多的關(guān)鍵幀,這樣使得月球圖片的運(yùn)行軌跡更加平滑。代碼清單 13 中給出了新的關(guān)鍵幀的生成方法。
清單 13. 更平滑的關(guān)鍵幀生成方法
function getKeyFrames() : KeyFrame[] {
var frames = [] as KeyFrame[];
for (i in [1..36]) {
var y = 260 - 260 * Math.sin((360 - i * 10) * Math.PI / 180);
var x = 260 + 260 * Math.cos((360 - i * 10) * Math.PI / 180);
var frame = KeyFrame {
time : 200ms * i
action : function() {
moonX = x.intValue();
moonY = y.intValue();
}
};
insert frame into frames;
}
return frames;
}
從代碼清單 13 中可以看到,一共定義了 36 個(gè)關(guān)鍵幀,每個(gè)幀對(duì)應(yīng)的 moonX 和 moonY 的值都是通過(guò)計(jì)算得出來(lái)的。使用了上面的 36 個(gè)關(guān)鍵幀之后,運(yùn)行起來(lái)可以看到月球圖片的更好的動(dòng)畫效果。
在討論完 JavaFX Script 中的動(dòng)畫之后,下面將討論如何部署 JavaFX Script 應(yīng)用。
部署 JavaFX Script 應(yīng)用
在完成 JavaFX Script 應(yīng)用的編寫和調(diào)試之后,就可以部署該應(yīng)用了。 JavaFX Script 的應(yīng)用的部署方式主要有兩種,分別是使用 Java Web Start 和使用 Open JavaFX 編譯器。下面具體介紹這兩種部署方式。
使用 Java Web Start
Java Web Start 是從 JRE 5.0 開(kāi)始被引入到 Java 運(yùn)行環(huán)境(JRE)中來(lái)的。它使得可以從 Web 下載和運(yùn)行 Java 程序。當(dāng)本機(jī)安裝了 5.0 及以上版本的 JRE 后,如果通過(guò)瀏覽器訪問(wèn)內(nèi)容類型(Content type)是 application/x-java-jnlp-file 的 URL 時(shí),Java Web Start 會(huì)自動(dòng)運(yùn)行,并下載相應(yīng)的 JNLP 文件,來(lái)啟動(dòng) Java 應(yīng)用。
JNLP 的文件內(nèi)容可以參考 代碼清單 14。該 JNLP 文件可以用來(lái)啟動(dòng)前面提到的 JavaFX Script 應(yīng)用“ RSS 訂閱源閱讀器”。
清單 14. “ RSS 訂閱源閱讀器”的 JNLP 文件
<?xml version="1.0" encoding="utf-8"?>
<jnlp
spec="1.5+"
codebase="//localhost:8080/javafx"
href="feedReader.jnlp">
<information>
<title>RSS Feed Reader</title>
<vendor>Fu CHENG</vendor>
<offline-allowed />
</information>
<security>
<all-permissions/>
</security>
<resources>
<j2se version="1.5+" href="//java.sun.com/products/autodl/j2se"
java-vm-args="-Xss1M -Xmx256M"
>
</j2se>
<jar href="javafxrt.jar"/>
<jar href="javafxgui.jar"/>
<jar href="javafx-swing.jar"/>
<jar href="Scenario.jar"/>
<jar href="rome-0.8.jar"/>
<jar href="jdom.jar"/>
<jar href="FeedReader.jar" main="true"/>
</resources>
<application-desc main-class="feedreader.Main">
</application-desc>
</jnlp>
需要說(shuō)明的是,在使用 Java Web Start 時(shí),所有的 jar 包都必須經(jīng)過(guò)數(shù)字簽名。可以使用 JDK 中自帶的 jarsigner 這個(gè)工具。
使用 OpenJFX 編譯器
OpenJFX 是 JavaFX 開(kāi)源社區(qū)中的一個(gè)孵化項(xiàng)目,它的作用是將 JavaFX Script 編譯成 JVM 上可以直接運(yùn)行的 class 文件(字節(jié)碼)。從 參考資源 中下載了 OpenJFX 的編譯器之后,通過(guò)運(yùn)行 javafxc 命令就可以將一個(gè) JavaFX Script 文件編譯成一系列 Java class 文件。再使用 javafx 命令就可以運(yùn)行該應(yīng)用。
在獨(dú)立的 Java 應(yīng)用中嵌入 JavaFX Script
JDK 6.0 中引入了 JSR 223(Scripting 框架),使得可以在 JVM 上執(zhí)行 JavaScript、Python、Ruby 和 JavaFX Script 等動(dòng)態(tài)語(yǔ)言。如果你的 JavaFX Script 是作為一個(gè)獨(dú)立的 Java 應(yīng)用的一部分的話,使用 JSR 223 可以很容易將 JavaFX Script 嵌入其中。
下面以一個(gè)簡(jiǎn)單計(jì)算器的例子來(lái)說(shuō)明如何使用 JSR 223 來(lái)將 JavaFX Script 嵌入 Java 應(yīng)用中。該簡(jiǎn)單計(jì)算器可以接受用戶輸入的算術(shù)表達(dá)式并將計(jì)算結(jié)果告訴用戶。算術(shù)表達(dá)式可以包含加、減、乘、除和括號(hào)等。如果使用 Java 來(lái)計(jì)算算術(shù)表達(dá)式的值話,需要對(duì)表達(dá)式進(jìn)行分析,拆分成可以識(shí)別的符號(hào),再進(jìn)行運(yùn)算。而如果使用 JavaFX Script 的話,只需要將整條表達(dá)式交給 JavaFX 引擎去求值即可。因此,整個(gè)程序由 Java 來(lái)處理用戶的輸入和輸出結(jié)果,使用 JavaFX Script 來(lái)求值。具體見(jiàn) 代碼清單 15。
清單 15. Java 應(yīng)用中嵌入 JavaFX Script 的示例
import static java.lang.System.out;
class CalculationException extends Exception {
public CalculationException(String message) {
super(message);
}
}
public class Main {
private static ScriptEngine engine = getScriptEngine();
public static void main(String[] args) {
out.println("Enter the expression after the >, " +
"enter 'q' to exit. Spaces are not allowed.");
out.print(">");
Scanner sc = new Scanner(System.in);
try {
while (sc.hasNext()) {
String input = sc.next();
if ("q".equals(input.trim())) {
out.println("Exit!");
break;
}
try {
out.println(calculate(input));
} catch (CalculationException ce) {
out.println(ce.getMessage());
}
out.print(">");
}
} finally {
sc.close();
}
}
private static ScriptEngine getScriptEngine() {
ClassLoader loader = Thread.currentThread().getContextClassLoader();
ScriptEngineManager manager = new ScriptEngineManager(loader);
ScriptEngine engine = manager.getEngineByExtension("fx");
return engine;
}
private static String calculate(String expression)
throws CalculationException {
if (engine == null) {
throw new CalculationException(
"Can not find the JavaFX script engine!");
}
try {
Object result = engine.;
return result == null ? "" : result.toString();
} catch (ScriptException e) {
throw new CalculationException("Wrong expression!");
}
}
}
需要說(shuō)明的是,必須將 OpenJFX 編譯器中的 javafxc.jar 這個(gè)包添加進(jìn)來(lái),否則會(huì)出現(xiàn)找不到ScriptEngine的錯(cuò)誤。這是由于 JavaFX Script 的引擎是由 javafxc.jar 包中的 com.sun.tools.javafx.script.JavaFXScriptEngineFactory 類來(lái)實(shí)現(xiàn)的。
本站文章除注明轉(zhuǎn)載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉(zhuǎn)載,但請(qǐng)務(wù)必注明出處、不得修改原文相關(guān)鏈接,如果存在內(nèi)容上的異議請(qǐng)郵件反饋至chenjj@fc6vip.cn
文章轉(zhuǎn)載自:IBM