事件驅動程序設計


事件和事件源

運行java圖形用戶界面程序時,程序與用戶進行交互,事件驅動程序的執行.事件(event)可以定義為程序發生了某些事情的信號.外部用戶動作和內部程序動作都可以觸發事件,外部用戶動作的例子有移動鼠標,點擊按鈕和敲擊鍵盤等,而內部程序動作的例子有定時器.程序可以選擇響應事件或忽略事件.
能創建一個事件並觸發該事件的組件稱為源對象(source object)源組件(source component).例如,按鈕是按鈕點擊動作事件的源對象.一個事件是事件類的實例.事件類的根類是java.util.EventObject.
這里寫圖片描述
事件對象包含與事物相關的一切屬性.可以使用EventObject類中的實例方法getSource()獲得事件的源對象.EventObject類的子類處理特定類型的事件,例如,動作事件,窗口事件,組件事件,鼠標事件以及按鍵事件.
外部動作用戶,源對象和事件類型
這里寫圖片描述
注意:如果一個組件可以觸發某個事件,那么這個組件的任意子類都可以觸發同類型的事件.例如,每個GUI組件都可以觸發MouseEvent,KeyEvent,FocusEventComponentEvent,因為Component是所有GUI組件的父類.
注意:上圖除了ListSelectionEventChangeEvent之外的所有事件類都包括在java.awt.event包中,ListSelectionEventChangeEventjavax.swing.event包中.AWT是為AWT組件設計的,但是許多Swing組件都會觸發它們.

監聽器,注冊以及處理事件

Java使用一種基於委托的模型來處理事件:源對象觸發一個事件,對此事件感興趣的對象會處理它.將對此事件感興趣的對象稱為監聽器(listener).一個對象要成為源對象上的事件監聽器,需要具備兩個條件:
這里寫圖片描述
這里寫圖片描述
1.監聽器對象的類必須是相應的事件監聽器接口的實例,以確保監聽器有處理這個事件的正確方法.Java為每一種類型的事件都提供個監聽器接口.通常,事件XEvent的監聽器接口命名為XListener,監聽器MouseMotionListener例外.例如,事件ActionEvent對應的監聽器接口是ActionListener,ActionEvent的每個監聽器都因該實現ActionListener接口.事件類型,對應的監聽器接口以及定義在監聽器接口中的方法.包含處理事件的監聽器接口稱為處理器(handler)的方法.
2.監聽器對象必須由源對象注冊.注冊方法依賴與事件的類型.如果事件類型是ActionEvent,那么對應的注冊方法是addActionListener.一般來說,XEvent的注冊方法命名為addXListener.一個源對象可以觸發幾種類型的事件.一個源對象針對每個事件都維護着一個注冊的監聽器列表,通過調用監聽器對象上的處理器來通知所有注冊的監聽器響應這個事件,

JButton jbtOK = new JButton("OK");
ActionListener listener1 = new OKListenerClass();
jbtOK.addActionListener(listener1);

點擊該按鈕時,JButton對象觸發一個ActionEvent,然后將它作為參數傳遞以調用監聽器的actionPerformed方法來處理這個事件
事件,事件監聽器和監聽器方法
這里寫圖片描述
這里寫圖片描述
現在我們可以編寫一個程序,使用兩個按鈕控制一個圓的大小
這里寫圖片描述

**ControlCircle1.java代碼:**
package chapter16;
import javax.swing.*;
import java.awt.*;
public class ControlCircle1 extends JFrame
{

/**
*
*/

private static final long serialVersionUID = 1L;
private JButton jbtEnlarge = new JButton("Enlarge");
private JButton jbtShrink = new JButton("Shrink");
private CirclePanel canvas = new CirclePanel();

public ControlCircle1()
{
JPanel panel = new JPanel();//Use the panel to group buttons
panel.add(jbtEnlarge);
panel.add(jbtShrink);

this.add(canvas,BorderLayout.CENTER);//Add canvas to center
this.add(panel, BorderLayout.SOUTH);//Add buttons to the frame
}

public static void main(String[] args)
{
JFrame frame = new ControlCircle1();
frame.setTitle("ControlCircle1");
frame.setLocationRelativeTo(null);
frame.setSize(200, 200);
frame.setVisible(true);
}
}

