4 Java事件模型的流程

为了使图形界面能够接收用户的操作,必须给各个组件加上事件处理机制。

在事件处理的过程中,主要涉及3类对象:

1.Event Source(事件源):事件发生的场所,通常就是各个组件,例如按钮、窗口、菜单等。

2.Event(事件):事件封装了GUI组件上发生的特定时期(通常就是一次用户操作)。如果程序需要获得GUI组件上所发生事件的相关信息,都通过Event对象来取得

3.EventListener(事件监听器):负责监听事件源所发生的时间,并对各种事件做出响应处理

事件响应的动作实际上就是一系列的程序语句,通常以方法的形式组织起来。但Java是面向对象的编程语言,方法不能独立存在,所以必须以类的形式来组织这些方法。因此事件监听器的核心就是它所包含的方法——这些方法也被称为事件处理器(Event Handler).当事件源上的事件发生时,事件对象会作为参数传给事件处理器(即事件监听器的实例方法)

当用户按下一个按钮,或者单击某个菜单项,或单击窗口右上角的状态按钮时,这些动作就会激发一个相应的事件,这个事件由AWT封装成一个相应的Event对象,该事件就会触发事件源上注册的事件监听器(特殊的Java对象),事件监听器就会调用对应的事件处理器来响应。

AWT的事件处理机制是一种委派式事件处理方式:普通组件(事件源)将整个事件处理委托给特定的对象(事件监听器);当该事件源发生指定的事件时,就通知所委托的事件监听器,由事件监听器来处理这个事件。

每个组件均可以针对特定的事件指定一个或多个事件监听对象,每个事件监听器也可以监听一个或多个事件源。因为同一个事件源上可能发生多个事件源。因为同一个事件源上可能发生多种事件,委派式事件处理方式可以把事件源上所有可能发生的事件分别授权给不同的事件监听器来处理;同时也可以让一类事件都使用同一个事件监听器来处理。

下面是AWT事件处理流程示意图:

packagechapter11;import java.awt.*;import java.awt.event.*;public classEventQs {private Frame f = new Frame("测试事件");private Button ok = new Button("确定");private TextField tf = new TextField(30);public voidinit(){//注册事件监听器

ok.addActionListener(newOKListener());

f.add(tf);

f.add(ok, BorderLayout.SOUTH);

f.pack();

f.setVisible(true);

}class OKListener implementsActionListener{//下面定义的方法是事件处理器,用于处理特定的事件

public voidactionPerformed(ActionEvent e){

System.out.println("用户单击了OK按钮");

tf.setText("Hello World");

}

}public static voidmain(String[] args){newEventQs().init();

}

};

View Code

上面的代码用于注册事件监听器,定义的方法就是事件处理器,当程序中的OK按钮被单击时,该处理器被触发,将看到程序中tf文本框变为Hello World,而程序控制台打印出"用户单击了OK按钮"字符串。

从上面程序可以看出,实现AWT事件处理机制的步骤如下:

1. 实现事件监听器类,该监听器类是一个特殊的Java类,必须实现一个XxxListener接口

2. 创建普通组件(事件源),创建事件监听器对象

3. 调用addXxxListener方法将事件监听器对象注册给普通组件(事件源)。这样当事件源发生指定事件时,AWT会触发事件监听器,由事件监听器调用相应的方法(事件处理器)来处理事件,事件源上所发生的事件会作为参数传入事件处理器。

5 事件和事件监听器

当外部动作在AWT组件上进行操作时,系统会自动生成事件对象,这个事件对象是EventObject子类的实例,该事件对象会自动触发注册到事件源上的事件监听器。

AWT事件机制涉及到三个成员:事件源、事件和事件监听器,其中事件源最容易创建,只要通过new来创建一个AWT组件,该组件就是事件源,事件的产生无须程序员关心,它是由虚拟机自动产生的,所以,实现事件监听器是整个事件处理的核心。

事件监听器必须实现事件监听器接口,AWT提供了大量的事件监听器接口用于实现不同类型的事件监听器,用于监听不同类型的事件。AWT中提供了丰富的事件类,用于封装不同组件上所发生的特定操作:AWT的事件类都是AWTEvent类的子类,它是EventObject类的子类。

EventObject类代表更广义的事件对象,包括Swing组件上所引发事件、数据库连接所引发的事情等。

AWT事件分为两大类:低级事件和高级事件。

5.1 低级事件

低级事件是指基于特定动作的事件。如鼠标的进入、点击、拖放等动作的鼠标事件,当组件得到焦点、失去焦点时触发焦点事件。

