对象可识别和响应的行为是“事件”。对象可以识别和响应的行为称为事件,事件是对象所能辨识和检测的动作,当此动作发生于某一个对象上时,其对应的事件便会被触发。
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:描绘组件时发生的一个事件
TextEvent:更改文本时发生
WindowEvent:操作窗口时发生的事件,如最大化或最小化某一窗口。
监听器对象的层次结构
监听器对象就是一个实现了特定监听器接口的类的实例,那么监听器接口就是我们所关心的问题了。在监听器接口的最顶层接口是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实际开发中的对应关系图:
常见的事件对象与监听器对照表:
监听器接口 | 事件源 |
---|---|
ActionListener | AbstractButton JcomboBox JTextField Timer |
AdjustmentListener | JscrollBar |
ItemListener | AbstractButton JComboBox |
FocusListener | Component |
KeyListener | Component |
MouseListener | Component |
MouseMotionListener | Component |
MouseWheelListener | Component |
WindowListener | Window |
WindowFocusListener | Window |
WindowStateListener | Window |
建议:对这一部分了解需要先了解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中文网!
Atas ialah kandungan terperinci 对象可识别和响应的行为是什么?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!