2014年2月21日 星期五

JavaFX Event (1) Introduction

欲建立JavaFX程式與使用者間的互動,需處理物件的事件,所謂事件 (Event) 是指當物件其狀態改變時所觸發產生的相關動作,例如按下滑鼠按鍵、滑鼠拖曳、按下鍵盤按鍵等,均會觸發其相對應的事件。

首先回顧Java處理事件的程式架構。

在Java AWT與Java Swing中,處理事件的方式有兩種,第一種方式為實作處理事件的Listener介面,各Listener介面提供處理事件的方法。其次為處理事件的類別,並分為Event類別與Adapter抽象類別,以定義物件所產生的事件。

以實作Listener介面為例,程式需實作介面所提供的全部方法,不論是否使用到,均需全部實作於程式中,若需處理某一事件,則將Listener介面所提供的方法內容加以覆寫 (Override)。此外,Listener介面需以下列方法處理:
  • addXXXListener():註冊事件的Listener,以處理物件所產生的相關事件。
  • getXXXListeners():取得物件所註冊的Listener,並以陣列回傳所註冊的所有相關事件。
  • removeXXXListener():移除物件所註冊的事件Listener。
以下為以JFrame類別實作MouseListener介面以處理滑鼠事件的程式架構:


import java.awt.*;
import java.awt.event.*;

import javax.swing.*;

import javax.swing.event.*;

// 實作MouseListener介面

public class JavaEventDemo extends javax.swing.JFrame 
  implements MouseListener {

  // 建構函式

  public JavaEventDemo() {
    ...  
    // 註冊MouseListener
    this.addMouseListener(this);
  }

  // 實作MouseListener介面的方法

  public void mouseClicked(MouseEvent e) {...}
  public void mouseEntered(MouseEvent e) {...}
  public void mouseExited(MouseEvent e) {...}
  public void mousePressed(MouseEvent e) {...}
  public void mouseReleased(MouseEvent e) {...}
  ...  
}


在實作Listener介面時,即使未使用到該事件的方法,仍需將介面所提供的方法全部描述一遍,並將方法的內容以空白表示,欲處理事件則覆寫該介面的方法。

除了實作介面之外,另一種處理事件的方法為事件類別,並分為Event類別與Adapter抽象類別,以定義不同物件所產生的事件。Event類別繼承自java.util.EventObject類別,並對應於Listener介面,例如以MouseListener介面為例,其Event類別則為MouseEvent

其次,Adapter抽象類別為Listener介面相對應的類別,同樣提供與Listener介面一樣的方法,但不同的是,使用上是以繼承Adapter抽象類別,但僅處理所發生的方法,而未發生的方法則不需重新描述一遍,因此可精簡程式。以下是以Inner Class的方式使用Adapter類別:


import java.awt.*;
import java.awt.event.*;

import javax.swing.*;

import javax.swing.event.*;

public class JavaEventDemo extends javax.swing.JFrame


  // 建構函式

  public JavaEventDemo() {
    ...
    // 以Inner Class的方式使用滑鼠的Adapter類別
    this.addMouseListener(new MouseInputAdapter() {
      // 處理滑鼠事件
      public void mousePressed(MouseEvent e) {
        ...
      }
    });
  }
}


以下為繼承Adapter抽象類別的程式架構:


import java.awt.*;
import java.awt.event.*;

import javax.swing.*;

import javax.swing.event.*;

public class JavaEventDemo extends javax.swing.JFrame

  // 建構函式
  public JavaEventDemo() {
    ...
    // 以自訂MouseAdapter類別建立MouseListener
    this.addMouseListener(new MyMouseAdapter());
    ...
  }
}

// 繼承MouseAdapter

class MyMouseAdapter extends MouseInputAdapter {

  // 建構函式

  public MyMouseAdapter() {
    ...
  }
  // 處理滑鼠事件
  public void mousePressed(MouseEvent e) { 
    ...
  }
}


接著說明JavaFX處理事件的程式架構。

JavaFX簡化處理事件的方式,不像Java以不同的Listener介面處理各類事件,JavaFX僅以javafx.event.EventHandler介面處理各類事件,且介面僅提供handle()方法

至於如何以單一的EventHandler介面處理各類事件呢?這點可說是JavaFX的一項重大改變。