ComponentEvent:组件事件,当组件尺寸发生、位置发生移动、显示/隐藏状态发送改变时候触发该事件。

ContainerEvent:容器事件,当容器里发生添加组件、删除组件时触发该事件。

WindowEvent:窗口事件,当窗口状态发生改变(如打开、关闭、最大化、最小化)时触发

FocusEvent:焦点事件,当组件得到焦点或失去焦点时触发该事件。

KeyEvent:键盘事件,当键进行按下、松开、单击时触发该事件。

MouseEvent:鼠标事件,当鼠标进行单击、按下、松开、移动等动作时触发该事件

PaintEvent:组件绘制事件,该事件是一个特殊事件类型,当GUI组件调用update/paint方法来呈现自身时将触发该事件,该事件并非用于事件处理模型。

5.2 高级事件(语义事件)

高级事件是基于语义的事件,它可以不和特定的动作相关联,而依赖于触发此事件的类。比如,在TextField中按Enter键会触发ActionEvent事件,滑动滚动条会触发AdjustmentEvent事件,选中项目列表的某一条就会触发ItemEvent事件。

ActionEvent:动作事件,当按钮、菜单项被单机,TextField中按Enter键时触发

AdjustmentEvent:调节事件,在滑动条上移动滑块以调节数值时触发

ItemEvent:选项事件,当用户选中某项,或取消选中某项时触发

TextEvent:文本事件,当文本框、文本域里的文本发生改变时触发。

AWT中事件继承层次如图所示:

上图常用的AWT事件使用粗线框框出,对于系统没有用粗线框框出的事件,程序员很少使用它们,它们可能被作为事件基类或作为系统内部实现来使用。

不同事件需要使用不同的监听器监听,不同的监听器需要实现不同的监听器接口,当指定事件发生后,事件监听器就会调用所包含的事件处理器(实例方法)来处理事件。下表显示了常用事件、监听器接口和处理器之间的关系。

通过上表,可以大致知道常用组件可能发生哪些事件,以及该事件对应的监听器接口,通过实现该监听器接口就可以实现对应的事件处理器,然后通过addXxxListener方法来将事件监听器注册给指定的组件(事件源)。当事件源组件上发生特定事件时,被注册到该组件的事件监听器里的对应方法(事件处理器)将被触发。

实际上可以把事件处理模型简化成如下理解:当事件源组件发生事件时,系统将会执行该事件源组件的所有监听器里的对应方法。与前面编程方式不同的是:普通Java程序里的方法由程序主动调用,事件处理中的事件处理器方法由系统负责调用。

下面程序示范了一个监听器监听多个组件,一个组件被多个监听器监听的效果:

View Code

上面程序详细监听了窗口的每个动作,当用户单击窗口右上角的每个按钮时,程序作出相应的响应,当用户单击窗口的X按钮时,程序将正常退出。

大部分时候,程序无须监听窗口的每个动作,程序只需要为用户单击窗口的X按钮提供响应,无须为每个窗口事件提供响应——即程序只想重写windowClosing事件处理器,但因为该监听器实现了WindowListener接口,实现该接口就不得不实现该接口里的每个抽象方法,这是非常繁琐的事情。为此,AWT提供了事件适配器。

5.3 事件适配器

事件适配器是监听器接口的空实现:事件适配器实现了监听器接口,并为该接口里每个方法都提供了实现,这种实现是一种空实现(方法体内没有任何代码的实现)。当需要创建监听器时,可以通过继承事件适配器,而不是实现监听器接口,因为事件适配器已经为监听器接口的每个方法提供了空实现,所以程序自己的监听器无须实现监听器接口里的每个方法,只需要重写自己感兴趣的方法,从而可以简化事件监听器的实现类代码。

如果某个监听器接口只有一个方法,则该监听器接口就无须提供适配器,因为该接口对应的监听器别无选择,只能重写该方法。如果不重写该方法,就没有必要实现该监听器。

从上表可以看出,所有包含多个方法的监听器接口都有一个对应的适配器,但只包含一个方法的监听器接口没有对应的适配器。

下面通过事件适配器来创建事件监听器,程序如下:

View Code

上面程序只重写了windowClosing方法,其他方法没有重写。

5.4 事件监听器的实现形式

事件监听器是一个特殊的Java对象,实现事件监听器对象有如下几种形式:

1.内部类形式:将事件监听器类定义成当前类的内部类

2.顶级类形式:将事件监听器定义成一个顶级类

3.类本身作为事件监听器类:让当前类本身实现监听器接口或继承事件适配器。

4.匿名内部类形式:使用匿名内部类创建事件监听器对象

内部类形式

