前面介紹了JavaFX的常見控件用法,雖然JavaFX控件比起AWT與Swing要好用些,可是同樣經過代碼編寫控件界面,並無提升什麼開發效率。要想瀏覽界面的展現效果,都必須運行測試程序才能觀看,即便只是微調控件的大小,也得從新運行程序查看效果,顯然既費時又費力。爲此JavaFX提供了另外一種給界面排版的方式,沒必要使用Java代碼堆砌控件,而是利用FXML文件開展界面佈局,同時藉助於idea的預覽功能,無需運行程序便可直接觀察FXML的佈局效果。所謂「FXML」意思是JavaFX專用的XML格式,它基於XML標準並加以擴展,每一個JavaFX控件均有對應的XML標籤,把這些蘊含控件的標籤組裝起來,便造成了一個窗口界面專屬的佈局文件。
舉個簡單的例子,如今準備畫登陸界面,包含用戶名輸入框、密碼輸入框,以及登陸按鈕,這些控件自上往下分紅三行排列。該界面預期的展現效果以下圖所示。html
假若徹底使用代碼實現以上的登陸界面,無疑要反覆地調整代碼並屢次執行程序,才能達到滿意的佈局效果。那麼採用FXML方式的話,能夠把與界面相關的控件元素剝離出來,改成在FXML文件中書寫XML標籤結構。好比上述登陸頁對應的FXML文件名叫login.fxml,其內容示例以下:java
<?import javafx.scene.layout.FlowPane?> <?import javafx.scene.layout.HBox?> <?import javafx.scene.control.Button?> <?import javafx.scene.control.Label?> <?import javafx.scene.control.TextField?> <?import javafx.scene.control.PasswordField?> <FlowPane xmlns:fx="http://javafx.com/fxml" alignment="center" hgap="5" vgap="5"> <HBox fx:id="hbUser" prefWidth="400" prefHeight="40"> <Label fx:id="labelUser" prefWidth="120" prefHeight="40" text="用戶名:" /> <TextField fx:id="fieldUser" prefWidth="280" prefHeight="40" /> </HBox> <HBox fx:id="hbPassword" prefWidth="400" prefHeight="40"> <Label fx:id="labelPassword" prefWidth="120" prefHeight="40" text="密 碼:" /> <PasswordField fx:id="fieldPassword" prefWidth="280" prefHeight="40" /> </HBox> <Button fx:id="btnLogin" prefWidth="400" prefHeight="40" text="登 錄" /> </FlowPane>
在idea中打開login.fxml,注意到該文件界面的左下角有兩個選項卡,一個叫「Text」,另外一個叫「Scene Builder」。當前打開的login.fxml展現爲文本內容,對應的正是「Text」選項,此時單擊右邊的「Scene Builder」選項,原先的文本內容迅速變爲一組可視化頁面,頁面中央呈現着login.fxml的預覽效果,正以下圖所示。程序員
原來fxml文件相似於html文件,儘管html文件內部充斥着各類文本標籤,但使用瀏覽器打開html文件總能看到排版精美的網頁;而idea自帶的Scene Builder承擔了fxml瀏覽器的角色,只要程序員修改了fxml文件的格式內容,切換至「Scene Builder」選項就能馬上看見修改後的界面效果,比起傳統的運行程序看效果的方式,Scene Builder的渲染速度要快得多。
回頭再看前述的login.fxml,它的文件內容分爲兩大塊,前面一塊形如「<?import ***?>」,其做用是導入指定包名路徑的控件,與Java代碼的import語句類似;後面一塊包含各級控件的嵌套結構,其標籤格式爲「<控件名稱 屬性列表></控件名稱>」,若是當前控件不存在下級控件,則它的標籤格式可簡化爲「<控件名稱 屬性列表 />」。依據login.fxml的標籤內容,可知該界面採起FlowPane流式窗格,且流式窗格擁有下列三類控件:
一、容納用戶名組件的水平箱子HBox,它的編號是hbUser。該箱子內部又有編號爲labelUser的用戶名標籤,以及編號爲fieldUser的用戶名輸入框;
二、容納密碼組件的水平箱子HBox,它的標識爲hbPassword。該箱子內部又有編號爲labelPassword的密碼標籤,以及編號爲fieldPassword的密碼輸入框;
三、編號爲btnLogin的登陸按鈕;
引入FXML佈局以後,Java代碼要改成從指定的fxml文件中加載界面,也就是將場景的建立過程改爲以下兩行代碼:瀏覽器
// 從FXML資源文件中加載程序的初始界面 Parent root = FXMLLoader.load(getClass().getResource("login.fxml")); Scene scene = new Scene(root, 410, 240); // 建立一個場景
因而繪製界面的JavaFX代碼縮小到了下面寥寥幾行:ide
//登陸窗口的程序入口(FXML佈局控件) public class LoginMain extends Application { @Override public void start(Stage stage) throws Exception { // 應用程序開始運行 stage.setTitle("登陸窗口"); // 設置舞臺的標題 // 從FXML資源文件中加載程序的初始界面 Parent root = FXMLLoader.load(getClass().getResource("login.fxml")); Scene scene = new Scene(root, 410, 240); // 建立一個場景 stage.setScene(scene); // 設置舞臺的場景 stage.setResizable(true); // 設置舞臺的尺寸是否容許變化 stage.show(); // 顯示舞臺 } public static void main(String[] args) { launch(args); // 啓動JavaFX應用,接下來會跳到start方法 } }
接着運行上面的LoginMain程序,彈出的登陸界面正如預期所示。佈局
JavaFX的絕大多數靜態控件,都能以單個標籤的形式添加到fxml之中,除了前面例子說起的流式窗格FlowPane、水平箱子HBox、按鈕Button、標籤Label、文本輸入框TextField、密碼輸入框PasswordField,還包括網格窗格GridPane、邊界窗格BorderPane、垂直箱子VBox、多行輸入框TextArea、複選框CheckBox、下拉框ComboBox等。然而單選按鈕RadioButton的添加方式別具一格,原因在於好幾個單選按鈕要構成一個按鈕小組,這樣才能讓同組的單選按鈕聯動起來。所以fxml得先聲明一個ToggleGroup標籤,並給它分配標籤編號,而後在RadioButton標籤後面添加toggleGroup屬性,指定加入前一步的ToggleGroup編號。操做單選按鈕的具體fxml片斷示例以下:測試
<HBox fx:id="hbType" prefWidth="400" prefHeight="40"> <Label fx:id="labelType" prefWidth="120" prefHeight="40" text="登陸類型:" /> <fx:define> <ToggleGroup fx:id="tgType" /> </fx:define> <RadioButton fx:id="rbPassword" prefWidth="140" prefHeight="40" toggleGroup="$tgType" text="密碼登陸" selected="true" /> <RadioButton fx:id="rbVerifycode" prefWidth="140" prefHeight="40" toggleGroup="$tgType" text="驗證碼登陸" /> </HBox>
固然,新來的RadioButton和ToggleGroup也要在fxml頭部添加如下的導入語句:ui
<?import javafx.scene.control.RadioButton?> <?import javafx.scene.control.ToggleGroup?>
把與單選按鈕有關的xml標籤補充到login.fxml,再另存爲新的fxml文件名叫login_with_flow.fxml,完整的文件內容以下所示:idea
<?import javafx.scene.layout.FlowPane?> <?import javafx.scene.layout.HBox?> <?import javafx.scene.control.Button?> <?import javafx.scene.control.Label?> <?import javafx.scene.control.TextField?> <?import javafx.scene.control.PasswordField?> <?import javafx.scene.control.RadioButton?> <?import javafx.scene.control.ToggleGroup?> <FlowPane xmlns:fx="http://javafx.com/fxml" alignment="center" hgap="5" vgap="5"> <HBox fx:id="hbType" prefWidth="400" prefHeight="40"> <Label fx:id="labelType" prefWidth="120" prefHeight="40" text="登陸類型:" /> <fx:define> <ToggleGroup fx:id="tgType" /> </fx:define> <RadioButton fx:id="rbPassword" prefWidth="140" prefHeight="40" toggleGroup="$tgType" text="密碼登陸" selected="true" /> <RadioButton fx:id="rbVerifycode" prefWidth="140" prefHeight="40" toggleGroup="$tgType" text="驗證碼登陸" /> </HBox> <HBox fx:id="hbUser" prefWidth="400" prefHeight="40"> <Label fx:id="labelUser" prefWidth="120" prefHeight="40" text="用戶名:" /> <TextField fx:id="fieldUser" prefWidth="280" prefHeight="40" /> </HBox> <HBox fx:id="hbPassword" prefWidth="400" prefHeight="40"> <Label fx:id="labelPassword" prefWidth="120" prefHeight="40" text="密 碼:" /> <PasswordField fx:id="fieldPassword" prefWidth="280" prefHeight="40" /> </HBox> <Button fx:id="btnLogin" prefWidth="400" prefHeight="40" text="登 錄" /> <Label fx:id="labelLoginResult" prefWidth="400" prefHeight="40" text="這裏顯示登陸結果" /> </FlowPane>
而後利用Scene Builder觀察login_with_flow.fxml的預覽界面,由下圖可見單選按鈕組合已經添加至登陸窗口的上方。code
接着修改LoginMain.java,將建立場景時加載的資源文件名改成login_with_flow.fxml,再從新運行測試程序,此時彈出的登陸界面以下圖所示:
比較Scene Builder的預覽界面,以及實際運行的窗口界面,整體而言二者大同小異,基本的佈局排列是吻合的。
更多Java技術文章參見《Java開發筆記(序)章節目錄》