【JDK8】迎接 JavaFX 8(1) by 黃嘉輝 | CodeData
top

【JDK8】迎接 JavaFX 8(1)

分享:

【JDK8】JavaScript 引擎 Nashorn 之 jjs << 前情

2014年3月18日Oracle正式釋出Java SE Development Kit 8,應 CodeData 的邀請,特別整理JavaFX 8與JavaFX 2之比較,作為【JDK8】系列之一。

移除各物件對應的Builder類別

JavaFX 8移除各物件對應的Builder類別,最初建議移除的提案,可以參考 Proposal: Deprecate Builders 的內容。

這裡回顧一下JavaFX 2的Builder類別,Builder是JavaFX 2一個特殊功能與語法,以Button類別 (按鈕) 為例,其對應之Builder類別為ButtonBuilder,透過ButtonBuilder類別可精簡程式長度,但程式的撰寫方式與以往的Java程式不同。

ButtonBuilder類別的方法包括:

  • create():建立ButtonBuilder的實體 (Instance)。
  • build():以ButtonBuilder物件建立按鈕的實體,並回傳Button物件。
  • cancelButton():設定按鈕是否為取消按鈕,則設定按鈕的cancelButton屬性值,若為true,則為取消按鈕。
  • defaultButton():設定按鈕是否為預設按鈕,則設定按鈕的defaultButton屬性值,若為true,則為預設按鈕。

ButtonBuilder類別建立按鈕的程式架構如下,首先以create()方法建立ButtonBuilder的實體,最後再以build()方法以ButtonBuilder物件建立Button物件,其間並以上述方法設定按鈕的相關屬性,各方法可為任意順序或省略:

Button button = ButtonBuilder.create()
  .cancelButton(...)
  .defaultButton(...)
  .build();

請參考以下範例示範以ButtonBuilder類別建立按鈕:

Image image = new Image(
  ButtonDemo.class.getResourceAsStream("images/dukeswing.gif"));

Scene scene = SceneBuilder.create()
  .width(250)
  .height(250)
  .root(
    FlowPaneBuilder.create()
      .hgap(5)
      .vgap(5)
      .padding(new Insets(5, 5, 5, 5))
      .alignment(Pos.CENTER)
      .children(
        ButtonBuilder.create() // 建立一般按鈕
          .text("Plain Text")  // 設定按鈕文字
          .prefWidth(100)      // 設定按鈕最佳寬度
          .prefHeight(20)      // 設定按鈕的最佳高度
          .build(), 
        ButtonBuilder.create()                  // 建立圖像按鈕
          .text("Image Button")
          .graphic(new ImageView(image))        // 設定按鈕所使用的圖像
          .contentDisplay(ContentDisplay.TOP)   // 設定圖像與文字間的相對位置
          .prefWidth(100)
          .build(), 
        ...
      )
      .build()
  )
  .build();
...

【執行結果】
5-1

Lambda Expression

Lambda Expression為Java S.E. 8.0新增的一項語言描述方式,其語法如下:

(argument) -> (body)

Lambda Expression是一種匿名函式 (Anonymous Function),沒有Method Declaration (方法宣告),亦不需要Modifier (修飾詞) 與Return Value Declaration (回傳值宣告) 等,因此程式更為精簡。

以下是一些簡單的例子:

(int a, int b) -> {return a + b;}

() -> System.out.println("...");

(String value) -> {return value;}

我們可以將Lambda Expression運用於JavaFX 8的事件 (Event) 處理上,讓處理事件的方式更為簡單。在這之前,先來回顧JavaFX 2處理事件的程式架構。

JavaFX 2處理事件的方式,不像以往Java以不同的Listener介面處理各類事件,JavaFX 2僅以EventHandler介面處理各類事件,且介面僅提供handle()方法,並以事件類型 (Event Type) 定義各類事件,其基礎類別為javafx.event.Event,繼承自Event類別的事件類別分別如下,其中較特殊的是手勢與觸控事件:

  • ActionEvent:動作事件。
  • ContextMenuEvent:快顯選單事件。
  • DragEvent:拖曳事件,適用於滑鼠與觸控裝置。
  • GestureEvent:手勢事件,適用於觸控裝置。
  • InputEvent:輸入事件。
  • InputMethodEvent:輸入方法事件。
  • KeyEvent:按鍵事件。
  • MediaErrorEvent:多媒體錯誤事件。
  • MouseEvent:滑鼠事件。
  • MouseDragEvent:滑鼠拖曳事件,有別於DragEvent
  • RotateEvent:旋轉事件,適用於觸控裝置。
  • ScrollEvent:捲動事件,適用於滑鼠與觸控裝置。
  • SwipeEvent:滑動事件,適用於觸控裝置。
  • TouchEvent:觸控事件,適用於觸控裝置。
  • WebEvent:Web Engine事件。
  • WindowEvent:視窗事件。
  • WorkerStateEvent:Worker狀態改變時之事件。
  • ZoomEvent:縮放事件,適用於觸控裝置。

JavaFX 2處理事件的第一種方式是以物件的setOnXXX()方法設定處理事件的Event Handler函式,其語法如下,其中[Event_TYPE]為上述之事件類別:

