2014年1月23日 星期四

JavaFX Scene Builder

Oracle為加速JavaFX圖形介面的開發,推出JavaFX Scene Builder,目前版本為1.1,如同NetBeans與JBuilder IDE一般,藉由拖曳的方式配置物件,待完成配置之後,並儲存成FXML格式檔案,此檔案以XML描述物件配置,再交由JavaFX程式處理,因此可減少直接以JavaFX撰寫配置物件程式的困難度。

FXML類似於Java S.E. 5.0新增的Synth Look and Feel,其最大特色在於以XML描述物件配置與樣式,JavaFX程式在執行階段只需讀取此FXML檔案,則可設定JavaFX的物件配置,且配置或樣式改變,也僅需修改FXML檔案,不需修改JavaFX程式。JavaFX Scene Builder具有以下特色:
  • 以拖曳的方式配置物件。
  • 以所見即所得(What You See is What You Get)的方式編輯物件配置。
  • 與NetBeans IDE、Eclipse、IntelliJ IDEA等緊密整合。
  • 自動產生FXML程式碼。
  • 支援CSS(Cascading Style Sheets Styling)設定物件樣式。
  • 支援跨平臺如Microsoft Windows、Mac OS X、UNIX、Linux等作業系統。
JavaFX Scene Builder可自Oracle網站下載。以Microsoft Windows 7作業系統為例,其安裝步驟如下:

Step 1:下載檔案名為javafx_scenebuilder-1_1-windows.msi的JavaFX Scene Builder之後,直接執行安裝程式。以下為JavaFX Scene Builder的安裝說明,點選「下一步」按鈕:
Step 2:接著選擇安裝JavaFX Scene Builder的目錄,預設目錄為C:\Program Files\Oracle\JavaFX Scene Builder 1.1\,點選「安裝」按鈕進行安裝程序
Step 3:安裝JavaFX Scene Builder所需檔案:
Step 4:安裝完成:
以JavaFX Scene Builder配置物件與建立FXML檔案的步驟如下:

Step 1:執行JavaFX Scene Builder,其中JavaFX Scene Builder包含以下之區域:
  • 物件面板 (Library Panel):位於JavaFX Scene Builder左上方,用以顯示JavaFX Scene Builder所有的JavaFX GUI物件,並分成Containers、Controls、Popup Controls、Menu Content、Miscellaneous、Shapes與Charts等類別。
  • 階層面板 (Hierarchy Panel):位於JavaFX Scene Builder左下方,用以顯示物件的樹狀階層關係。
  • 內容面板 (Content Panel):位於JavaFX Scene Builder中間區域,可藉由拖曳的方式自物件面板拖曳物件至內容面板以配置物件。
  • 屬性面板 (Property Panel):位於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>


接著將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<ActionEvent>() {
        @Override public void handle(ActionEvent e) {
          System.out.println("Hello World");
        }
      });
    }
  }
}


接著在JavaFX Scene Builder的屬性面板中,設定最上層容器的Controller類別為上述自定之類別,當點選物件如按鈕時,則以此自定的Controller類別處理物件的事件,如下圖所示:


【參考資料】

[1] 黃嘉輝,深入研究JavaFX 2。
[2] 黃嘉輝,深入研究Java Swing。
[5] NetBeans: http://netbeans.org
[7] JavaFX 2.2 API Specification.
[8] Java Platform, Standard Edition 7 API Specification.

© Chia-Hui Huang

沒有留言:

張貼留言