前面示例程序中的所有事件监听器类都是内部类形式,使用内部类可以在当前类中复用该监听器类。因为监听器类是外部类的内部类,所以可以自由访问外部类的所有GUI组件,这也是内部类的两个优势。

使用内部类定义事件监听器类的例子可以参看前面的例子程序,此处不再赘述。

顶级类形式

使用顶级类定义事件监听器类的形式比较少见,主要有如下两个原因:

1. 事件监听器通常属于特定的GUI界面,定义成顶级类不利于提高程序的内聚性。

2. 顶级类形式的事件监听器不能自由访问创建GUI界面的类中的组件,编程不够简洁。

但如果某个事件监听器确实需要被多个GUI界面所共享,而且主要是完成某种业务逻辑的实现,则可以考虑使用顶级类的形式来定义事件监听器类。下面程序定义了一个顶级类作为事件监听器类,该事件监听器类实现了发送邮件的功能:

View Code

上面监听器事件类没有与任何GUI界面耦合,创建该监听器对象时传入一个TextField对象,该文本框里的字符串被作为收件人地址。下面程序使用了该事件监听器来监听窗口中的按钮:

匿名内部类形式

大部分时候,事件处理器都没有什么复用价值(可复用代码通常都被抽象成了业务逻辑方法),因此大部分事件监听器只是临时使用一次,所以使用匿名内部类形式的事件监听器更合适。实际上,这种形式是目前使用最广泛的事件监听器形式。下面程序使用匿名内部类来创建事件监听器:

View Code

6 AWT的菜单

前面介绍了创建GUI界面的方式:将AWT组件按某种布局摆放在容器内即可。创建AWT菜单的方式与此完全类似:将菜单条、菜单、菜单项组合放在一起即可。

菜单条、菜单和菜单项

AWT中的菜单由如下几个类组合而成:

MenuBar:菜单条,菜单的容器

Menu:菜单组件,菜单项的容器

PopupMenu:上下文菜单组件(右键菜单组件)

MenuItem:菜单组件

CheckboxMenuItem:复选框菜单项组件

MenuShortcut:菜单快捷键组件

AWT菜单组件类之间的继承、组合关系,从下图可以看出MenuBar和Menu都实现了菜单容器接口,所以MenuBar可用于盛装Menu,而Menu可用于盛装MenuItem(包括Menu和CheckMenuItem两个子类对象),Menu还有一个子类:PopupMenu代表上下文菜单,上下文菜单无须使用MenuBar盛装。

Menu、MenuItem的构造器都可接受一个字符串参数,该字符串作为其对应菜单、菜单项上的标签文本。除此之外,MenuItem还可以接受一个MenuShortcut对象,该对象用于指定该菜单的快捷键。MenuShortcut类使用虚拟键代码(而不是字符)来创建快捷键。例如,Ctrl-A(通常都以Ctrl键作为快捷键的辅助键)快捷方式通过以下的代码创建:

MenuShortcut ms = new MenuShortcut(KeyEvent.VK_A);

如果该快捷键还需要Shift键的辅助,则可使用如下代码:

MenuShortcut ms = new MenuShortcut(keyEvent.VK_A, true);

有时候我们还希望将某个菜单进行分组,将功能相似的菜单分成一组,此时需要使用菜单分隔符,AWT中添加菜单分隔符有两种方法:

调用Menu对象的addSeparator方法来添加菜单分割线

添加new MenuItem("-")菜单项来添加菜单分隔线。

创建了MenuItem、Menu和MenuBar对象之后,然后调用Menu的add方法将多个MenuItem组合成菜单(也可将另一个Menu对象组合进来,从而形成二级菜单),再调用MenuBar的add方法将多个Menu组合成菜单条,最后调用Frame对象的setMenuBar为该窗口添加菜单条。

View Code

右键菜单

右键菜单使用PopupMenu对象表示,创建右键菜单的步骤如下:

1. 创建PopupMenu的实例

2. 创建多个MenuItem的多个实例,依次将这些实例加入PopupMenu中

3. 将PopupMenu加入到目标组件之中

4. 为需要出现上下文菜单的组件编写鼠标监听器,当用户释放鼠标右键时弹出右键菜单

下面程序创建了一个右键菜单,该右键菜单就是"借用"前面SimpleMenu中edit菜单中的所有菜单项,程序如下:

View Code

