FXML是JavaFX 2.0提供的新技術。你可能會問“什麼是FXML?”,“對我來說有什麼用?”。 FXML是一種在JavaFX應用程序中定義用戶界面的,基於XML的聲明性標記語言。FXML非常適合用來靜態佈局,如表單、控件和表格。使用FXML,您還可以通過腳本動態地構建佈局。
FXML的優勢之一是基於XML,是大多數開發人員所熟悉的,尤其是Web開發人員和使用其他RIA平臺的開發人員。另一個優點是,FXML是不是編譯語言,你不需要重新編譯代碼就可看到您所做的更改。FXML的第三個優勢是很容易看到應用程序的場景結構圖。反過來,這更容易完成開發團隊成員之間合作的用戶界面。
要比較JavaFX和FXML,看看如圖1所示的用戶界面。構成這個應用程序的場景圖包括一個頂部區域和一箇中心區域的邊框式佈局,每個區域都包含一個標籤 。
圖1 邊框窗格的簡單例子
例1 JavaFX場景圖
BorderPane border=new BorderPane();
Label toppanetext =new Label(“Page Title”);
border.setTop(toppanetext);
Label centerpanetext =new Label(“Some data here”);
border.setCenter(centerpanetext);
例2 FXML場景圖
<BorderPane>
<top>
<Label text="Page Title"/>
</top>
<CENTER>
<Label text="Some data here"/>
</CENTER>
</BorderPane>
展示FXML優勢的最好辦法是使用一個例子。本教程介紹瞭如何創建如圖2所示的登錄用戶界面。
圖2 登錄用戶界面
在開始之前,先來熟悉一下登錄用戶界面,它如圖 3所示。用戶界面使用了一個包含兩個區域的邊框佈局 。頂部區域包含一個內有“Login Example”字樣並附圖像的文本的堆式佈局。中心區域包含一個內有標籤,文本框,密碼框和按鈕的網格式佈局。
圖3 登錄用戶界面的佈局
要創建這樣的登錄用戶界面,您將完成以下任務:
準備工作
本教程使用NetBeans IDE。請確保您使用的NetBeans IDE版本支持JavaFX 2.0。有關詳細信息,請參閱系統需求。
要完成本教程,你應該熟悉如何使用JavaFX構建一個用戶界面。如何使用場景圖來完成任務的知識非常有用,因爲層次結構的FXML與JavaFX場景圖的結構是非常相似的。
設置項目
第一步是在NetBeans IDE中建立JavaFX項目。
1. 從“ 文件”“菜單中選擇“新建項目”。
2. 在JavaFX的類別目錄中選擇基於JavaFX FXML的應用程序 。單擊“下一步” 。
3. 以FXMLExample命名項目,然後單擊“ 完成 “ 。NetBeans IDE會打開一個有三個文件的項目:FXMLExample.java,Sample.fxml和Sample.java。
4. 右鍵點擊這個鏈接 (fx_boxback.jpg)下載背景爲淡藍色漸變的圖像並保存到您的桌面作爲程序的背景。然後將它從桌面拖動到源包下的fxmlexample目錄下 。
設置應用基礎信息
每個FXML應用程序得了必須包括一些JavaFX代碼。這些代碼是創舞臺和場景並啓動應用程序代碼所要求的最小的代碼單元。
打開FXMLExample.java文件 ,刪除由Netbeans IDE生成的代碼,例 3中的代碼替換它 。
例如3 FXMLExample.java
package fxmlexample;
import java.util.ResourceBundle;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class FXMLExample extends Application {
@Override
public void start(Stage stage)throws Exception {
stage.setTitle("FXMLExample");
Parent root =FXMLLoader.load(getClass().getResource("fxml_example.fxml"),
ResourceBundle.getBundle("fxmlexample.fxml_example"));
Scene scene = new Scene(root, 226, 264);
stage.setScene(scene);
stage.show();
}
public static void main(String[]args) {
launch(args);
}
}
作爲一個JavaFX程序員,上面創建場景和舞臺並啓動應用程序的代碼對你應該是很熟悉的。然而,這一行是涉及到FXML:Parent root= FXMLLoader.load(getClass().getResource(“fxml_example.fxml”),ResourceBundle.getBundle(“fxmlexample.fxml_example”));
FXMLLoader.load()方法從資源文件fxml_example.fxml中加載對象的層次結構,並把它分配到的名爲root變量。getResources參數增加一個資源包到用戶界面中的字符串中,這會使本地化的任務更容易。在接下來的兩節,會再次回到的資源包屬性文件,並創建FXML源文件 。
總體而言,一個場景對象被創建,並賦到場景圖的根變量 。在FXML標記的根元素,成爲場景圖的根。
創建屬性文件
最好的做法是在屬性文件中指定用戶界面的文本字符串顯示內容。按照以下的步驟來創建一個登錄用戶界面的屬性文件。
1.在“項目”窗口中,右鍵單擊源包下的fxmlexample文件夾,然後選擇“新建”,再選擇“其他”。
2.在新建文件對話框,單擊“其他”,然後再單擊“屬性文件”,再次單擊“下一步”。
3.輸入fxml_example 作爲文件名 ,然後單擊完成。IDE將打開一個擴展名. properties的文件。
4.輸入資源名稱和它們的值,如例4所示。
例4 fxml_example.properties中的資源名稱
loginExample=Login Example
signIn=Sign in:
userName=Username:
password=Password:
submit=Submit
創建FXML文件
現在創建一個名爲fxml_example.fxml 的FXML文件,插入XML聲明和import語句。
1.在“項目”窗口中,右鍵單擊fxmlexample文件夾下的Sample.fxml,並選擇 “ 重命名”。
2.輸入文件fxml_example並點擊“確定”。
3.打開fxml_example文件,刪除NetBeans IDE生成的代碼,並用例5中的代碼替換它。
例5聲明和import語句
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.*?>
<?import javafx.scene.image.*?>
FXML所有文件必須以XML聲明開始。它定義了XML的版本(1.0)和類型的編碼(UTF - 8)。
就像在JavaFX中一樣,類的名字可以是全名(包括包名),或者也可以使用import語句導入,如例5所示。如果你願意,你可以使用與類相關的導入 。
定義一個邊境窗格佈局
接下來,開始構建用戶界面。在導入語句後,插入邊框式窗格佈局,如例6所示。
例6邊境窗格佈局
<BorderPane fx:controller="fxmlexample.FXMLExampleController"
xmlns:fx="http://javafx.com/fxml">
<top>
</top>
<center>
</center>
</BorderPane>
在這個例子中,場景圖的根是BorderPane佈局類,它定義兩個區域,頂部和中心。
FX:controller屬性標識了一個控制器文件,它必須爲該文件的根元素。在本教程的後續部份您將瞭解更多有關控制器的內容。
Xmlns:fx =“http://javafx.com/fxml”屬性將命名空間映射到http://javafx.com/fxml鏈接。您必須在FXML的根元素中聲明命名空間。這個屬性使您能夠使用FXML標籤對應的JavaFX API元素。
在圖像的堆放文本
現在,窩在堆棧的頂部區域的邊界窗格佈局窗格中 。堆棧窗格包含重疊的圖像,在圖 4所示的標籤 。
圖4邊框窗格的頂部區域,包括堆式窗格
堆式窗格的代碼如例7所示。將<top> 和</top>之間的代碼插入到標籤之間。
例7在圖像的堆放文本
<StackPane>
<children>
<ImageView>
<image>
<Image url="@fx_boxback.jpg"/>
</image>
</ImageView>
<Labeltext="%loginExample" style="-fx-font: NORMAL 20Tahoma;"/>
</children>
</StackPane>
StackPane佈局將它的子節點放置在一個堆內,每新增加一個結點,它就會被放置在前一個結點的上面。這種佈局模型提供了一種簡單的方法在圖像上覆蓋文本。
<children>將子結點添加到場景圖,這是類似於使用JavaFX中的getChildren()方法。
Image類加載與FXML文件位於相應目錄的fx_boxback.jpg文件,ImageView類將圖像顯示在屏幕上。
標籤類有一個文本屬性被設爲資源名loginExample。在FXML中,資源名稱通過%來識別。加載時,FXML啓動器用它的值“Longin Example”取代loginExample資源名稱。
請注意,FXML定義樣式的方法與在JavaFX 代碼中定義CSS樣式時使用setStyle()的方法類似 。在例7中,標籤類使用樣式標籤來設置字體的爲正常,字體爲宋體,大小爲20點。
另一種定義樣式的方法是爲場景增加樣式表,這和JavaFX一樣。使用樣式表,可以更容易地在後期給你的應用程序重新設定樣式。請參閱本教程使用樣式表的部份來了解更多有關爲FXMLExample應用程序設定樣式表的信息。
添加網格佈局和控件
下一步,在邊框窗格的中心區域放置一個網格佈局。您可以使用網格佈局在屏幕在縱向和橫向放置控件,如在圖5所示。
圖5網格窗格在邊框窗格中心區
例8中包括網格佈局的代碼 。將它們插入到<CENTER>和</CENTER>標記之間 。
例8有控件的網格佈局
<GridPane alignment="top_center" hgap="8"vgap="8"
style="-fx-padding:40 0 0 0">
<children>
<Labeltext="%signIn"
style="-fx-font: NORMAL 14 Tahoma;"
GridPane.columnIndex="0" GridPane.rowIndex="0"/>
<Labeltext="%userName"
GridPane.columnIndex="0"GridPane.rowIndex="1"
labelFor="$usernameField"/>
<TextFieldfx:id="usernameField" prefColumnCount="10"
GridPane.columnIndex="1" GridPane.rowIndex="1"/>
<Labeltext="%password"
GridPane.columnIndex="0" GridPane.rowIndex="2"
labelFor="$passwordField"/>
<PasswordFieldfx:id="passwordField" prefColumnCount="10"
GridPane.columnIndex="1" GridPane.rowIndex="2"
onAction="#handlePasswordFieldAction"/>
<Buttonfx:id="submitButton" text="%submit"
GridPane.columnIndex="1" GridPane.rowIndex="3"
onAction="#handleSubmitButtonAction"/>
<Labelfx:id="buttonStatusText"
GridPane.columnIndex="1" GridPane.rowIndex="4"
style="-fx-text-fill: #ff0000;"/>
</children>
</GridPane>
現在的代碼應該看起來很熟悉,但有些新的屬性必須解釋。GridPane.columnIndex和GridPane.rowIndex屬性對應GridPane類setColumnIndex()和setRowIndex()方法。網格的行和列編號從零開始。例如,第一個Label控件的位置是(0,0),這意味着它是在第一行的第一列,或說成左上角。prefColumnCount屬性用於TextField和PasswordField控件,來將首選列寬設爲10。
爲元素分配的fx:id的值會在文檔的命名空間中創建一個變量,你可以在後面的代碼中引用。變量引用使用$符號來識別。在例8中,TextField的ID是usernameField,這個ID被分配到Label控件的labelFor屬性,將會設置TextField的標籤。
請注意,PasswordField和Button控件會有一個onAction屬性。數字符號#會引用自定義方法,這些方法會在下一節創建 FXMLExampleController類時被定義 。
雖然FXML是一種定義應用程序用戶界面結構的簡便方法,但是它沒有提供一個方法來實現應用程序的行爲。這種行爲必須通過在下一節中描述的Java代碼或在《使用腳本語言》中描述的腳本語言來實現。
添加一個按鈕事件
現在,創建一個控制器來處理按鈕的事件。這個例子演示瞭如何將FXML標記與Java編寫的事件處理程序關聯起來。
1. 在“項目”窗口中,右鍵單擊fxmlexample文件夾下的Sample.java,然後選擇“重構”,再選擇“重命名”。
2. 輸入FXMLExampleController並點擊“重構”。
3. 打開FXMLExampleController.java文件,刪除NetBeans IDE生成的代碼,用例9中的代碼替換它。
例9 FXMLExampleController.java
package fxmlexmaple
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
public class FXMLExampleController {
@FXML private LabelbuttonStatusText;
@FXML protected voidhandleSubmitButtonAction(ActionEvent event) {
buttonStatusText.setText("Submit button pressed");
}
@FXML protected voidhandlePasswordFieldAction(ActionEvent event) {
buttonStatusText.setText("Enter key pressed");
}
}
@FXML註釋用來標識已在FXML中標記過的非公有控制器的成員屬性和事件處理方法。主要針對Java編程語言,你也可以使用其他編譯語言,比如Scala來實現一個控制器。
現在,您可以運行應用程序。測試在應用程序的這兩個編輯框中輸入文本,然後點擊“提交”。
完整的源代碼,你可以下載FXMLExample.zip。
使用腳本語言
作爲用Java代碼來創建事件處理的替代方案,你可以用任何兼JSR223腳本引擎的腳本語方來創建處理程序。例如JavaScript、Groovy、Jython和Clojure。按如下的步驟編輯FXML文件以外便在登錄例子中使用JavaScript。
1.在文件fxml_example.fxml中,在XML聲明之後添加JavaScript聲明:<?language JavaScript?>
2.在按鈕標記中,改變函數的名稱,調用看起來如下:OnAction =“handleSubmitButtonAction(event);”
3.更新上PasswordField的標記,看起來像這樣:OnAction =“handlePasswordFieldAction(event);”
4.從BorderPane標記中移除fx:controller屬性,在一個<script>標籤下添加JavaScript函數,如例10所示。
例10FXML中的JavaScript
<BorderPane xmlns:fx="http://javafx.com/fxml">
<fx:script>
function handleSubmitButtonAction(){
buttonStatusText.setText("Calling the JavaScript");
}
functionhandlePasswordFieldAction(event) {
buttonStatusText.text = "More JavaScript";
}
</fx:script>
另外,您可以把JavaScript函數放在一個外部文件中(如fxml_example.js),然後將它像這樣包括進來:<fx:script source="fxml_example.js"/>
如果你正在考慮在FXML中使用一種腳本語言,請注意,有的IDE可能不支持通過步進方式調試腳本代碼。
使用樣式表
作爲使用內聯樣式的替代方案,你可以爲場景添加一個樣式表,然後爲節點設置樣式類。按照下列步驟來創建一個樣式表,它定義了網格窗格和標籤控件的風格。
1.創建樣式表。
a. 在“項目”窗口中,右鍵單擊源包目錄下fxmlexample文件夾,然後選擇“ 新建”,再選擇“其他”。
b. 在新建文件對話框,選擇“其他”,然後選擇“層疊樣式表”並單擊“下一步”。
c. 輸入fxmlstylesheet,然後單擊完成。
d. 刪除NetBeans IDE生成代碼,用例11中的代碼替換它。
實例11的內容樣式表
@charset "utf-8";
/*
Document : FXMLstylesheet.css
*/
.grid-pane {
-fx-padding: 80 0 0 0;
}
.label {
-fx-font: normal 36px Tahoma;
}
2.打開FXMLExample.java文件,在stage.show()這一行前包含這段代碼來爲場景增加樣式表:scene.getStylesheets().add(“fxmlexample /fxmlstylesheet.css”);
3.在fxml_example.fxml文件中增加樣式類。
a. 爲<String>元素添加一個import語句:<?import java.lang .* ?>
b. 用例12的代碼替換GridPane標記。
12例爲網格窗格的樣式類
<GridPane alignment="top_center" hgap="8"vgap="8">
<styleClass>
<Stringfx:value="grid-pane"/>
</styleClass>
c. 用例13的代碼更換“Sign In”標籤的標記。
<Labeltext="%signIn"
GridPane.columnIndex="0" GridPane.rowIndex="0">
<styleClass>
<Stringfx:value="label"/>
</styleClass>
</Label>
當您爲對像使用<styleClass>標記時,樣式應用於同一類的所有實例,除非類有自己的內聯樣式。因此,當您運行FXMLExample應用程序時,範例13的樣式不僅對登錄標籤起作用,而且對用戶名和密碼標籤也同樣起作用。這個樣式對LoginExample標籤不起作用,因爲它的內聯樣式覆蓋了樣式表 。
總結
下面是在本教程中的信息摘要:
- FXML是JavaFX的組成部分。這是另一種創建JavaFX應用程序用戶界面的語言。
- FXML是基於XML的。
- FXML文件作爲普通JavaFX項目的一部份包括在classpath中,不會被編譯。
- FXML的層次結構與JavaFX場景圖的結構密切相關。
- 一個最好的編碼實踐是以<? XML version=”1.0” encodeing=”utf-8”>作爲一個 FXML 文件的開始。
- FXML命名空間必須定義在頂層組件或佈局中,以便FXML標籤可以在整個文件範圍內被訪問。例如:<rootElement XMLNS:FX =“http://javafx.com/fxml”>
- 通過提取資源包字符串,FXML可以在加載時進行本地化。資源替換通過%操作符標識。
- 在FXML中定義樣式類似於在Java代碼中通過setStyle()方法定義CSS樣式。您可以使用內聯樣式 或創建樣式表。
- 爲元素分配fx:id值以便在文檔的命名空間中創建一個變量,它可以被後面的代碼引用。變量參考通過$符號來引用。
- 除了Java,FXML還支持其他編譯語言,比如Scala,來實現控制器。
- FXML支持任何JSR223兼容的腳本引擎。這些語言包括JavaScrip、Groovy、Jython和Clojure。