[object].setOnXXX(new EventHandler() {
  @Override public void handle([Event_TYPE] e) {
    ...
  }
});

以按鈕的動作事件為例,其設定Event Handler函式的方法為setOnAction()、事件類別為ActionEvent

Button button = new Button();

button.setOnAction(new EventHandler() {
  @Override public void handle(ActionEvent e) {
    ...
  }
});

亦可使用建立類別的方式處理:

Button button = new Button();
button.setOnAction(onActionEventHandler);
...

EventHandler onActionEventHandler = new EventHandler() {
  @Override public void handle(ActionEvent e) {
    ...
  }
};

透過Java S.E. 8.0的Lambda Expression可將上述程式精簡如下,省略EventHandler介面的描述:

Button button = new Button();

button.setOnMouseMoved((ActionEvent e) -> {
  ...
});

或以建立類別的方式處理:

Button button = new Button();
button.setOnAction(onActionEventHandler);
...

EventHandler onActionEventHandler = 
  (EventHandler)(ActionEvent e) -> {
  ...
};

更進一步可依賴編譯器的型態推斷 (Type Inference),讓程式更精簡:

Button button = new Button();

button.setOnAction(event -> {
  ...
});

JavaFX 2處理事件的第二種方式是以物件的addEventHandler()方法註冊事件的Event Handler,其語法如下,其中[eventType]代表事件類型、[Event_TYPE]為前述之事件類別:

[object].addEventHandler([eventType], new EventHandler() {
  @Override public void handle([Event_TYPE] e) {
    ...
  }
});

以按鈕的動作事件為例,其事件類型為ActionEvent.ACTION、事件類別為ActionEvent,註冊Event Handler的程式架構如下:

Button button = new Button();

button.addEventHandler(ActionEvent.ACTION,
  new EventHandler() {
    @Override public void handle(ActionEvent e) {
      ...
    }
  }
);

透過Lambda Expression可將上述程式精簡如下:

Button button = new Button();

button.addEventHandler(ActionEvent.ACTION, (ActionEvent e) -> {
  ...
};

JavaFX 2處理事件的第三種方式是以物件的addEventFilter()方法註冊事件的Event Filter,其語法如下,與Event Handler幾乎一樣:

[object].addEventFilter([eventType], new EventHandler() {
  @Override public void handle([Event_TYPE] e) {
    ...
  }
});

以按鈕的動作事件為例,註冊Event Filter的程式架構如下:

Button button = new Button();

button.addEventFilter(ActionEvent.ACTION,
  new EventHandler() {
    @Override public void handle(ActionEvent e) {
      ...
    }
  }
);

透過Lambda Expression可將上述程式精簡如下:

Button button = new Button();

button.addEventFilter(ActionEvent.ACTION, (ActionEvent e) -> {
  ...
};

Modena主題樣式

JavaFX 2預設外觀主題 (Theme) 稱為Caspian,例如以下為選單之Caspian主題樣式:

8-4

JavaFX 8新增Modena主題,可使用javafx.application.Application抽象類別新增的setUserAgentStylesheet()方法設定,其中參數為以下之主題樣式:

  • STYLESHEET_CASPIAN:Caspian主題。
  • STYLESHEET_MODENA:Modena主題。

例如:

// 設定Modena主題
setUserAgentStylesheet(STYLESHEET_MODENA);

// 設定Caspian主題
setUserAgentStylesheet(STYLESHEET_CASPIAN);

以下範例以單選選單項目 (Radio Menu Item) 控制主題樣式,可分別選取Modena與Caspian主題。

【執行結果】
ModenaCaspian

JavaFX Scene Builder 2.0

Oracle為加速JavaFX圖形介面的開發,2014/05/13 Oracle正式發表JavaFX Scene Builder 2.0,可至以下網址下載:

http://goo.gl/rYah4S

JavaFX Scene Builder如同NetBeans與JBuilder IDE一般,藉由拖曳的方式配置物件,待完成配置之後,並儲存成FXML格式檔案,此檔案以XML描述物件配置,再交由JavaFX程式處理,因此可減少直接以JavaFX撰寫配置物件程式的困難度。

JavaFX Scene Builder 2.0新增JavaFX Theme預覽功能,可點選「Preview」→「JavaFX Theme」選單選擇不同的主題,包括:

  • Modena (FX8).
  • Modena Touch (FX8).
  • Modena High Contrast – Black on White (FX8).
  • Modena High Contrast – White on Black (FX8).
  • Modena High Contrast – Yellow on Black (FX8).
  • Caspian (FX2).
  • Caspian Embedded (FX2).
  • Caspian Embedded QVGA (FX2).

待完成物件配置之後,點選「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="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"
  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>

【參考資料】
[1] 黃嘉輝,深入研究JavaFX 2。
[2] 黃嘉輝,JavaFX遊戲程式設計。
[3] Java Official Web Site:http://www.oracle.com/technetwork/java/index.html
[4] JavaFX:http://www.oracle.com/technetwork/java/javafx
[5] JavaFX 8.0 API Specification.
[6] Java Platform, Standard Edition 8 API Specification.

後續 >> 【JDK8】迎接 JavaFX 8(2)

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

留言

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

關於作者

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

熱門論壇文章

熱門技術文章