物件可辨識和回應的行為是「事件」。物件可以辨識和回應的行為稱為事件,事件是物件所能辨識和偵測的動作,當此動作發生於某一個物件上時,其對應的事件就會被觸發。
Java 事件總結
事件處理模型
對於GUI的應用程式來說,事件處理是必不可少的,因此我們需要熟練地掌握事件處理模型。對於事件我們需要了解兩個名詞:事件來源物件與監聽器物件。從字面上我們可以理解個大概,下面我們系統說明一下:
監聽器物件是一個實作了特定監聽器介面(listener interface)的類別的實例
事件來源是一個能夠註冊監聽器物件並傳送事件物件的物件
當事件發生時,事件來源將事件物件傳遞給所有註冊的監聽器
監聽器物件將利用事件物件中的資訊決定如何對事件做出對應
首先我們將監聽器對象註冊給事件來源對象,這樣當事件觸發時系統便可以透過事件來源存取對應的監聽器。如下圖:
當事件來源觸發事件後,系統便將事件的相關資訊封裝成對應類型的事件對象,並將其傳送給註冊到事件來源的相應監聽器。如下圖:
當事件物件傳送給監聽器後,系統呼叫監聽器的對應事件處理方法會對事件進行處理,也就是做出回應。如下圖:
注意:監聽器與事件來源之間是「多對多」的關係。
事件物件的層次結構
在事件物件中最高層是java.util.EventObject,所有事件狀態物件都將從其派生的根類別。這個類別除了從Object類別繼承下來的類別之外還有一個就是getSource() 方法,其功能就是傳回最初發生 Event 的物件。
除了這個類別是在util套件中,其它都在java.awt、java.awt.event套件或java.swing、java.swing.event套件中,值得注意的並不是說Swing控制項只使用Swing事件。
AWTEvent類別提供了getID() 方法傳回事件本質的識別碼。例如,如果滑鼠事件發生,能夠找出是點選、拖曳、按、還是其他操作。
常用的幾個事件類別的說明:
EventObject:所有事件類別的超類別。最重要的方法-- getSource(),傳回產生某事件的物件
AWTEvent:所有AWT事件類別的超類別。最重要的方法-- getID(),傳回某事件的ID號,事件的ID是整數,它指定事件的類型,例如按鈕事件或滑鼠點擊事件
ActionEvent :啟動元件時發生的事件
AdjustmentEvent:調節可調整的元件(如移動捲軸)時發生的事件
ComponentEvent:操縱某元件時發生的一個高層事件
ContainerEvent:向容器新增或刪除元件時發生
InputEvent:由某輸入裝置產生的一個高層事件
ItemEvent:從選擇項,複選框或清單中選擇時發生
KeyEvent:操作鍵盤時發生
MouseEvent:操作滑鼠時發生
#PaintEvent:描繪元件時發生的一個事件
監聽器物件的層次結構
######監聽器物件就是一個實作了特定監聽器介面的類別的實例,那麼監聽器接口就是我們所關心的問題了。在監聽器介面的最頂層介面是java.util.EventListener,這個介面是所有事件偵聽器介面必須擴展的標記介面。感到詬異的是這個介面完全是空的,裡面沒有任何的抽象方法的定義,查看原始碼裡面空空如也啊! ############事件監聽器類別(監聽器物件所屬的類別)必須實作事件監聽器介面或繼承事件監聽器適配器類別。 ############事件監聽器介面定義了處理事件必須實作的方法。 ############事件監聽器適配器類別是對事件監聽器介面的簡單實作。目的是為了減少程式設計的工作量。 ###事件監聽器的介面命名方式為:XXListener,而且,在java中,這些介面已經被定義好了。用來被實現,它定義了事件處理器(即事件處理的方法原型,這個方法需要重新實作)。
例如:ActionListener介面、MouseListener介面、WindowListener介面、KeyListener介面、ItemListener介面、MouseMotionListener介面、FocusListener介面、ComponentListener介面等
事件來源
#事件最初由事件來源產生,事件來源可以是GUI元件Java Bean或由產生事件能力的對象,在GUI元件情況下,事件來源或是元件的同位體(對於Abstract Window Toolkit[awt]GUI元件來說)或元件本身(對於Swing元件來說)。
在java中,每一個元件會產生什麼樣的事件,已經被定義好了。或者說,對於任何一個事件來說,哪些元件可以產生它,已經是確定的了。
事件
AWT將事件分為低階事件和語意事件。
語意事件是表示使用者動作的事件。
低階事件是形成那些事件的事件。
java.awt.event套件中常見的語意事件類別:
ActionEvent(對應按鈕點選、選單選擇、選擇清單項目或在文字方塊中ENTER)
AdjustmentEvent(使用者調節捲軸)
ItemEvent(使用者從複選框或列錶框中選擇一項目)
常用的5個低階事件類別:
KeyEvent(一個鍵被按下或釋放)
MouseEvent(滑鼠鍵被按下、釋放、移動或拖曳)
#MouseWheelEvent(滑鼠滾輪被轉動)
FocusEvent(某個元件獲得焦點或失去焦點)
WindowEvent(視窗狀態被改變)
java.awt.event套件中定義的常用事件適配器類別包括以下幾個:
1. ComponentAdapter( 元件適配器)
2. ContainerAdapter( 容器適配器)
3. FocusAdapter( 焦點適配器)
4. KeyAdapter( 鍵盤轉接器)
5. MouseAdapter( 滑鼠適配器)
6. MouseMotionAdapter( 滑鼠運動適配器)
7. WindowAdapter( 視窗適配器)
事件來源與監聽器的對應關係
##下圖是Java實際開發中的對應關係圖: #常見的事件物件與監聽器對照表:事件來源 | |
---|---|
AbstractButton |
JcomboBox JTextField Timer |
JscrollBar | |
AbstractButton |
JComboBox |
Component | |
Component | |
Component | |
Component | ## Component |
建議:對這一部分了解需要先了解Java視覺化元件與容器之間的大致關係,這樣方便我們的理解。
程式通常的開發步驟
作為程式開發者,我們要做的是建立事件監聽器物件並且在被啟動(new)事件的元件中進行註冊。所謂的創建事件監聽器對象,就是創建一個類,而這個類必須實現形如XXListener的接口(或者繼承”已經實現了XXListener的類”),當然,實現這個接口就意味著重寫XXListener的方法。
例如,對於ActionListener, 只有一個actionPerformed方法:
class B1 implements ActionListener{// 实现ActionListener @override public void actionPerformed(ActionEvent e){ //重写actionPerformed //do somthing.... } }
在被啟動事件的元件中註冊事件監聽器: 即呼叫形如addXXListener()的方法。
例如:
Button b1 = new Button("Button 1"); b1.addActionListener(new B1()); //注册事件监听器
b1就是被啟動事件的元件這樣一來,當事件被啟動時,處理流程如下:由於已經透過addActionListener進行了事件監聽器的註冊,所以,就會呼叫到特定的事件處理方法,即actionPerformed()函數。這樣,執行的結果就要看actionPerformed是具體做什麼工作了。
一個監聽器只監聽一個特定的事件來源,則我們可以採用匿名物件的方式來註冊監聽器。
例如:
JButton b=new JButton("jjjj"); b.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { //重写actionPerformed //do somthing.... } });
Java Swing中處理各元件事件的一般步驟為:
1. 新建一個元件(如JButton)。
2. 將該組件加入對應的面板(如JPanel)。
3. 註冊監聽器以監聽事件來源產生的事件(如透過ActionListener來回應使用者點擊按鈕)。
4. 定義處理事件的方法(如在ActionListener中的actionPerformed定義對應方法)。
上面第一種創建的監聽器類可以是一個內部類,第二種創建監聽器的方式為匿名內部類,很好理解。
回應與介面分離設計
我們將事件的處理與介面寫在一起,一個是不便於維護,在一個會導致目前程式碼檔案的臃腫,所以我還是建議大家講事件的相對於介面分離,這樣既可以彌補前面兩種缺陷,同時也提高了程式碼的複用性。但也不要忽略內部類別與匿名內部類別的使用,因為各有優缺點,我們要綜合考慮。
Swing套件提供了一個非常實用的機制來封裝指令,並將它們連接到多個事件來源,這就是Action介面。一個動作是封裝下列內容的物件:
指令的說明(一個文字字串和一個可選圖示)
執行指令所需的參數(例如,在列舉的範例中要求改變的顏色)
詳細的內容請參考API。
要注意,Action是一個接口,而不是一個類別。實作這個介面的所有類別都必須實作其中的7個方法。慶幸的是有一個類別實作了這個介面除actionPerformed方法之外的所有方法,它就是AbstractAction。這個類別儲存了所有名/值對,並管理屬性變更監聽器。我們可以直接擴充AbstractAction類,並在擴充類別中實作actionPerformed方法。
我看過的一個比較好的設計方式是:監聽器類別繼承javax.swing.AbstractAction,在元件上註冊的時候講元件傳遞到這個監聽器。
監聽器:
public class AC_temp extends AbstractAction{ private static final long serialVersionUID = 1L; MainFrame main; public AC_EditVideoInfo(MainFrame temp,Color color) { main=temp; putValue(Action.NAME, "name"); putValue(Action.SMALL_ICON, new ImageIcon("images/edit.png")); putValue(Action.SHORT_DESCRIPTION, "description"); putValue("color",color); //.... } @Override public void actionPerformed(ActionEvent e) { // do something } }
事件來源:
组件.addActionListener(new AC_EditVideoInfo(this));//注册监听器
建立包含一個方法呼叫的監聽器
java.beans. EventHandler從命名來看是一個事件管理器。官方API給出的解釋是:EventHandler 類別為動態生成事件偵聽器提供支持,這些偵聽器的方法執行一條涉及傳入事件物件和目標物件的簡單語句。
更詳細的解釋參考:————————>>>>>>>>>
使用EventHandler 的範例:
EventHandler 最簡單的使用方法是安裝一個偵聽器,不帶參數地在目標物件上呼叫某個方法。在下列範例中,將建立一個在 javax.swing.JFrame 實例上呼叫 toFront 方法的 ActionListener。
myButton.addActionListener( (ActionListener)EventHandler.create(ActionListener.class, frame, "toFront"));
當按下 myButton 時,將執行 frame.toFront() 語句。透過定義ActionListener 介面的新實作並將其實例新增至按鈕中,使用者可以獲得相同的效果,且具有額外的編譯時類型安全性:
//Equivalent code using an inner class instead of EventHandler. myButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { frame.toFront(); } });
EventHandler 的另一種最簡單用法是從偵聽器介面(通常是一個事件物件)中的方法的第一個參數中提取屬性值,並用其設定目標物件中的屬性值。在下列範例中,將建立一個 ActionListener,它將目標 (myButton) 物件的 nextFocusableComponent 屬性設定為事件的 "source" 屬性的值。
EventHandler.create(ActionListener.class, myButton, "nextFocusableComponent", "source")
這將對應到以下內部類別實作:
//Equivalent code using an inner class instead of EventHandler. new ActionListener() { public void actionPerformed(ActionEvent e) { myButton.setNextFocusableComponent((Component)e.getSource()); } }
也可以建立一個只是將傳入事件物件傳遞給目標動作的 EventHandler。如果 EventHandler.create 中的第四個參數為空字串,則事件的傳遞方式如下:
EventHandler.create(ActionListener.class, target, "doActionEvent", "")
這將對應於下列內部類別實作:
//Equivalent code using an inner class instead of EventHandler. new ActionListener() { public void actionPerformed(ActionEvent e) { target.doActionEvent(e); } }
EventHandler 最常见的用法可能是从事件对象的 source 中提取属性值,并将此值设置为目标对象的属性值。在以下示例中,将创建一个 ActionListener,它将目标对象的 "label" 属性设置为事件源的 "text" 属性的值("source" 属性的值)。
EventHandler.create(ActionListener.class, myButton, "label", "source.text")
这将对应于以下内部类实现:
//Equivalent code using an inner class instead of EventHandler. new ActionListener { public void actionPerformed(ActionEvent e) { myButton.setLabel(((JTextField)e.getSource()).getText()); } }
可以使用以 "." 字符分隔的任意数量的属性前缀来“限定”事件属性。采用出现在 "." 字符前面的“限定”名称作为将应用于事件对象的属性名称,最左边的最先应用。
例如,以下动作侦听器
EventHandler.create(ActionListener.class, target, "a", "b.c.d")
可以写成以下内部类(假定所有属性都有规范的获取方法并返回适当的类型):
//Equivalent code using an inner class instead of EventHandler. new ActionListener { public void actionPerformed(ActionEvent e) { target.setA(e.getB().getC().isD()); } }
也可以使用以 "." 字符分隔的任意数量的属性前缀来“限定”目标属性。例如,以下动作侦听器:
EventHandler.create(ActionListener.class, target, "a.b", "c.d")
可以写成以下内部类(假定所有属性都有规范的获取方法并返回适当的类型):
//Equivalent code using an inner class instead of EventHandler. new ActionListener { public void actionPerformed(ActionEvent e) { target.getA().setB(e.getC().isD()); } }
由于 EventHandler 最终依赖反射来调用方法,所以建议不要以重载方法为目标。例如,如果目标是类 MyTarget 的一个实例,而 MyTarget 定义如下:
public class MyTarget { public void doIt(String); public void doIt(Object); }
那么方法 doIt 被重载。EventHandler 将基于源调用恰当的方法。如果源为 null,那么两个方法都可以,具体调用哪个方法是不确定的。因此,建议不要以重载方法为目标。
更多相关知识,请访问:PHP中文网!
以上是物件可辨識和回應的行為是什麼?的詳細內容。更多資訊請關注PHP中文網其他相關文章!