第9章AWT事件模型 本模块讨论了事件驱动的图形用户界面(GUD的用户输入机制。 The J uage Basics G出 in& smed asad and Ty Artas Ex ception Handling Developing Graphical User Inte rfaces Evnt ]ode1 Netcon玄 第一节相关问题 讨论一以下为与本模块内容有关的问题 哪些部分对于一个图形用户界面来说是必需的? 个图形化程序如何处理鼠标点击或者其他类型的用户交互? 第二节目标 完成本模块之后,你应当能够: 编写代码来处理在图形用户界面中发生的事件 描述 Adapter类的概念,包括如何和何时使用它们 根据事件对象的细节来确定产生事件的用户动作 为各种类型的事件创建合适的接口和事件处理器 第三节什么是事件? 什么是事件? 事件一描述发生了什么的对象 事件源一事件的产生器 事件处理器一接收事件、解释事件并处理用户交互的方法 如果用户在用户界面层执行了一个动作(鼠标点击和按键),这将导致一个事件的发生。事件是描述发生了什么的对象 存在各种不同类型的事件类用来描述各种类型的用户交互
104 第9章 AWT 事件模型 本模块讨论了事件驱动的图形用户界面(GUI)的用户输入机制。 第一节 相关问题 讨论 - 以下为与本模块内容有关的问题: - 哪些部分对于一个图形用户界面来说是必需的? - 一个图形化程序如何处理鼠标点击或者其他类型的用户交互? 第二节 目 标 完成本模块之后,你应当能够: - 编写代码来处理在图形用户界面中发生的事件 - 描述 Adapter 类的概念,包括如何和何时使用它们 - 根据事件对象的细节来确定产生事件的用户动作 - 为各种类型的事件创建合适的接口和事件处理器。 第三节 什么是事件? 如果用户在用户界面层执行了一个动作(鼠标点击和按键),这将导致一个事件的发生。事件是描述发生了什么的对象。 存在各种不同类型的事件类用来描述各种类型的用户交互。 什么是事件? - 事件-描述发生了什么的对象 - 事件源-事件的产生器 - 事件处理器-接收事件、解释事件并处理用户交互的方法
93.1事件源 事件源是一个事件的产生者。例如,在Butn组件上点击鼠标会产生以这个 Button为源的一个 Action event这个 Action Event实例是一个对象,它包含关于刚才所发生的那个事件的信息的对象。这些信息包括 etAction Command一返回与动作相关联的命令名称。 Getmodifiers一返回在执行动作时持有的修饰符 932事件处理器 事件处理器就是一个接收事件、解释事件并处理用户交互的方法 第四节JDK1.0的事件模型与JDKL.2的事件模型比较 JDK1.0的事件模型与JDK1,2的事件模型比较 次模型(JDK10) 委托模型(JDK12) 在JDK1.1中,事件接收和处理的方法发生了重要的改变。本节将比较以前的事件模型(JDK10)和当前的事件模型 (JDK1.1和JDK1.2)。 JDK1.0采用的是层次事件模型,而JDK11以及更高的版本采用的是委托事件模型。 941层次模型(JDK1.0) 层次模型是基于容器的。事件先发送到组件,然后沿容器层次向上传播。没有被组件处理的事件会自动地继续传播 到组件的容器 JDK1.0的事件模型与JDK1.2的事件模型比较 例如,在下图中,Buon对象(包含在一个 Frame上的Pane中)上的鼠标点击首先向 Button发送一个动作事件。如果 它没有被 Button处理,这个事件会被送往Pane,如果它在那儿仍然没有被处理,这个事件会被送往 frame 层次模型(JDK1.0) 优点 简单,而且非常适合面向对象的编程环境。 缺 事件只能由产生这个事件的组件或包含这个组件的容器处理。 -为了处理事件,你必须定义接收这个事件的组件的子类,或者在基 容器创建 handle Evento方法。 Frame lane Button Action event
105 9.3.1 事件源 事件源是一个事件的产生者。例如,在 Button 组件上点击鼠标会产生以这个 Button 为源的一个 ActionEvent. 这个 ActionEvent 实例是一个对象,它包含关于刚才所发生的那个事件的信息的对象。这些信息包括: - getActionCommand-返回与动作相关联的命令名称。 - GetModifiers-返回在执行动作时持有的修饰符。 9.3.2 事件处理器 事件处理器就是一个接收事件、解释事件并处理用户交互的方法。 第四节 JDK1.0 的事件模型与 JDK1.2 的事件模型比较 在 JDK1.1 中,事件接收和处理的方法发生了重要的改变。本节将比较以前的事件模型(JDK1.0)和当前的事件模型 (JDK1.1 和 JDK1.2)。 JDK1.0 采用的是层次事件模型,而 JDK1.1 以及更高的版本采用的是委托事件模型。 9.4.1 层次模型(JDK1.0) 层次模型是基于容器的。 事件先发送到组件,然后沿容器层次向上传播。没有被组件处理的事件会自动地继续传播 到组件的容器。 JDK1.0 的事件模型与 JDK1.2 的事件模型比较 例如,在下图中,Button 对象(包含在一个 Frame 上的 Panel 中)上的鼠标点击首先向 Button 发送一个动作事件。如果 它没有被 Button 处理,这个事件会被送往 Panel,如果它在那儿仍然没有被处理,这个事件会被送往 Frame。 JDK1.0 的事件模型与 JDK1.2 的事件模型比较 - 层次模型(JDK 1.0) - 委托模型(JDK 1.2) 层次模型(JDK1.0) 优点 - 简单,而且非常适合面向对象的编程环境。 缺点 - 事件只能由产生这个事件的组件或包含这个组件的容器处理。 - 为了处理事件,你必须定义接收这个事件的组件的子类,或者在基 容器创建 handleEvent()方法
层次模型(JDK1.0)(续) 这种模型有一个显著的优点: 它简单,而且非常适合面向对象的编程环境:说到底,所有的组件都继承了javaawt.componenT类,而handleevent 就在 java. awt. Component类中。 然而,这种模型也存在缺点: 事件只能由产生这个事件的组件或包含这个组件的容器处理。这个限制违反了面向对象编程的一个基本原则 功能应该包含在最合适的类中。而最适合处理事件的类往往并不是源组件的容器层次中的成员。 大量的CPU周期浪费在处理不相关的事件上。任何对于程序来说不相关或者并不重要的事件会沿容器层次一路 传播,直到最后被抛弃。不存在一种简单的方法来过滤事件。 为了处理事件,你必须定义接收这个事件的组件的子类,或者在基容器创建一个庞大的 handleevent0方法。 委托事件模型是在JDKL.1中引入的。在这个模型中,事件被送往产生这个事件的组件,然而,注册一个或多个称为 监听者的类取决于每一个组件,这些类包含事件处理器,用来接收和处理这个事件。采用这种方法,事件处理器可以安 排在与源组件分离的对象中。监听者就是实现了 Listener接口的类 Frame Panel and Frame event handlers Acton event ction handler actionPerformed (ActionEvent e)t 事件是只向注册的监听者报告的对象。每个事件都有一个对应的监听者接口,规定哪些方法必须在适合接收那种类 型的事件的类中定义。实现了定义那些方法的接口的类可以注册为一个监听者 942委托模型 从没有注册的监听者的组件中发出的事件不会被传播。 例如,这是一个只含有单个 Button的简单 Frame 1. import java. awt.* 4. public static void main(String args[]) i 6. Button b= new Button(Press Me!)i 10.f. setvisible(true)i Button handler类是一个处理器类,事件将被委托给这个类 3.public class ButtonHandler implements ActionListener 4. public void actionPerformed(ActionEvent e)t
106 层次模型(JDK1.0)(续) 这种模型有一个显著的优点: - 它简单,而且非常适合面向对象的编程环境;说到底,所有的组件都继承了 java.awt.Component类,而 handleEvent() 就在 java.awt.Component 类中。 然而,这种模型也存在缺点: - 事件只能由产生这个事件的组件或包含这个组件的容器处理。这个限制违反了面向对象编程的一个基本原则: 功能应该包含在最合适的类中。而最适合处理事件的类往往并不是源组件的容器层次中的成员。 - 大量的 CPU 周期浪费在处理不相关的事件上。任何对于程序来说不相关或者并不重要的事件会沿容器层次一路 传播,直到最后被抛弃。不存在一种简单的方法来过滤事件。 - 为了处理事件,你必须定义接收这个事件的组件的子类,或者在基容器创建一个庞大的 handleEvent()方法。 委托事件模型是在 JDK1.1 中引入的。在这个模型中,事件被送往产生这个事件的组件,然而,注册一个或多个称为 监听者的类取决于每一个组件,这些类包含事件处理器,用来接收和处理这个事件。采用这种方法,事件处理器可以安 排在与源组件分离的对象中。监听者就是实现了 Listener 接口的类。 事件是只向注册的监听者报告的对象。每个事件都有一个对应的监听者接口,规定哪些方法必须在适合接收那种类 型的事件的类中定义。实现了定义那些方法的接口的类可以注册为一个监听者。 9.4.2 委托模型 从没有注册的监听者的组件中发出的事件不会被传播。 例如,这是一个只含有单个 Button 的简单 Frame。 1.import java.awt.*; 2. 3.public class TestButton { 4.public static void main(String args[]) { 5.Frame f = new Frame("Test"); 6.Button b = new Button("Press Me!"); 7.b.addActionListener(new ButtonHandler()); 8.f.add(b,"Center"); 9.f.pack(); 10.f.setVisible(true); 11.} 12.} ButtonHandler 类是一个处理器类,事件将被委托给这个类。 1.import java.awt.event.*; 2. 3.public class ButtonHandler implements ActionListener { 4.public void actionPerformed(ActionEvent e) {
5. System. out. println("Action occurred") 6. System. out. println("Buttons label is 7+e. getActioncommand())i 这两个范例的特征如下 Bun类有一个 add Action Listner(ActionListener)方法 Addiction listner接口定义了一个方法 action Performed,用来接收一个 Action event 创建一个 Button对象时,这个对象可以通过使用 add Action Listener方法注册为 Action Events的监听者。调用这 个方法时带有一个实现了 Action Listener接口的类的参数 委托模型(JDK.或更高版本) 优点 事件不会被意外地处理 有可能创建并使用适配器( adapter)类对事件动作进行分类 委托模型有利于把工作分布到各个类中 缺点 不容易将JDK10代码移植到JDKl.1上 委托模型(JDK1.1或更高版本)(续) 在 Button对象上用鼠标进行点击时,将发送一个 Action event事件。这个 Action Event事件会被使用 ddActionListenerO方法进行注册的所有 ActionListener的 action Performed方法接收 Action event类的 getAction Commando方法返回与动作相关联的命令名称。以按钮的点击动作为例,将返回 Button 的标签。 这种方法有若干优点 事件不会被意外地处理。在层次模型中,一个事件可能传播到容器,并在非预期的层次被处理。 有可能创建并使用适配器( adapter)类对事件动作进行分类。 委托模型有利于把工作分布到各个类中。 新的事件模型提供对 Javabeans的支持。 这种方法也有一个缺点 尽管当前的JDK支持委托模型和JDK1.0事件模型,但不能混合使用JDκ1.0和JDKI. 第五节图形用户界面的行为 9.51事件类型 我们己经介绍了在单一类型事件上下文中从组件接收事件的通用机制。事件类的层次结构图如下所示。许多事件类 在 java. awt event包中,也有一些事件类在API的其他地方。 对于每类事件,都有一个接口,这个接口必须由想接收这个事件的类的对象实现。这个接口还要求定义一个或多个 方法。当发生特定的事件时,就会调用这些方法。表9-1列出了这些(事件)类型,并给出了每个类型对应的接口名称,以 ContainerEvent java. awt AWTEvent FocusEvent Com ponentevent InputEvent java beans. bean Context Bean contextEvent
107 5.System.out.println("Action occurred"); 6.System.out.println("Button's label is : ' 7.+ e.getActionCommand()); 8.} 9.} 这两个范例的特征如下: - Button 类有一个 addActionListner(ActionListener)方法。 - AddActionListner 接口定义了一个方法 actionPerformed,用来接收一个 ActionEvent。 - 创建一个 Button 对象时,这个对象可以通过使用 addActionListener 方法注册为 ActionEvents 的监听者。调用这 个方法时带有一个实现了 ActionListener 接口的类的参数。 委托模型(JDK1.1 或更高版本)(续) - 在 Button 对象上用 鼠标进行 点击时 ,将发送 一个 ActionEvent 事件 。这个 ActionEvent 事件会被 使用 addActionListener()方法进行注册的所有 ActionListener 的 actionPerformed()方法接收。 - ActionEvent类的 getActionCommand()方法返回与动作相关联的命令名称。以按钮的点击动作为例,将返回 Button 的标签。 这种方法有若干优点: - 事件不会被意外地处理。在层次模型中,一个事件可能传播到容器,并在非预期的层次被处理。 - 有可能创建并使用适配器(adapter)类对事件动作进行分类。 - 委托模型有利于把工作分布到各个类中。 - 新的事件模型提供对 JavaBeans 的支持。 这种方法也有一个缺点: - 尽管当前的 JDK 支持委托模型和 JDK1.0 事件模型,但不能混合使用 JDK1.0 和 JDK1.1。 第五节 图形用户界面的行为 9.5.1 事件类型 我们已经介绍了在单一类型事件上下文中从组件接收事件的通用机制。事件类的层次结构图如下所示。许多事件类 在 java.awt.event 包中,也有一些事件类在 API 的其他地方。 对于每类事件,都有一个接口,这个接口必须由想接收这个事件的类的对象实现。这个接口还要求定义一个或多个 方法。当发生特定的事件时,就会调用这些方法。表 9-1 列出了这些(事件)类型,并给出了每个类型对应的接口名称,以 委托模型(JDK1.1 或更高版本) 优点 - 事件不会被意外地处理。 - 有可能创建并使用适配器 (adapter)类对事件动作进行分类。 - 委托模型有利于把工作分布到各个类中。 缺点 - 不容易将 JDK1.0 代码移植到 JDK1.1 上
及所要求定义的方法。这些方法的名称是易于记忆的,名称表示了会引起这个方法被调用的源或条件 表9-1方法类型和接口 Category Interface Name Methods Action ActionListener actionPerformed (actionEvent) Mouse motion MouseMo tionlistener Mouse button Mouselistener mouseEntered(Mous eVent) mouseClicked(Mous eVent) KeyListener keyReleased( KeyEvent) ocus FocusListener focus Gained( Focus Event) focusLo st(Focusevent Adjustment AdjustmentListener ComponentListener componentMoved(ComponentEvent) componentHidden (ComponentEvent) component Shown(ComponentEvent) 表9-1方法类型和接口(续) Window Window listener window Closing( Window Event window iconified(window Event) indow closed( window Event) window Deactivated(window Event) Container ContainerListener componentAdded( ContainerEvent) componentRemoved( ContainerEvent TextLis tener textValue ChangedcTextEvent 9.52复杂的范例 本节将考察一个更复杂的Jawa软件范例。它将跟踪鼠标被按下时,鼠标的移动情况(鼠标拖动)。这个范例还将监测当 鼠标没有按下时,鼠标的移动情况(鼠标移动)。 当鼠标按下或没有按下时,移动鼠标产生的事件会被实现了 Mouse Motion listener接口的类的对象检取。这个接口要 求定义两个方法, mouse Dragged和 mouseMove(。即使你只对鼠标拖动感兴趣,也必须提供这两个方法。然而, mouseMove的体可以是空的 要检取其他鼠标事件,包括鼠标点击,必须定义 Mouselistener接口。这个接口包括若干个事件, mouseEntered
108 及所要求定义的方法。这些方法的名称是易于记忆的,名称表示了会引起这个方法被调用的源或条件。 表 9-1 方法类型和接口 Category Interface Name Methods Action ActionListener actionPerformed(ActionEvent) Item ItemListener itemStateChanged(ItemEvent) Mouse motion MouseMotionListener mouseDragged(MouseEvent) mouseMoved(MouseEvent) Mouse button MouseListener mousePressed(MouseEvent) mouseReleased(MouseEvent) mouseEntered(MouseEvent) mouseExited(MouseEvent) mouseClicked(MouseEvent) Key KeyListener keyPressed(KeyEvent) keyReleased(KeyEvent) keyTyped(KeyEvent) Focus FocusListener focusGained(FocusEvent) focusLost(FocusEvent) Adjustment AdjustmentListener adjustmentValueChanged (AdjustmentEvent) Component ComponentListener componentMoved(ComponentEvent) componentHidden(ComponentEvent) componentResized(ComponentEvent) componentShown(ComponentEvent) 表 9-1 方法类型和接口(续) 9.5.2 复杂的范例 本节将考察一个更复杂的 Java 软件范例。它将跟踪鼠标被按下时,鼠标的移动情况(鼠标拖动)。这个范例还将监测当 鼠标没有按下时,鼠标的移动情况(鼠标移动)。 当鼠标按下或没有按下时,移动鼠标产生的事件会被实现了 MouseMotionListener 接口的类的对象检取。这个接口要 求定义两个方法,mouseDragged()和 mouseMoved()。即使你只对鼠标拖动感兴趣,也必须提供这两个方法。然而, mouseMoved()的体可以是空的。 要检取其他鼠标事件,包括鼠标点击,必须定义 MouseListener 接口。这个接口包括若干个事件,即:mouseEntered