class CirclePanel extends JPanel
{
/**
*
*/

private static final long serialVersionUID = 1L;
private int radius = 5;//Default circle radius

/*Repaint重畫 the circle*/
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawOval(getWidth()/2-radius, getHeight()/2-radius, 2*radius, 2*radius);
}
}

運行結果,但不能擴大縮小圓的大小:
這里寫圖片描述
如何使用按鈕放大和縮小這個圓呢?當點擊Enlarge按鈕時,希望能用一個比較大的半徑來重新繪制這個圓。該如何完成它呢?
1.定義一個名為EnlargeListener的監聽器類,實現ActionListener.
2.創建一個監聽器,並且將它注冊到jdtEnlarge.
3.在CirclePanel中添加一個名為enlarge()的方法來增加半徑,然后重新繪制面板.
4.實現EnlargeListener中的actionPerformed方法來調用canvas.enlarge().
5.為了讓actionPerformed方法可以訪問引用變量canvas,將EnlargeListener定義為ControlCircle2類的內部類.內部類定義在另一個類中
6.為了避免編譯錯誤,CirclePanel類現在也定義為ControlCircle2的一個內部類.

package chapter16;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class ControlCircle2 extends JFrame
{

private static final long serialVersionUID = 1L;
private JButton jbtEnlarge = new JButton("Enlarge");
private JButton jbtShrink = new JButton("Shrink");
private CirclePanel canvas = new CirclePanel();

public ControlCircle2()
{
JPanel panel = new JPanel();
panel.add(jbtEnlarge);
panel.add(jbtShrink);

this.add(canvas,BorderLayout.CENTER);//Add canvas to center
this.add(panel, BorderLayout.SOUTH);//Add buttons to the frame

jbtEnlarge.addActionListener(new EnlargeListener());
}

public static void main(String[] args)
{
JFrame frame = new ControlCircle2();
frame.setTitle("ControlCircle2");
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(200, 200);
frame.setVisible(true);
}

class EnlargeListener implements ActionListener//Inner class
{

public void actionPerformed(ActionEvent e)
{
canvas.enlarge();
}
}

class CirclePanel extends JPanel//Inner class
{

private static final long serialVersionUID = 1L;
private int radius = 5;//Default circle radius

/*Enlarge the circle*/
public void enlarge()
{
radius++;
repaint();
}

/*Repaint the circle*/
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawOval(getWidth()/2-radius, getHeight()/2-radius, 2*radius, 2*radius);
}
}
}

這里寫圖片描述

內部類

內部類(inner class)或者潛套類(nested class)是定義在另一個類的范圍的類.如下圖a中的代碼定義了兩個獨立的類:Test和A.圖b的代碼定義A為Test的一個內部類.
這里寫圖片描述
圖c中定義在OuterClass中的InnerClass類是內部類的另一個例子.內部類可以像常規類一樣使用.通常,如果內部類只是被外部類使用,那就將該類定義為內部類.一個內部類有如下特征:
1.一個內部類被編譯成一個名為OuterClassName$InnerClassName.class的類.例如,在圖b中Test中的內部類A被編譯成Test$A.class
2.內部類可以引用定義在它嵌套的外部類中的數據和方法,所以,不需要將外部類對象的引用傳遞個內部類的構造方法.因為這個原因,內部類可以使程序更加簡單和簡潔.
3.使用可見性修飾符定義內部類時,遵從和應用與在類成員上一樣的可見性規則.
4.可以將內部類定義為static,一個static內部類可以使用外部類的名字訪問.一個static類是不能訪問外部類的非靜態成員的.
5.內部類的對象經常在外部類中創建.但是,也可以從另一個類中創建一個內部類的對象。如果該內部類是非靜態的,就必須先創建一個外部類的實例,然后使用下面的語法創建一個內部類的對象:

OuterClass.InnerClass innerObject = outerObject.new InnerClass();

如果內部類是靜態的,那么使用下面的語法為它創建一個對象:

OuterClass.InnerClass innerObject = new OuterClass.InnerClass();

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com