JavaFX Scene Builder 與 FXML by 黃嘉輝 | CodeData
top

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具有以下特色:

  • 以拖曳的方式配置物件。
  • 以所見即所得(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網站下載。下載檔案名為javafx_scenebuilder-1_1-windows.msi的JavaFX Scene Builder之後,直接執行安裝程式即可完成安裝。

以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的開始畫面:

Scene Builder

Step 2:點選「File」→「New」選單建立新檔,接著選擇物件如標籤,並拖曳至內容面板中,此時屬性面板將顯示標籤的所有屬性如標籤文字、字型、文字顏色、對齊方式等。接著依序以相同的方式拖曳物件至內容面板,此時階層面板將顯示所有物件的樹狀關係,其中最上層的容器為GridPane,如下圖所示:

Scene Builder

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類別處理物件的事件,如下圖所示:

Scene Builder

【執行結果】

Scene Builder

除了處理事件的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,如下圖所示:

Scene Builder

以此類推,依序點選各物件並設定其Style Class,如此則完成以CSS設定物件樣式,其中JavaFX程式完全不需任何修改。

【執行結果】

Scene Builder

【參考資料】

[1] Java Official Web Site
[2] JavaFX
[3] NetBeans
[4] JavaFX Scene Builder
[5] JavaFX 2.2 API Specification.
[6] Java Platform, Standard Edition 7 API Specification.

後續 >> JavaFX 程式架構

分享:
按讚!加入 CodeData Facebook 粉絲群

留言

留言請先。還沒帳號註冊也可以使用FacebookGoogle+登錄留言

關於作者

黃嘉輝副教授,目前任職於國立臺北商業大學企業管理學系,喜歡寫程式,特別愛Java,範例可參考教學網站

熱門論壇文章

熱門技術文章