java程序设计B_Java程序设计11——GUI设计与事件处理B相关推荐

  1. java上位机开发(GUI设计)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途. 联系信箱:feixiaoxing @163.com] 对于上位机来说,GUI设计是很重要的一个环节.如果没有GUI,那就成了命令行工具了.对于java ...

  2. Java-GUI编程实战之管理系统 Day3【学生管理系统GUI设计、学生管理系统增删改查、项目MVC结构介绍、Java技能图谱】

    视频.课件.源码[链接:https://pan.baidu.com/s/13ffqGDzH-DZib6-MFViW3Q 提取码:zjxs] Java-GUI编程实战之管理系统 Day1[项目开发流程. ...

  3. 20175310 《Java程序设计》第11周学习总结

    20175310 <Java程序设计>第11周学习总结 教材学习内容总结 学习中的问题和解决过程 问题1:在做简易计算器时,测试乘法出错,如下图,显示格式错误: 问题1解决方案: 检查代码 ...

  4. 201521123014 《Java程序设计》第11周学习总结

    201521123014 <Java程序设计>第11周学习总结 1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多线程相关内容. 2. 书面作业 Q1 互斥访问与同步访 ...

  5. 基于java项目ssm二手书交易平台设计与实现(论文+程序设计源码+数据库文件)

    1 绪论 4 1.1 项目开发背景 4 1.2 项目开发意义 5 1.3 项目主要的内容 5 2 相关技术介绍及系统环境开发条件 6 2.1相关技术介绍 6 2.2系统环境开发条件 7 3 系统的需求 ...

  6. java开发网站学年论文,《Java程序设计》教学网站的设计【毕业论文】.doc

    您所在位置:网站首页 > 海量文档 &nbsp>&nbsp计算机&nbsp>&nbspJava <Java程序设计>教学网站的设计[毕业论 ...

  7. 合肥工业大学宣城校区Java技术实验二 基于GUI的网络通信程序设计

    一.实验目的 1.掌握Java中GUI程序的编写,包括事件监听机制. 2.掌握Java的网络通信编程,ServerSocket,Socket类的使用. 3.掌握Java中多线程的编程,Thread类, ...

  8. 【java毕业设计】基于java+swing+Eclipse的俄罗斯方块游戏GUI设计与实现(毕业论文+程序源码)——俄罗斯方块游戏

    基于java+swing+Eclipse的俄罗斯方块游戏GUI设计与实现(毕业论文+程序源码) 大家好,今天给大家介绍基于java+swing+Eclipse的俄罗斯方块游戏GUI设计与实现,文章末尾 ...

  9. 【java毕业设计】基于java+swing+GUI的雷电游戏GUI设计与实现(毕业论文+程序源码)——雷电游戏

    基于java+swing+GUI的雷电游戏GUI设计与实现(毕业论文+程序源码) 大家好,今天给大家介绍基于java+swing+GUI的雷电游戏GUI设计与实现,文章末尾附有本毕业设计的论文和源码下 ...

最新文章

  1. [计算机]“华为的冬天”——任正非(华为总裁)
  2. wxWidgets:添加菜单栏
  3. sublime的使用
  4. 安卓市场和安智市场_影响安卓应用市场搜索排名的五大因素
  5. LeetCode LRU Cache
  6. c语言编程发展史详细介绍,一张图让你了解编程语言发展史
  7. mysql集群脑裂问题_redis集群怎么解决脑裂问题
  8. final修饰的对象咋办?
  9. 收看IT播吧吉米老师iptables讲座
  10. DiffPDF(pdf文件比较工具)官方正式版V6.0.0 | diffpdf如何使用 | 含diffpdf的软件安装教程
  11. android传感器原理,浅谈Android传感器 III-磁传感器
  12. 新浪滚动新闻的json数据获取页面
  13. 计算机工程中级职称怎么考,以前中级职称是要考什么计算机-计算机软考中级职称哪个好考...
  14. 《C语言程序设计》第4版 何钦铭、颜晖主编 课后习题答案
  15. 植物大战僵尸:学会使用人造指针
  16. 人力外派和猎头的区别是什么?哪个行业更赚钱?
  17. MySQL#Update语句
  18. C语言零基础入门习题(八)四则运算
  19. 关于深度学习移动化的思考
  20. Kafka之分区副本与ISR

热门文章

  1. 2010年7月微软最有价值专家(MVP)当选名单
  2. Docker 概念详解
  3. shell脚本分析mysql慢查询日志(slow log)
  4. 心智图/思维导图(Mind Map/Mind Mapping),思维导图介绍
  5. Ubuntu系统下添加程序启动器
  6. centos 5.3 配置sendmail服务器
  7. [导入]注意!玩具也能成危险
  8. 取消MySQL timestamp列默认ON UPDATE CURRENT_TIMESTAMP
  9. python 简化连锁比较 pycharm提示Simplify chained comparison
  10. 堆溢出攻击(XP SP2 - 2003)