JavaFX事件(1)EventHandler處理架構
|
JavaFX多媒體(4)Equalizer 與 Audio Spectrum << 前情 欲建立JavaFX程式與使用者間的互動,需處理物件的事件,所謂事件 (Event) 是指當物件其狀態改變時所觸發產生的相關動作,例如按下滑鼠按鍵、滑鼠拖曳、按下鍵盤按鍵等,均會觸發其相對應的事件。 AWT/Swing事件處理架構在Java AWT與Java Swing中,處理事件的方式有兩種,第一種方式為實作處理事件的Listener介面,各Listener介面提供處理事件的方法。其次為處理事件的類別,並分為Event類別與Adapter抽象類別,以定義物件所產生的事件。 以實作Listener介面為例,程式需實作介面所提供的全部方法,不論是否使用到,均需全部實作於程式中,若需處理某一事件,則將Listener介面所提供的方法內容加以覆寫 (Override)。此外,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簡化處理事件的方式,不像AWT/Swing以不同的Listener介面處理各類事件,JavaFX僅以javafx.event.EventHandler介面處理各類事件,且介面僅提供handle()方法。 至於如何以單一的EventHandler介面處理各類事件呢?這點可說是JavaFX的一項重大改變。 JavaFX以事件類型 (Event Type) 定義各類事件,其基礎類別為javafx.event.Event,繼承自Event類別的事件類別分別如下所示,其中較特殊的是手勢與觸控事件,由於目前大部份裝置均支援觸控螢幕 (Touch Screen) 與觸控板 (Touch Pad),因此JavaFX增加處理多點觸控 (Multi-Touch) 的事件類別:
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() {
@Override public void handle(ActionEvent e) {
...
}
});
以按鈕的滑鼠移動事件為例,其設定方法為setOnMouseMoved()、事件類別為MouseEvent: Button button = new Button();
button.setOnMouseMoved(new EventHandler() {
@Override public void handle(MouseEvent e) {
...
}
});
由上述說明可以瞭解,JavaFX以單一EventHandler介面與不同事件類別的組合處理事件,相較於Java以實作處理事件的Listener介面、或使用Event類別與Adapter抽象類別,JavaFX處理事件的方式更為簡單。 除了上述語法之外,亦可以建立類別的方式處理,以按鈕的動作事件為例: Button button = new Button();
button.setOnAction(onActionEventHandler);
...
EventHandler onActionEventHandler = new EventHandler() {
@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() {
@Override public void handle(ActionEvent e) {
...
}
}
);
除了上述語法之外,亦可以建立類別的方式處理,以按鈕的動作事件為例: Button button = new Button();
button.addEventHandler(ActionEvent.ACTION, onActionEventHandler);
...
EventHandler onActionEventHandler = new EventHandler() {
@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() {
@Override public void handle(ActionEvent e) {
...
}
}
);
除了上述語法之外,亦可以建立類別的方式處理,以按鈕的動作事件為例: Button button = new Button();
button.addEventFilter(ActionEvent.ACTION, onActionEventFilter);
...
EventHandler onActionEventFilter = new EventHandler() {
@Override public void handle(ActionEvent e) {
...
}
};
此外Java 8.0新增Lambda Expression,其語法如下: (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的事件處理上,讓處理事件的方式更為簡單。透過Lambda Expression可將上述程式精簡如下,省略EventHandler介面的描述: Button button = new Button();
button.setOnMouseMoved((ActionEvent e) -> {
...
});
或以建立類別的方式處理: Button button = new Button();
button.setOnAction(onActionEventHandler);
...
EventHandler onActionEventHandler =
(EventHandler<ActionEvent>)(ActionEvent e) -> {
...
};
更進一步可依賴編譯器的型態推斷 (Type Inference),讓程式更精簡: Button button = new Button();
button.setOnAction(event -> {
...
});
【參考資料】 [1] Java Official Web Site
|

Java 學習之路

