
JavaFX Scene Builder 與 FXML
Oracle為加速JavaFX圖形介面的開發,推出JavaFX Scene Builder,如同NetBeans或JBuilder IDE一般,藉由拖曳的方式配置物件,待完成配置之後,並儲存成FXML格式檔案,此檔案以XML描述物件配置,再交由JavaFX程式處理,因此可減少直接以JavaFX撰寫配置物件程式的困難度。 FXML類似於Java SE 5.0新增的Synth Look and Feel,其最大特色在於以XML描述物件配置與樣式,JavaFX程式在執行階段只需讀取此FXML檔案,則可設定JavaFX的物件配置,且配置或樣式改變,也僅需修改FXML檔案,不需修改JavaFX程式。JavaFX Scene Builder具有以下特色:
JavaFX Scene Builder可自Oracle網站下載。下載檔案名為javafx_scenebuilder-1_1-windows.msi的JavaFX Scene Builder之後,直接執行安裝程式即可完成安裝。 以JavaFX Scene Builder配置物件與建立FXML檔案的步驟如下: Step 1:執行JavaFX Scene Builder,其中JavaFX Scene Builder包含以下之區域:
下圖JavaFX Scene Builder的開始畫面: Step 2:點選「File」→「New」選單建立新檔,接著選擇物件如標籤,並拖曳至內容面板中,此時屬性面板將顯示標籤的所有屬性如標籤文字、字型、文字顏色、對齊方式等。接著依序以相同的方式拖曳物件至內容面板,此時階層面板將顯示所有物件的樹狀關係,其中最上層的容器為GridPane,如下圖所示: Step 3:待完成物件配置之後,點選「File」→「Save」選單儲存為FXML檔案,其內容如下所示: <?xml version="1.0" encoding="UTF-8"?> <?import java.lang.*?> <?import java.net.*?> <?import javafx.geometry.*?> <?import javafx.scene.control.*?> <?import javafx.scene.layout.*?> <?import javafx.scene.text.*?> <GridPane alignment="CENTER" styleClass="root" hgap="10.0" vgap="10.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2" fx:controller="javafxapplication.JavaFXController"> <padding> <Insets bottom="25.0" left="25.0" right="25.0" top="25.0" /> </padding> <Text id="welcome-text" text="Welcome to JavaFX" GridPane.columnIndex="0" GridPane.columnSpan="2" GridPane.rowIndex="0" /> <Label text="User Name:" GridPane.columnIndex="0" GridPane.rowIndex="1" /> <TextField GridPane.columnIndex="1" GridPane.rowIndex="1" /> <Label text="Password:" GridPane.columnIndex="0" GridPane.rowIndex="2" /> <PasswordField fx:id="passwordField" GridPane.columnIndex="1" GridPane.rowIndex="2" /> <HBox alignment="BOTTOM_RIGHT" spacing="10.0" GridPane.columnIndex="1" GridPane.rowIndex="4"> <Button fx:id="button" text="Login" /> </HBox> </GridPane> 依照以上的步驟則完成以JavaFX Scene Builder配置物件與建立FXML檔案,上述FXML內容對應於以下的JavaFX程式:
import javafx.geometry.*; import javafx.scene.control.*; import javafx.scene.layout.*; import javafx.scene.text.*; ... GridPane gridpane = new GridPane(); gridpane.setAlignment(Pos.CENTER); gridpane.setHgap(10); gridpane.setVgap(10); gridpane.setPadding(new Insets(25, 25, 25, 25)); Text text = new Text("Welcome to JavaFX"); text.setId("welcome-text"); gridpane.add(text, 0, 0, 2, 0); gridpane.add(new Label("User Name:"), 0, 1); gridpane.add(new TextField(), 1, 1); gridpane.add(new Label("Password:"), 0, 2); PasswordField passwordfield = new PasswordField(); passwordfield.setId("passwordField"); gridpane.add(passwordfield, 1, 2); Button button = new Button("Login"); button.setId("button"); HBox hbox = new HBox(); hbox.setAlignment(Pos.BOTTOM_RIGHT); hbox.setSpacing(10); hbox.getChildren().add(button); gridpane.add(hbox, 1, 4); ... 接著將FXML檔案與JavaFX程式置於同一目錄,並以javafx.fxml.FXMLLoader類別的load()方法將FXML檔案的內容載入至JavaFX程式中,由於在JavaFX Scene Builder中設定最上層的容器為GridPane類別,因此載入FXML內容之後,需轉換為GridPane: try { // 載入FXML內容並轉換為GridPane GridPane fxmlRoot = (GridPane) FXMLLoader.load( getClass().getResource("JavaFXApplication.fxml")); Scene scene = new Scene(fxmlRoot); primaryStage.setTitle("JavaFX Hello World"); primaryStage.setScene(scene); // Show Stage primaryStage.show(); } catch (IOException ex) { System.out.println(ex.toString()); } ... 為避免因變更最上層容器而需要修改原JavaFX程式,因此亦可將載入FXML內容轉換為Parent抽象類別,如此不論最上層容器為何,均不需修改JavaFX程式: try { // 載入FXML內容並轉換為Parent Parent fxmlRoot = FXMLLoader.load( getClass().getResource("JavaFXApplication.fxml")); Scene scene = new Scene(fxmlRoot); primaryStage.setTitle("JavaFX Hello World"); primaryStage.setScene(scene); // Show Stage primaryStage.show(); } catch (IOException ex) { System.out.println(ex.toString()); } ... 由於FXML已處理所有的物件配置,因此JavaFX程式變得更為精簡。此外,FXML可搭配事件處理,首先建立一處理事件的Controller類別,並將此Controller類別與FXML檔案置於同一目錄,例如: package javafxapplication; import java.net.URL; import java.util.ResourceBundle; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.fxml.FXML; import javafx.fxml.Initializable; import javafx.scene.control.Button; /** * Controller class */ public class JavaFXController implements Initializable { @FXML Button button; /** * Initializes the controller class. */ @Override public void initialize(URL location, ResourceBundle resources) { if (button != null) { button.setOnAction(new EventHandler() { @Override public void handle(ActionEvent e) { System.out.println("Hello World"); } }); } } } 接著在JavaFX Scene Builder的屬性面板中,設定最上層容器的Controller類別為上述自定之類別,當點選物件如按鈕時,則以此自定的Controller類別處理物件的事件,如下圖所示: 【執行結果】 除了處理事件的Controller類別之外,FXML支援CSS設定物件樣式,首先將CSS樣式定義於CSS檔案中,並將此CSS檔案與FXML檔案置於同一目錄,例如: .background { -fx-background-image: url("images/javafx.jpg"); -fx-background-repeat: repeat; -fx-background-color: linear-gradient(#38424b 0%, #1f2429 20%, #191d22 100%), linear-gradient(#20262b, #191d22), radial-gradient(center 50% 0%, radius 100%, rgba(114,131,148,0.9), rgba(255,255,255,0)); } .top-segment { -fx-background-color: rgba(255, 255, 255, 0.05); -fx-border-color: transparent transparent rgb(255, 255, 255, 0.08) transparent, transparent transparent rgb(0, 0, 0, 0.5) transparent; -fx-border-width: 1, 1.5; -fx-border-insets: -1, 0; } .title { -fx-font-size: 16; } .label { -fx-font-family: "Verdana"; -fx-font-size: 12; -fx-text-fill: rgb(162, 21, 35, 1); -fx-effect: dropshadow(one-pass-box , rgb(0, 0, 0, 0.6), 0, 0, 0, 1); } .button .text { -fx-effect: dropshadow(one-pass-box, rgb(0, 0, 0, 0.8), 0, 0, 0, -1); } .button { -fx-background-color: rgb(255, 255, 255, 0.08), rgb(0, 0, 0, 0.8), #090a0c, linear-gradient(#4a5661 0%, #1f2429 20%, #1f242a 100%), linear-gradient(#242a2e, #23282e), radial-gradient(center 50% 0%, radius 100%, rgba(135,142,148,0.9), rgba(255,255,255,0)); -fx-background-radius: 7, 6, 5, 4, 3, 5; -fx-background-insets: -3 -3 -4 -3, -3, 0, 1, 2, 0; -fx-font-family: "Verdana"; -fx-text-fill: blue; -fx-text-fill: linear-gradient(white, #d0d0d0); -fx-padding: 10 20 10 20; } .button:focused, .button:hover { -fx-background-color: rgb(255, 255, 255, 0.08), rgb(0, 0, 0, 0.8), #090a0c, linear-gradient(#4a5661 0%, #1f2429 20%, #1f242a 100%), linear-gradient(#3f4950, #23282e), radial-gradient(center 50% 0%, radius 100%, rgba(135,142,148,0.9), rgba(255,255,255,0)); } .text-field { -fx-background-color: rgb(255, 255, 255, 0.3), linear-gradient(rgb(0, 0, 0, 0.5), rgb(0, 0, 0, 0.8) 50%), rgb(218, 226, 224); -fx-background-insets: 0 0 -1 0, 0, 1.5; -fx-background-radius: 6, 5, 4; -fx-padding: 6 10 4 10; -fx-effect: innershadow(gaussian, rgb(0, 0, 0, 0.8), 5, 0, 0, 2 ); -fx-font-family: "Verdana"; } .text-field:focused { -fx-prompt-text-fill: rgb(128,128,128); -fx-background-color: rgb(235, 235, 235, 0.5), rgb(0, 0, 0, 0.4), rgb(255, 255, 255); } 接著在JavaFX Scene Builder的屬性面板中,設定最上層容器GridPane的Stylesheets為上述之CSS檔案,並設定GridPane的Style Class為CSS檔案中所定義的background,如下圖所示: 以此類推,依序點選各物件並設定其Style Class,如此則完成以CSS設定物件樣式,其中JavaFX程式完全不需任何修改。 【執行結果】 【參考資料】 [1] Java Official Web Site |