JavaFX以事件類型 (Event Type) 定義各類事件,其基礎類別為javafx.event.Event,繼承自Event類別的事件類別分別如下所示,其中較特殊的是手勢與觸控事件,由於目前大部份裝置均支援觸控螢幕 (Touch Screen) 與觸控板 (Touch Pad),因此JavaFX增加處理多點觸控 (Multi-Touch) 的事件類別:
  • ActionEvent:動作事件。
  • ContextMenuEvent:快顯選單事件。
  • DragEvent:拖曳事件,適用於滑鼠與觸控裝置。
  • GestureEvent:手勢事件,適用於觸控裝置。
  • InputEvent:輸入事件。
  • InputMethodEvent輸入方法事件。
  • KeyEvent按鍵事件。
  • MediaErrorEvent多媒體錯誤事件。
  • MouseEvent滑鼠事件。
  • MouseDragEvent滑鼠拖曳事件,有別於DragEvent。
  • RotateEvent旋轉事件,適用於觸控裝置。
  • ScrollEvent捲動事件,適用於滑鼠與觸控裝置。
  • SwipeEvent滑動事件,適用於觸控裝置。
  • TouchEvent觸控事件,適用於觸控裝置。
  • WebEventWeb Engine事件。
  • WindowEvent視窗事件。
  • WorkerStateEventWorker狀態改變時之事件。
  • ZoomEvent縮放事件,適用於觸控裝置。
JavaFX處理事件的第一種方式是以物件的setOnXXX()方法設定處理事件的Event Handler函式,其語法如下,其中[Event_TYPE]為上述之事件類別:


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


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


Button button = new Button();

button.setOnAction(new EventHandler<ActionEvent>() {

  @Override public void handle(ActionEvent e) {
    ...
  }
});


以按鈕的滑鼠移動事件為例,其設定方法為setOnMouseMoved()、事件類別為MouseEvent


Button button = new Button();

button.setOnMouseMoved(new EventHandler<MouseEvent>() {

  @Override public void handle(MouseEvent e) {
    ...
  }
});


由上述說明可以瞭解,JavaFX以單一EventHandler介面與不同事件類別的組合處理事件,相較於Java以實作處理事件的Listener介面、或使用Event類別與Adapter抽象類別,JavaFX處理事件的方式更為簡單。

除了上述語法之外,亦可以建立類別的方式處理,以按鈕的動作事件為例:


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

EventHandler onActionEventHandler = new EventHandler<ActionEvent>() {

  @Override public void handle(ActionEvent e) {
    ...
  }
};


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


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


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


Button button = new Button();

button.addEventHandler(ActionEvent.ACTION,

  new EventHandler<ActionEvent>() {
    @Override public void handle(ActionEvent e) {
      ...
    }
  }
);


除了上述語法之外,亦可以建立類別的方式處理,以按鈕的動作事件為例:


Button button = new Button();
button.addEventHandler(ActionEvent.ACTION, onActionEventHandler);
...

EventHandler onActionEventHandler = new EventHandler<ActionEvent>() {

  @Override public void handle(ActionEvent e) {
    ...
  }
};


JavaFX處理事件的第三種方式是以物件的addEventFilter()方法註冊事件的Event Filter,其語法如下,與Event Handler幾乎一樣,其中[eventType]代表事件類型、[Event_TYPE]為前述之事件類別:


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


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


Button button = new Button();

button.addEventFilter(ActionEvent.ACTION,

  new EventHandler<ActionEvent>() {
    @Override public void handle(ActionEvent e) {
      ...
    }
  }
);


除了上述語法之外,亦可以建立類別的方式處理,以按鈕的動作事件為例:


Button button = new Button();
button.addEventFilter(ActionEvent.ACTION, onActionEventFilter);
...

EventHandler onActionEventFilter = new EventHandler<ActionEvent>() {

  @Override public void handle(ActionEvent e) {
    ...
  }
};


【參考資料】

[1] 黃嘉輝,深入研究JavaFX 2。
[2] 黃嘉輝,深入研究Java Swing。
[3] Java Official Web Site:http://www.oracle.com/technetwork/java/index.html
[4] JavaFX:http://www.oracle.com/technetwork/java/javafx
[5] JavaFX 2.2 API Specification.
[6] Java Platform, Standard Edition 7 API Specification.

© Chia-Hui Huang

沒有留言:

張貼留言