JavaFX 是 Sun 推出的一套基於 Java 技術的產品家族。 JavaFX Script 可以用來高效的創建富媒體和交互性很強的應用。 JavaFX 是 Adobe Flex 和 Microsoft Silverlight 的有力競爭者。本文通過具體的實例介紹了 JavaFX Script 語言本身的一些高級特性並討論了 JavaFX Script 中的一些高級話題,包括創建復雜的用戶界面、實現動畫效果、JavaFX Script 應用的部署和在一個獨立的 Java 應用程序中嵌入 JavaFX Script 等。
JavaFX Script 語言簡介
JavaFX 是 Sun 推出的一套基於 Java 技術的產品家族,其目的是為從桌面機、移動設備、機頂盒到藍光光盤等提供一致的用戶體驗。 JavaFX 目前包含 JavaFX Script 和 JavaFX Mobile 。 JavaFX Script 可以用來高效的創建富媒體和交互性很強的應用。 JavaFX 是 Adobe Flex 和 Microsoft Silverlight 的有力競爭者。本文通過具體的例子介紹了 JavaFX Script 語言本身的一些高級特性。這些特性包括塊表達式、范圍(Range)表達式、序列的修改、觸發器(Trigger)和數據綁定。另外還結合具體的應用,討論了 JavaFX Script 中的一些高級話題,包括創建復雜的用戶界面、實現動畫效果、JavaFX Script 應用的部署和在一個獨立的 Java 應用程序中嵌入 JavaFX Script 等。
目前 JavaFX Script 語言本身在不斷的變化之中,本文中對 JavaFX Script 語法的說明和實例,均基於 JavaFX Script 在 2008 年 7 月 21 號的版本。開發環境采用 NetBeans 6.1,並安裝 JavaFX Script 插件。請從 參考資源 中下載相關的工具。
JavaFX Script 高級特性
下面具體介紹 JavaFX Script 語言的一些高級特性。
塊表達式
JavaFX Script 中的塊表達式是包含在 {} 中的一系列用分號分隔的語句。如果塊表達式中的最後一個語句是表達式的話,那麼這個塊表達式的值就是最後這個表達式的值;否則該塊表達式的值是 Void 類型。塊表達式適合於那些在代碼中只出現一次的計算邏輯。因為只出現一次,可以不用把這樣的邏輯封裝在一個 function 中。而塊表達式又可以把這部分邏輯的代碼與其它部分區別開來。在 代碼清單 1 中,對於薪水的計算邏輯被封裝在一個塊表達式中。
清單 1. 塊表達式示例
var baseSalary = 10000;
var salary = {
12 * (baseSalary + 1000) + 2 * baseSalary
};
System.out.println(salary);
范圍表達式
熟悉其他動態語言,如 Python、Ruby 和 Groovy 的人對於范圍(Range)表達式可能並不陌生。 JavaFX Script 也引入了同樣的范圍表達式,可以用來定義一個序列。不過在使用方式與其他語言有些不同。
在 JavaFX Script 中可以通過 [number1..number2] 來定義一個序列。這裡需要注意的是兩個邊界數字 number1 和 number2 都是包含在序列裡面的。如 [0..5] 包含 0,1,2,3,4,5 這六個數字。這點和 Ruby 裡面的 number1...number2 和 Groovy 裡面的 number1..number2 是一樣的。默認情況下,范圍中的數字之間的間隔是 1,可以通過在 number2 後面加上顯式的 step 來聲明間隔。比如 [0..9 step 3] 包含的數字是 0,3,6,9 。
當 number1 大於 number2 的時候,可以通過指定值為負數的 step 來生成降序排列的序列。如 [5..0 step -1] 包含的數字是 5,4,3,2,1,0 ;如果不指定 step,或是 step 的值為正數的話,生成的序列實際上是空的。如 [5..0] 是個空的序列。
序列的修改
JavaFX Script 提供了兩個強大的操作符 insert 和 delete 來對序列進行操作。
insert 語句的語法如 代碼清單 2 中所示。
清單 2. insert 語句的語法
insert x into seq
insert x before seq[idx]
insert x after seq[idx]
從 代碼清單 2 列出的語法中可以看到,insert 語句可以往序列中的指定位置插入新元素。使用 insert x into seq 會把 x 添加到序列末尾。而 insert x before seq[idx] 和 insert x after seq[idx] 則分別可以把新元素插入到 seq[idx] 所對應的元素的前面和後面。
delete 的語法如 代碼清單 3 中所示。
清單 3. delete 語句的語法
delete seq
delete x from seq
delete seq[idx]
delete seq[a..b]
在 代碼清單 3 列出的四種用法中,第一種會刪除整個序列;第二種和第三種都會刪除指定元素,不同的是第二種需要指定元素的值,而第三種需要指定其序號;第四種是用來刪除序列中給定范圍之內的全部元素的。
觸發器
JavaFX Script 提供類似 SQL 中觸發器的機制來處理數據的變化。如果在某個屬性上聲明了觸發器,那麼當它的值發生變化的時候,觸發器就會被觸發,預先定義的邏輯就會被執行。代碼清單 4 中給出了觸發器的一個實例。
清單 4. 觸發器示例
class Person {
attribute address : String
on replace oldAddress = newAddress {
System.out.println(" 地址已經從 {oldAddress} 改為 {newAddress} 。 ");
};
}
var person = Person {
address : " 北京市朝陽區 "
};
person.address = " 北京市海澱區 ";
從 代碼清單 4 中可以看到,當屬性 address 的值發生改變時,會輸出相應的提示信息。該屬性的舊值和新值都可以得到,並在相應的處理邏輯代碼中使用。觸發器不僅可以用於單值屬性,也可以用於序列上。代碼清單 5 和 代碼清單 6 中給出的兩個例子分別演示了如何在序列中插入和刪除元素之後得到通知。
清單 5. 序列中插入新元素的觸發器
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. 序列中刪除元素的觸發器
class Student {
attribute courses : String[]
on replace oldCourses = newCourses {
if (sizeof newCourses == 0) {
System.out.println(" 你已經成功退選了課程 {oldCourses} 。 ");
}
}
}
var student = new Student();
insert " 網絡信息體系結構 " into student.courses;
insert " 編譯原理 " into student.courses;
delete student.courses[0];
數據綁定
JavaFX Script 中,屬性初始化的時候,可以通過 bind 將屬性的值和某個表達式綁定起來,當該表達式所引用的對象發生變化時,該屬性的值也會自動更新。方法也可以通過 bound 來設成綁定的。以 代碼清單 7 為例,方法 getPercent 在其內部的變量的值發生改變的時候,會自動重新求值。屬性 currentValue 的值的改變首先使得方法 getPercent 的值發生改變,然後再使得 percent 的值發生變化。這一切都是自動的。
清單 7. 數據綁定示例
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 語言本身的一些高級特性,下面將以實例的方式討論 JavaFX Script 開發中的幾個重要的主題。
創建復雜用戶界面
用過 Swing 的人可能都有個感覺,那就是用 Swing 創建用戶界面的時候,不僅編寫起來麻煩,代碼也比較冗長。使用 JavaFX Script,可以幫助你更快更簡單的創建用戶界面。 JavaFX Script 簡化用戶界面的創建的能力主要體現在三個方面:
聲明式創建圖形用戶界面(GUI)組件 程序員可以在代碼中以聲明的方式編寫 GUI 組件,這些 GUI 組件的層次結構就反映了實際的用戶界面的布局。聲明式的方式大大減少了創建用戶界面所需要的代碼量。程序員只需要看到代碼的組織結構,就可以想象出實際的運行效果。 數據綁定和增量式求值 數據綁定和增量式求值使得組件的創建和配置變得更加容易,應用本身的數據和 GUI 組件可以自動同步。比如在用戶界面上有個標簽(javafx.ext.swing.Label)用來顯示雇員的名字,只需要將標簽的 text 屬性綁定到雇員數據的 name 屬性上。當雇員數據發生變化的時候,該標簽會自動更新。 觸發器 觸發器使得當某個屬性的值發生變化的時候,可以執行相應的處理邏輯。這非常類似 Java Bean 中的 PropertyChangeListener 和 PropertyChangeEvent 的組合。但是觸發器的創建和使用更加簡單。
在 JavaFX Script 中使用 Swing 的 GUI 組件是很容易的。 JavaFX Script 在 javafx.ext.swing 包中提供了很多常用的 Swing 組件的封裝。這些組件可以在 JavaFX Script 代碼中直接以聲明式的方式使用。另外一些復雜的組件,如 JTable 和 JTree,目前在 JavaFX Script 中還不可以直接使用。在這種情況下,需要繼承 javafx.ext.swing.Component 類並實現該類的抽象方法 createJComponent()。該方法返回一個 JComponent 對象。
下面以一個具體的實例來說明如何創建復雜用戶界面。該應用是一個 RSS 訂閱源(Feed)的閱讀器,它可以解析 OPML 文件並在左側以一個樹形結構來顯示所有的訂閱源。當點擊某個訂閱源時,可以在右側看到該訂閱源的內容。顯示所有訂閱源的是左側的 OmplViewer,顯示訂閱源內容的是右側的 FeedViewer。該應用的截圖見 圖 1。
圖 1. RSS 訂閱源閱讀器
由於 RSS 訂閱源閱讀器的代碼比較多,在本文中將只介紹其中的重點,完整的代碼請 下載。
繼承javafx.ext.swing.Component
在上面提到,一些復雜的 Swing 組件,目前需要通過繼承 javafx.ext.swing.Component 的方式來使用。在 RSS 訂閱源閱讀器中,左側顯示所有訂閱源的組件是 JTree。類 OpmlViewer 繼承自 javafx.ext.swing.Component,並實現其createJComponent()方法,該方法創建了一個JTree 對象,並包裝在一個 JScrollPane 中。該類中的其它代碼都與 JTree 對象交互。具體見 代碼清單 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);
}
}
觸發器的使用
類 OpmlViewer 有一個屬性 opmlFilePath 用來表示 OPML 文件的路徑。當該屬性的值發生改變的時候,OpmlViewer 就需要顯示該 OPML 文件中的所有訂閱源。這是通過在屬性 opmlFilePath 上創建一個觸發器來實現的。具體見 代碼清單 9。
清單 9. OpmlViewer 中的觸發器使用
public attribute opmlFilePath : String on replace
oldPath = newPath {
if (newPath != null and not "".equals(newPath.trim())) {
setOpmlFilePath(newPath);
}
}
數據綁定的使用
數據綁定在這個應用中主要用來協調左側的 OmplViewer 和右側的 FeedViewer。FeedViewer 的屬性 feedUrl 綁定到 OmplViewer 的屬性 selectedFeedUrl。這樣當用戶選擇了某個訂閱源的時候,OmplViewer 的屬性 selectedFeedUrl 的值會發生變化,FeedViewer 的屬性 feedUrl 的值也會隨之變化。FeedViewer 就會去加載新的訂閱源內容了。具體見 代碼清單 10。
清單 10. OpmlView 和 FeedViewer 之間的數據綁定
var opmlViewer = OpmlViewer {
opmlFilePath : "c:\\google-reader-subscriptions.xml",
hmax : 200
hmin : 100
};
var feedViewer = FeedViewer {
feedUrl : bind opmlViewer.selectedFeedUrl
};
上面介紹了如何在 JavaFX Script 中創建復雜的用戶界面,下面將涉及 JavaFX Script 中一個有趣的話題,那就是實現動畫效果。
創建動畫
使用 JavaFX Script 來創建動畫是一件非常容易的事情。 JavaFX Script 所采用的動畫方式叫“關鍵幀動畫(key frame animation)”。這種動畫是通過一系列的場景的轉換來完成的,而場景則是由特定時間點上的關鍵幀來表示的。程序員只需要以聲明式的方式定義這些關鍵幀,系統會自動的完成剩下的工作。“關鍵幀動畫”又分成兩種,離散型和插值型。兩者的區別在於:對於後者,系統會用特定的插值函數來計算每個關鍵幀之間的中間狀態。 JavaFX Script 中的動畫主要是依靠 javafx.animation.Timeline、javafx.animation.KeyFrame、javafx.animation.KeyValue 這三個類來完成的。
這三個類的基本說明如下:
javafx.animation.Timeline Timeline 可以理解為動畫的時間軸。所有的動畫都是圍繞一個時間軸來運行的。 javafx.animation.KeyFrame KeyFrame 是時間軸上的關鍵幀。每個關鍵幀都與時間軸上的某個時間點關聯起來。每個關鍵幀可以包含一系列的 KeyValue 和子時間軸,以及一個動作(action)。子時間軸的起始時間點是相對於其父時間軸的。從而使得時間軸可以嵌套起來,形成層次結構。動作則是當關鍵幀對應的時間點到達的時候,所執行的一段代碼。 javafx.animation.KeyValue KeyValue 給出了某個屬性在當前關鍵幀中的值,以及一個用來計算在之前的關鍵幀中該屬性的值與當前值之間的中間值的方法。關於 KeyValue 的具體介紹請看下節。
KeyValue 的用法
下面用一個例子來具體說明 KeyValue 的用法,見 代碼清單 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 中創建了一個無限運行的 Timeline,該 Timeline 包含 3 個關鍵幀,所關聯的時間點分別是 1 秒、1.5 秒和 2 秒。在這 3 個關鍵幀所關聯的時間點到達的時候,都會執行 output 方法,該方法會打印出 simpleVar 的值。需要說明的是在第三個關鍵幀上,通過 values 聲明了 simpleVar 在該關鍵幀中的值是 200,並且是通過線性插值(Interpolator.LINEAR)的方式來計算中間值。因此,在 1 秒和 1.5 秒的關鍵幀中,simpleVar 的值就是根據線性插值的方式計算出來的。
動畫實例
下面通過一個實例來說明如何使用 JavaFX Script 來編寫動畫。在這個動畫實例中,將演示地球自轉和月球圍繞地球的轉動。動畫的演示效果見 圖 2 所示。需要說明的是 圖 2 中的地球和月球的大小以及月球的運行軌道均為示意。
圖 2. 地球自轉和月球圍繞地球運轉的動畫
該動畫的源代碼如代碼清單 12所示。
清單 12. 地球和月球運行示意動畫的源代碼
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();
代碼中創建了兩個 Timeline,一個用來表示地球的自轉,另外一個用來表示月球圍繞地球的轉動。表示地球自轉的動畫使用的是離散型“關鍵幀動畫”。該 Timeline earthTimeline 包含 7 個關鍵幀,每個幀的間隔是 300 毫秒。當每個幀所關聯的時間點到達的時候,所執行的動作是將 currentEarthImage 的值設成該幀對應的地球的一張圖片。當 currentEarthImage 的值發生改變的時候,ImageView 就會顯示那張圖片。
表示月球圍繞地球轉動的動畫使用的是插值型“關鍵幀動畫”。該 Timeline moonTimeline 的效果是使得代表月球的圖片按照一個圓形來變換位置。該 Timeline 包含 8 個關鍵幀,分別表示圓周上的 8 個位置。當每個幀所關聯的時間點到達的時候,所執行的動作是 moonX 和 moonY 的值設成計算出來的月球的圖片在窗口中的位置。通過 Transform.translate(moonX, moonY) 這樣的一個變換來改變圖片的位置。插值型“關鍵幀動畫”指的是,程序中聲明了 8 個關鍵幀,系統會自動按照指定的函數來計算圖片在中間狀態的位置。這裡使用的插值函數是線性插值。
值得注意的是,如果使用 代碼清單 12 中的方式,運行起來之後,月球的圖片的運動並不是一個圓形,而是一個正八邊形。這是由於以線性插值的方式計算出來的中間狀態的位置與實際需要的弧形有較大的偏差。而目前 JavaFX Script 並沒有提供弧形的插值函數。所以一個更好的選擇是使用離散型“關鍵幀動畫”,並且提供更多的關鍵幀,這樣使得月球圖片的運行軌跡更加平滑。代碼清單 13 中給出了新的關鍵幀的生成方法。
清單 13. 更平滑的關鍵幀生成方法
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 個關鍵幀,每個幀對應的 moonX 和 moonY 的值都是通過計算得出來的。使用了上面的 36 個關鍵幀之後,運行起來可以看到月球圖片的更好的動畫效果。
在討論完 JavaFX Script 中的動畫之後,下面將討論如何部署 JavaFX Script 應用。
部署 JavaFX Script 應用
在完成 JavaFX Script 應用的編寫和調試之後,就可以部署該應用了。 JavaFX Script 的應用的部署方式主要有兩種,分別是使用 Java Web Start 和使用 Open JavaFX 編譯器。下面具體介紹這兩種部署方式。
使用 Java Web Start
Java Web Start 是從 JRE 5.0 開始被引入到 Java 運行環境(JRE)中來的。它使得可以從 Web 下載和運行 Java 程序。當本機安裝了 5.0 及以上版本的 JRE 後,如果通過浏覽器訪問內容類型(Content type)是 application/x-java-jnlp-file 的 URL 時,Java Web Start 會自動運行,並下載相應的 JNLP 文件,來啟動 Java 應用。
JNLP 的文件內容可以參考 代碼清單 14。該 JNLP 文件可以用來啟動前面提到的 JavaFX Script 應用“ RSS 訂閱源閱讀器”。
清單 14. “ RSS 訂閱源閱讀器”的 JNLP 文件
<?xml version="1.0" encoding="utf-8"?>
<jnlp
spec="1.5+"
codebase="http://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="http://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>
需要說明的是,在使用 Java Web Start 時,所有的 jar 包都必須經過數字簽名。可以使用 JDK 中自帶的 jarsigner 這個工具。
使用 OpenJFX 編譯器
OpenJFX 是 JavaFX 開源社區中的一個孵化項目,它的作用是將 JavaFX Script 編譯成 JVM 上可以直接運行的 class 文件(字節碼)。從 參考資源 中下載了 OpenJFX 的編譯器之後,通過運行 javafxc 命令就可以將一個 JavaFX Script 文件編譯成一系列 Java class 文件。再使用 javafx 命令就可以運行該應用。
在獨立的 Java 應用中嵌入 JavaFX Script
JDK 6.0 中引入了 JSR 223(Scripting 框架),使得可以在 JVM 上執行 JavaScript、Python、Ruby 和 JavaFX Script 等動態語言。如果你的 JavaFX Script 是作為一個獨立的 Java 應用的一部分的話,使用 JSR 223 可以很容易將 JavaFX Script 嵌入其中。
下面以一個簡單計算器的例子來說明如何使用 JSR 223 來將 JavaFX Script 嵌入 Java 應用中。該簡單計算器可以接受用戶輸入的算術表達式並將計算結果告訴用戶。算術表達式可以包含加、減、乘、除和括號等。如果使用 Java 來計算算術表達式的值話,需要對表達式進行分析,拆分成可以識別的符號,再進行運算。而如果使用 JavaFX Script 的話,只需要將整條表達式交給 JavaFX 引擎去求值即可。因此,整個程序由 Java 來處理用戶的輸入和輸出結果,使用 JavaFX Script 來求值。具體見 代碼清單 15。
清單 15. Java 應用中嵌入 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.eval(expression);
return result == null ? "" : result.toString();
} catch (ScriptException e) {
throw new CalculationException("Wrong expression!");
}
}
}
需要說明的是,必須將 OpenJFX 編譯器中的 javafxc.jar 這個包添加進來,否則會出現找不到ScriptEngine的錯誤。這是由於 JavaFX Script 的引擎是由 javafxc.jar 包中的 com.sun.tools.javafx.script.JavaFXScriptEngineFactory 類來實現的。
來源:http://www.ibm.com/developerworks/cn/java/j-lo-javafx/