本文部分内容参考:http://bdxnote.blog.163.com/blog/static/844423520134154319780/;
1.事件处理机制:GUI程序和用户操作的交互功能;
2.理解3个重要的概念:
事件:用户对组件的一个操作,称之为一个事件;
事件源:发生事件的组件就是事件源;
事件处理器:负责处理事件的方法;
3.事件处理的步骤:
STEP1:确定事件监听器类型之后,必须在程序中实现事件处理代码;可以实现事件监听器接口,可以继承事件适配器类;
STEP2:创建事件监听器对象;
STEP3:调用事件源的addXxxListener()方法,把事件监听器对象注册给事件源;
一、事件类和相应的事件监听器接口
1.MouseEvent对应鼠标事件,包括鼠标按下、释放、点击等;对应的监听器接口名MouseLister;
2.WindowEvent对应窗口事件,包括点击了关闭按钮,窗口得到与失去焦点,窗口被最小化等;对应的监听器接口名WindowListener;
3.ActionEvent对应一个动作事件,代表一个具体的动作,如按钮或菜单被鼠标单击。对应的监听器接口名ActionLister;
二、定义实现事件监听器有如下几种方法:
方法1:使用内部匿名类作为事件监听器;这种方法适用于简单的事件处理器对象;如下:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class MyGuiClass extends JFrame
{
public MyGuiClass()
{
......
component = new Component();
component.addXxxListener
(
new XxxListener() //内部匿名类
{
public void 事件处理函数(XxxEvent e)
{
//事件处理代码;
}
}
);
......
}
}
其中,new XxxListener()就是一个匿名内部类;其实就是在实现类的同时使用new运算符构造一个该类的对象,并把它作为addXxxListener()的参数;即:把内部匿名类的定义写到组件的事件处理器注册函数的参数列表的位置;
方法2:使用内部命名类作为事件监听器;就是在GUI程序类体内部实现事件监听器类;如下:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class MyGuiClass extends JFrame
{
public MyGuiClass()
{
......
component = new Component();
component.addXxxListener(new InnerClass());
......
}
/************内部命名类的定义************/
class InnerClass implements XxxListener //或extends XxxAdapter;
{
public void 事件处理函数(XxxEvent e)
{
//事件处理代码;
}
}
}
方法3:使用外部命名类作为事件监听器;就是在GUI程序类体外部实现事件监听器类;如下:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class MyGuiClass extends JFrame
{
public MyGuiClass()
{
......
component = new Component();
component.addXxxListener(new OuterClass());
......
}
}
/************外部命名类的定义************/
class OuterClass implements XxxListener //或extends XxxAdapter;
{
public void 事件处理函数(XxxEvent e)
{
//事件处理代码;
}
......
}
方法4:使用当前提供GUI界面的类自身作为监听器;就是把提供应用程序GUI界面的类自身当做监听器类;如下:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class MyGuiClass extends JFrame implements XxxListener //或extends XxxAdapter;
{
public MyGuiClass()
{
......
component = new Component();
component.addXxxListener(this);
......
}
public void 事件处理函数(XxxEvent e)
{
//事件处理代码;
}
......
}
备注:
(1)、使用匿名内部类存在很多问题;首先,根据组件在代码中被定义的位置不同,类的定义以及处理事件的代码将分散在程序的各个部分,而不是集中在一起的,不方便维护;各个事件的处理全部由嵌套的程序块组成,视觉上很难定位程序代码;如果事件处理程序比较复杂,内部类中的代码将变得很长,这就很难找到相应的组件定义的位置;内部匿名类的代码也不能被复用;
(2)、使用一般的命名内部类可以解决匿名内部类的全部问题;但是,一般的命名内部类也有一些问题,它可以访问当前提供GUI界面的类的全部成员,这破坏了类的封装性,会造成数据的不安全访问;
(3)、使用外部命名类可以避免其它三种方式的问题;但是又有新的问题了,外部命名类不能很方便地访问当前提供GUI界面的类的成员;
(4)、使用当前提供GUI界面的类自身作为监听器,这种方式看上去比较完美了;但是这种方式只能实现事件监听器接口,实现接口的全部事件处理函数,即便事件处理函数是空函数,也要写出来;而不能继承事件适配器类;因为它已经继承了Java的界面类JFrame;
综合比较,使用一般的内部命名类还是比较方便的;
三、事件适配器:
很多事件监听器接口中都定义了很多抽象方法,而往往只用到其中的一个或很少的几个;根据Java的语法规则,实现接口时,必须要把其中定义的全部方法都实现,对那些不需要的方法,填写成空语句即可;
例如:窗口监听器接口WindowListener有7个方法,而很多时候,程序可能只用到其中的windowClosing()方法,以便实现窗口右上角的关闭按钮的关闭代码;但是其它6个方法也必须实现,即便是空方法;这样就使得程序编写显得非常麻烦;
为了解决这个问题,事件适配器类就出现了;为了简化程序,Java中预定义了一些特殊类,这些类已经实现了相应的接口,所有方法都已经写上了空语句;使得在编写事件监听器类时,便可以通过继承这些特殊的类来达到实现相应的事件监听器接口的目的;同时又可以只选择程序中需要的方法进行重写,非常方便;
Java中把这些预定义的类称为事件适配器类,类似于监听器接口;为了方便使用,适配器类的名称有一定的规则:只需要把相应接口名称中的Listener改为Adapter即可;例如,窗口监听器接口WindowListener对应的适配器类是WindowAdapter;鼠标监听器接口MouseListener对应的适配器类是MouseAdapter;还有一些事件监听器接口,本身就只有一个事件处理函数,所以就不需要有对应的适配器类;比如,ActionListener接口,它就只有一个事件处理函数,JDK中就没有定义该接口的适配器类;
由于Java不支持多继承,所以,事件监听器实现方法4"使用当前提供GUI界面的类自身作为监听器"就不能使用事件适配器类,因为它已经继承了Java的GUI类;
通常把GUI界面类与事件处理器类分离在两个类中,这样有利于界面和业务逻辑的分离,提高了代码的灵活性和可重用性;然而把事件处理器类与GUI界面类分开放在两个类中时,又使得两个类之间的数据交流变得比较复杂;因此,综合评定各种优缺点,经常的做法就是把事件处理器类定义成GUI界面类的内部命名类,以便于从事件处理器中能够直接访问GUI界面类中的成员;
备注:同一个组件上可以注册多个事件监听器,同一个事件监听器也可以注册到多个组件上,同一个事件监听器也可以在同一个组件上添加和删除多次;这些特点都得益于Observer设计模式;