首先回顧Java處理事件的程式架構。
在Java AWT與Java Swing中,處理事件的方式有兩種,第一種方式為實作處理事件的Listener介面,各Listener介面提供處理事件的方法。其次為處理事件的類別,並分為Event類別與Adapter抽象類別,以定義物件所產生的事件。
以實作Listener介面為例,程式需實作介面所提供的全部方法,不論是否使用到,均需全部實作於程式中,若需處理某一事件,則將Listener介面所提供的方法內容加以覆寫 (Override)。此外,Listener介面需以下列方法處理:
- addXXXListener():註冊事件的Listener,以處理物件所產生的相關事件。
- getXXXListeners():取得物件所註冊的Listener,並以陣列回傳所註冊的所有相關事件。
- removeXXXListener():移除物件所註冊的事件Listener。
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:觸控事件,適用於觸控裝置。
- WebEvent:Web Engine事件。
- WindowEvent:視窗事件。
- WorkerStateEvent:Worker狀態改變時之事件。
- ZoomEvent:縮放事件,適用於觸控裝置。
[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
沒有留言:
張貼留言