除了使用Java原生的Code產生圖形介面外,JavaFX還支援使用XML來描述圖形介面(這好像已經成為一種趨勢了)。甚至Oracle還提供了一種叫作JavaFX Scene Builder的工具,讓開發人員製作圖形介面完全不用寫到程式。



JavaFX Scene Builder

JavaFX Scene Builder可以到Oracle的網站上下載安裝,之後就可以拿來排介面了!

拿之前登入表單的例子,使用JavaFX Scene Builder花不到五分鐘就可以做好下面的介面!之後存檔成fxml檔案就可以套入在JavaFX內啦!

使用FXML開發JavaFX的專案要注意到,若程式需要存取到圖形元件的狀態,需設定ID欄位,這樣才可以使用node的lookup或是lookupAll方法,以CSS名稱(#ID名稱)的字串方式,來找出該node底下符合此ID名稱的sub node。如果圖形元件需要處理事件,可以設定onAction欄位,由FXML去指向事件觸發後要執行的方法名稱,但此方法需要用到@FXML的annotation來實作。另外,@FXML也可以抓到FXML元件的fxID。要使用@FXML annotation的話,必須要替FXML指定Controller(指到JavaFX應用程式內的某個類別)。

套入FXML

JavaFX提供FXMLLoader.load()方法,可以將FXML讀入,並轉換成Node。

撰寫程式

LoginJavaFX.java

package javafxlogin;

import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class LoginJavaFX extends Application{

    @Override
    public void start(Stage primaryStage) throws IOException{
	Parent root = FXMLLoader.load(getClass().getResource("Login.fxml"));

	//用讀進來FXML的作為Scene的root node
	Scene scene = new Scene(root, 300, 275);
	primaryStage.setScene(scene);
	
	//顯示Stage
	primaryStage.setTitle("登入");
	primaryStage.show();
    }
}

FXController.java

package javafxlogin;

import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.text.Text;

public class FXController {

    @FXML
    private Text actiontarget;

    @FXML
    protected void submit(ActionEvent event) {
	actiontarget.setText("登入成功");
    }
}

Login.fxml

<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>

<GridPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="275.0" prefWidth="300.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="javafxlogin.FXController">
    <columnConstraints>
	<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
	<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
    </columnConstraints>
    <rowConstraints>
	<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
	<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
	<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
	<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
	<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
	<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
	<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
    </rowConstraints>
    <children>
	<Text strokeType="OUTSIDE" strokeWidth="0.0" text="歡迎">
	    <font>
		<Font size="20.0" />
	    </font>
	</Text>
	<Label text="帳號:" GridPane.rowIndex="1" />
	<TextField GridPane.columnIndex="1" GridPane.rowIndex="1" />
	<Label text="密碼:" GridPane.rowIndex="2" />
	<PasswordField GridPane.columnIndex="1" GridPane.rowIndex="2" />
	<HBox alignment="BOTTOM_RIGHT" prefHeight="100.0" prefWidth="200.0" GridPane.columnIndex="1" GridPane.rowIndex="4">
	    <children>
		<Button  mnemonicParsing="false" onAction="#submit" text="登入" />
	    </children>
	</HBox>
	<Text fx:id="actiontarget" id="actiontarget" fill="#ff4529" strokeType="OUTSIDE" strokeWidth="0.0" GridPane.columnIndex="1" GridPane.rowIndex="6" />
    </children>
    <padding>
	<Insets bottom="25.0" left="25.0" right="25.0" top="25.0" />
    </padding>
</GridPane>

執行結果: