事件表示程序和用戶之間的交互,例如在文本框中輸入,在列表框或組合框中選擇,選中複選框和單選框,單擊按鈕等。事件處理表示程序對事件的響應,對用戶的交互或者說對事件的處理是事件處理程序完成的。
當事件發生時,系統會自動捕捉這一事件,創建表示動作的事件對象並把它們分派給程序內的事件處理程序代碼。這種代碼確定瞭如何處理此事件以使用戶得到相應的回答。
事件處理模型
前面我們講解了如何放置各種組件,使圖形界面更加豐富多彩,但是還不能響應用戶的任何操作。若使圖形界面能夠接收用戶的操作,必須給各個組件加上事件處理機制。在事件處理的過程中,主要涉及三類對象。
- Event(事件):用戶對組件的一次操作稱爲一個事件,以類的形式出現。例如,鍵盤操作對應的事件類是 KeyEvent。
- Event Source(事件源):事件發生的場所,通常就是各個組件,例如按鈕 Button。
- Event Handler(事件處理者):接收事件對象並對其進行處理的對象事件處理器,通常就是某個 Java 類中負責處理事件的成員方法。
例如,如果鼠標單擊了按鈕對象 Button,則該按鈕 Button 就是事件源,而 Java 運行時系統會生成 ActionEvent 類的對象 ActionEvent,該對象中描述了單擊事件發生時的一些信息。之後,事件處理者對象將接收由 Java 運行時系統傳遞過來的事件對象 ActionEvent,並進行相應的處理。事件處理模型如圖 1 所示。
由於同一個事件源上可能發生多種事件,因此,Java 採取了授權模型(Delegation Model),事件源可以把在其自身上所有可能發生的事件分別授權給不同的事件處理者來處理。例如,在 Panel 對象上既可能發生鼠標事件,也可能發生鍵盤事件,該 Panel 對象可以授權給事件處理者 a 來處理鼠標事件,同時授權給事件處理者 b 來處理鍵盤事件。
有時也將事件處理者稱爲監聽器,主要原因在於監聽器時刻監聽事件源上所有發生的事件類型,一旦該事件類型與自己所負責處理的事件類型一致,就馬上進行處理。授權模型把事件的處理委託給外部的處理實體進行處理,實現了將事件源和監聽器分開的機制。
事件處理者(監聽器)通常是一個類,該類如果能夠處理某種類型的事件,就必須實現與該事件類型相對的接口。例如,一個 ButtonHandler 類之所以能夠處理 ActionEvent 事件,原因在於它實現了與 ActionEvent 事件對應的接口 ActionListener。每個事件類都有一個與之相對應的接口。
動作事件監聽器
動作事件監聽器是 Swing 中比較常用的事件監聽器,很多組件的動作都會使用它監聽,像按鈕被裏擊、列表框中選擇一項等。與動作事件監聽器有關的信息如下。
- 事件名稱:ActionEvent。
- 事件監聽接口: ActionListener。
- 事件相關方法:addActionListener() 添加監聽,removeActionListener() 刪除監聽。
- 涉及事件源:JButton、JList、JTextField 等。
例 1
下面以按鈕的單擊事件爲例來說明動作單擊事件監聽器的應用。在此案例中統計了窗口內按鈕被單擊的次數。
本案例的核心代碼如下:
import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
public class ActionListenerDemo extends JFrame
{
JList list;
JLabel label;
JButton button1;
int clicks=0;
public ActionListenerDemo()
{
setTitle("動作事件監聽器示例");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100,100,400,200);
JPanel contentPane=new JPanel();
contentPane.setBorder(new EmptyBorder(5,5,5,5));
contentPane.setLayout(new BorderLayout(0,0));
setContentPane(contentPane);
label=new JLabel(" ");
label.setFont(new Font("楷體",Font.BOLD,16)); //修改字體樣式
contentPane.add(label, BorderLayout.SOUTH);
button1=new JButton("我是普通按鈕"); //創建JButton對象
button1.setFont(new Font("黑體",Font.BOLD,16)); //修改字體樣式
button1.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
label.setText("按鈕被單擊了 "+(clicks++)+" 次");
}
});
contentPane.add(button1);
}
//處理按鈕單擊事件的匿名內部類
class button1ActionListener implements ActionListener
{
@Override
public void actionPerformed(ActionEvent e)
{
label.setText("按鈕被單擊了 "+(clicks++)+" 次");
}
}
public static void main(String[] args)
{
ActionListenerDemo frame=new ActionListenerDemo();
frame.setVisible(true);
}
}
上述代碼調用 addActionListener() 方法爲 button1 添加了單擊動作的事件監聽器,該監聽器由 button1ActionListener 類來實現。button1ActionListener 類必須繼承 ActionListener 類,並重寫父類的 actionPerformed() 方法。在 actionPerformed() 方法內編寫按鈕被單擊後執行的功能。
圖 2 所示爲程序運行後,沒有單擊和單擊後的效果。
在本例中使用的是內部類形式,當然也可以寫成如下形式的代碼:
//爲按鈕buttonl添加ActionEvent事件的處理程序
buttonl.addActionListener(new ActionListener()
{
public void action Performed(Action Event e)
{
//具體代碼編寫在這裏
label.setTextC 按鈕被單擊了 "+(ciicks++)+1 次");
}
}
焦點事件監聽器
除了單擊事件外,焦點事件監聽器在實際項目中應用也比較廣泛,例如將光標離開文本框時彈出對話框,或者將焦點返回給文本框等。
與焦點事件監聽器有關的信息如下。
- 事件名稱:FocusEvent。
- 事件監聽接口: FocusListener。
- 事件相關方法:addFocusListener() 添加監聽,removeFocusListener() 刪除監聽。
- 涉及事件源:Component 以及派生類。
FocusEvent 接口定義了兩個方法,分別爲 focusGained() 方法和 focusLost() 方法,其中 focusGained() 方法是在組件獲得焦點時執行,focusLost() 方法是在組件失去焦點時執行。
例 2
下面以文本框的焦點事件爲例來說明焦點單擊事件監聽器的應用。本案例的核心代碼如下:
import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.border.EmptyBorder;
public class FocusListenerDemo extends JFrame
{
JList list;
JLabel label;
JButton button1;
JTextField txtfield1;
public FocusListenerDemo()
{
setTitle("焦點事件監聽器示例");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100,100,400,200);
JPanel contentPane=new JPanel();
contentPane.setBorder(new EmptyBorder(5,5,5,5));
contentPane.setLayout(new BorderLayout(0,0));
setContentPane(contentPane);
label=new JLabel(" ");
label.setFont(new Font("楷體",Font.BOLD,16)); //修改字體樣式
contentPane.add(label, BorderLayout.SOUTH);
txtfield1=new JTextField(); //創建文本框
txtfield1.setFont(new Font("黑體", Font.BOLD, 16)); //修改字體樣式
txtfield1.addFocusListener(new FocusListener()
{
@Override
public void focusGained(FocusEvent arg0)
{
// 獲取焦點時執行此方法
label.setText("文本框獲得焦點,正在輸入內容");
}
@Override
public void focusLost(FocusEvent arg0)
{
// 失去焦點時執行此方法
label.setText("文本框失去焦點,內容輸入完成");
}
});
contentPane.add(txtfield1);
}
public static void main(String[] args)
{
FocusListenerDemo frame=new FocusListenerDemo();
frame.setVisible(true);
}
}
上述代碼爲 txtfield1 組件調用 addFocusListener() 方法添加了焦點事件監聽器,並且監聽器使用匿名的實現方式。在實現 FocusListener 接口的代碼中編寫 focusGained() 方法和 focusLost() 方法的代碼。最終程序運行效果如圖 3 所示。
監聽列表項選擇事件
列表框控件 JList 會顯示很多項供用戶選擇,通常在使用時會根據用戶選擇的列表項完成不同的操作。
本案例將介紹如何監聽列表項的選擇事件,以及事件監聽器的處理方法,實現過程如下。
(1) 創建一個繼承自 JFrame 的 JListDemo2 類。
(2) 在 JListDemo2 類中添加 JList 組件和 JLabel 組件的聲明,並創建空的構造方法,代碼如下所示。
import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
public class JListDemo2 extends JFrame
{
JList list;
JLabel label;
public JListDemo2(){};
public static void main(String[] args)
{
JListDemo2 frame=new JListDemo2();
frame.setVisible(true);
}
}
(3) 在構造方法中爲列表框填充數據源,主要代碼如下:
public JListDemo2()
{
setTitle("監聽列表項選擇事件");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100,100,400,200);
JPanel contentPane=new JPanel();
contentPane.setBorder(new EmptyBorder(5,5,5,5));
contentPane.setLayout(new BorderLayout(0,0));
setContentPane(contentPane);
label=new JLabel(" ");
contentPane.add(label,BorderLayout.SOUTH);
JScrollPane scrollPane=new JScrollPane();
contentPane.add(scrollPane,BorderLayout.CENTER);
list=new JList();
scrollPane.setViewportView(list);
String[] listData=new String[7];
listData[0]="《一點就通學Java》";
listData[1]="《一點就通學PHP》";
listData[2]="《一點就通學Visual Basic)》";
listData[3]="《一點就通學Visual C++)》";
listData[4]="《Java編程詞典》";
listData[5]="《PHP編程詞典》";
listData[6]="《C++編程詞典》";
list.setListData(listData);
}
(4) 爲列表框組件 list 添加選擇事件監聽,代碼如下所示。
list.addListSelectionListener(new ListSelectionListener()
{
public void valueChanged(ListSelectionEvent e)
{
do_list_valueChanged(e);
}
});
如上述代碼所示,list 組件綁定了 ListSelectionListener 事件監聽器,在觸發該事件後又會調用 do_list_valueChanged() 方法進行實際的業務邏輯處理。
(5) 創建 do_liSt_ValueChanged() 方法將用戶選擇的列顯示到標籤中,具體代碼如下:
protected void do_list_valueChanged(ListSelectionEvent e)
{
label.setText("感謝您購買:"+list.getSelectedValue());
}
(6) 運行程序,列表框選擇前後的效果如圖 4 所示。
謝謝觀看