从零开始理解JAVA事件处理机制(3)
我们连续写了两小节的教师-学生的例子,必然觉得无聊死了,这样的例子我们就是玩上100遍,还是不知道该怎么写真实的代码。那从本节开始,我们开始往真实代码上面去靠拢。
事件最容易理解的例子是鼠标事件:我们点击鼠标,鼠标发送指令,执行代码。
一:鼠标点击事件处理模型基础版
这个时候,我们必须去查看下JDK中相关类型。对照着上一节《从零开始理解JAVA事件处理机制(2)》中的UML图,我们很快发现,对应HomeworkListener,JDK中有MouseListener,其实我们靠分析也能得知,MouseListener继承自EventListener。现在既然有了接口MouseListener了,那我们必定会有一个实现类,这个类假设叫做:ConcreteMouseListener。不妨先实现之:
package com.zuikc.events;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;public class ConcreteMouseListener implements MouseListener {
public ConcreteMouseListener(){
}
@Override
public void mouseClicked(MouseEvent e) {
System.out.printf("我被{%s}点了一下,MD痒死了~~", e.getSource().toString());
}@Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
}@Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}@Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}@Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}}
我们为单击的事件处理器添加业务代码。
事件处理器:监听器的具体实现类的实现方法,就叫事件处理器。
接下来要看什么,当然是MouseEvent。MouseEvent,这个JDK中的类相对来说,就稍微有点大了,起构造方法的参数有点多,不过没有关系呀,我们慢慢看,我先说这个类要怎么用,即怎么new出来。
/*
* 这里的new Component() {} 就是 event.getSource() 得到的事件源 source
*/
MouseEvent event = new MouseEvent(new Component() {}, 1, 1, 1,2,3,4,false);
在实际且正常的情况下,MouseEvent是没有必要自己new的,JAVA运行时会捕获硬件鼠标的点击动作,由虚拟机底层为我们生成该实例对象(下文会为我们分析这一点),但是我们此时此刻我们是先模拟呀,所以不妨碍我们自己胡乱new一个出来。注意,new不是问题,问题的关键我们必须知道其构造器参数的意义,而其中核心关键参数就是第一个参数,new Component(),这是什么?这就是那个事件源!回头看看我们的教师学生版本是在哪里生产事件的:
public void setHomework(String homework) {
System.out.printf("%s布置了作业%s \n", this.name, homework);
homeworks.add(homework);
HomeworkEventObject event = new HomeworkEventObject(this);
/*
* 在观察者模式中,我们直接调用Observable的notifyObservers来通知被观察者
* 现在我们只能自己通知了~~
*/
for (HomeworkListener listener : homeworkListenerList) {
listener.update(event, homework);
}}
是在Teacher的业务代码setHomework中。所以,在当前的我们要写的这个例子中,new MouseEvent要在哪里呢?我们在Button的业务代码中,Button是谁,Button就类似Teacher,但又不完全等同Teacher,在Teacher中,Teacher本身就是事件源,所以它这个this作为参数传入进了HomeworkEventObject,而Button不能作为参数传入进MouseEvent,因为我不打算让Button继承自Component,所以我们先new了一个临时的Component。OK,分析到了这里,我们自己的Button代码大概就出来了,是这个样子的:
package com.zuikc.events;
import java.awt.AWTEvent;
import java.awt.AWTEventMulticaster;
import java.awt.Component;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.peer.LightweightPeer;public class Button {
private MouseListener mouseListener;
public void addMouseListener(MouseListener l) {
mouseListener = l;
}
public void doClick(){
/*
* 这里的new Component() {} 就是 event.getSource() 得到的事件源 source
*/
MouseEvent event = new MouseEvent(new Component() {}, 1, 1, 1,2,3,4,false);
//event.getSource();
this.mouseListener.mouseClicked(event);
}
}
至此,我们可以画出清晰的类图了,来看:

顺便我们看一下Client端的代码:
public static void main(String[] args) {
ConcreteMouseListener listener = new ConcreteMouseListener();
Button button = new Button();
button.addMouseListener(listener);
button.doClick();
}
运行一下吧,你应该得到一句类似这样的输出:
我被{com.zuikc.events.Button$1[,0,0,0x0,invalid]}点了一下,MD痒死了~~
二,一个正常的窗体程序的样子
上面,我们尽量偏向于教师学生的例子,写出了鼠标事件的基础版本,但是说好的程序本来的样子呢?来,我们接下来写个正常的程序,99.9%在人在写窗体程序的时候就是如下这么写的。我知道你们又会有人上来骂了,什么,java,窗体程序?我TMD学JAVA是为了EE开发的,企业开发的。现在,我们先说好不好互相伤害,要知道,即便是NB如JAVA,最先也是先从窗体发迹的,并且,JAVA的窗体框架推倒重写了还不止一次。所以,窗体的事件你明白了,EE中那些框架的事件碰到了简直跟切白菜一样。
言归正传,看代码:
package com.zuikc.events;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JButton;
import javax.swing.JFrame;public class Client {
public static void main(String[] args) {
new DemoFrame();
}
}class DemoFrame extends JFrame implements MouseListener {
public DemoFrame() {
super("demo");
this.setSize(500, 400);
this.setLocationRelativeTo(null);
this.getContentPane().setLayout(null);
this.setVisible(true);JButton button1 = new JButton("ok");
button1.setBounds(8, 8, 80, 80);
button1.addMouseListener(this);
this.getContentPane().add(button1);
}@Override
public void mouseClicked(MouseEvent e) {
System.out.printf("我被{%s}点了一下,MD痒死了~~", e.getSource().toString());
}@Override
public void mousePressed(MouseEvent e) {
}@Override
public void mouseReleased(MouseEvent e) {
}@Override
public void mouseEntered(MouseEvent e) {
}@Override
public void mouseExited(MouseEvent e) {
}
}
这段代码什么意思?最简单了,就是创建了一个窗体,窗体上放置了一个按钮,点击了之后,执行了一行代码。这简简单单的一个文件,没多少行代码,实际上就实现了我们上文中一堆类中实现的功能。来吧,我们分析吧,把监听器、事件处理器、事件、事件源都指出来。
监听器:DemoFrame就是监听器,对应ConcreteMouseListener;
事件处理器:MouseClicked方法就是监听器,ConcreteMouseListener里面也有这个方法;
事件:看不到了,怎么办?
事件源:看不到了,怎么办?
注意,窗体本身就监听器,所以上文代码中为button添加监听器怎么做?button1.addMouseListener(this);没错,就是把自身添加进去。
然后,事件和事件源都看不到了,这个时候怎么办?我们如果看输出的话,上文代码的输出为:
我被{javax.swing.JButton[,8,8,80x80,invalid,alignmentX=0.0,alignmentY=0.5,border=javax.swing.plaf.BorderUIResource$CompoundBorderUIResource@7fda7dfe,flags=296,maximumSize=,minimumSize=,preferredSize=,defaultIcon=,disabledIcon=,disabledSelectedIcon=,margin=javax.swing.plaf.InsetsUIResource[top=2,left=14,bottom=2,right=14],paintBorder=true,paintFocus=true,pressedIcon=,rolloverEnabled=true,rolloverIcon=,rolloverSelectedIcon=,selectedIcon=,text=ok,defaultCapable=true]}点了一下,MD痒死了~~
看上去,类似我们上文第一部分代码的输出,也是JButton业务代码运行过程中生成的一个变量,但它是在哪里生成的,在哪里产生的,我们并不知道。不过没关系,我们看调试堆栈!
一步步的往上追,我们终于追到了这里:

由此可见,MouseEvent也是在业务代码里new出来了,大家可能要为,那这个重要的第一个参数target呢?target可是事件源也很重要,道理很简单,往上继续追,限于篇幅,这里不在展开,它在某个你愿意看到它的地方被new出来了。
现在我们补齐回答,
事件:JAVA运行时捕获到硬件鼠标触发,从而调用了事件处理器,在事件处理器内部生成的这个MouseEvent,就是事件;
事件源:JAVA运行时捕获到硬件鼠标触发,从而调用了事件处理器,在事件处理器内部生成的这个target,就是事件源;
三:正常版的上文第一部分的代码
按照二中的代码来写,我们第一部分的代码应该是什么样子的呢?
一和二放在一起比较,其实只要改两个地方,一中的代码就和二中完全一致了,
1:将ConcreteMouseListener命名为DemoFrame;
2:将Button实例由客户端放置到ConcreteMouseListener内部;
OK,事件就是这么简单。
该系列的第一部分和第二部分分别在:
从零开始理解JAVA事件处理机制(3)的更多相关文章
- 从零开始理解JAVA事件处理机制(2)
第一节中的示例过于简单<从零开始理解JAVA事件处理机制(1)>,简单到让大家觉得这样的代码简直毫无用处.但是没办法,我们要继续写这毫无用处的代码,然后引出下一阶段真正有益的代码. 一:事 ...
- 从零开始理解JAVA事件处理机制(1)
“事件”这个词已经被滥用了.正因为“事件”的被滥用,很多人在用到事件的时候不求甚解,依样画葫芦,导致学习工作了很多年,还是不清楚什么是事件处理器.什么是事件持有者.所以,如果你对于Event这个词还是 ...
- Java事件处理机制(深入理解)
本文是关于Java事件处理机制的梳理,以及有重点的介绍一些注意点,至于基础的概念啥的不多赘述. 一.Java事件处理机制初步介绍(看图理解) 根据下图,结合生活实际,可以得知监护人可以有多个,坏人对小 ...
- java事件处理机制
java中的事件机制的参与者有3种角色: 1.event object:就是事件产生时具体的"事件",用于listener的相应的方法之中,作为参数,一般存在与listerne ...
- 理解Java类加载机制(译文)
理解java类加载机制 你想写类加载器?或者你遇到了ClassCastException异常,或者你遇到了奇怪的LinkageError状态约束异常.应该仔细看看java类的加载处理了. 什么是类加载 ...
- Java基础 -- 深入理解Java异常机制
异常指不期而至的各种状况,如:文件找不到.网络连接失败.非法参数等.异常是一个事件,它发生在程序运行期间,干扰了正常的指令流程.Java通 过API中Throwable类的众多子类描述各种不同的异常. ...
- [转]Java事件处理机制- 事件监听器的四种实现方式
原文来自http://stefan321.iteye.com/blog/345221 自身类作为事件监听器 外部类作为事件监听器 匿名内部类作为事件监听器 内部类作为事件监听器 自身类作为事件监听器: ...
- 【转】深入理解java异常处理机制
深入理解java异常处理机制 ; int c; for (int i = 2; i >= -2; i--) { c = b / i; System.out.println("i=&qu ...
- 转:一个经典例子让你彻彻底底理解java回调机制
一个经典例子让你彻彻底底理解java回调机制 转帖请注明本文出自xiaanming的博客(http://blog.csdn.net/xiaanming/article/details/17483273 ...
随机推荐
- 详解Executor框架
在Java中,使用线程来异步执行任务.Java线程的创建与销毁需要一定的开销,如果我们为每一个任务创建一个新线程来执行,这些线程的创建与销毁将消耗大量的计算资源.同时,为每一个任务创建一个新线程来执行 ...
- C#数据结构之串
串(string)是n(n>=0)个字符组成的有限序列. 由于串中的字符都是连续存储的,在C#中有恒定不变的特性.一经创建就保持不变. 为了区别C#中的string,因此以stringDS类模拟 ...
- OnsenUI 前端框架(三)
上一章咱们学习了OnsenUI的工具栏.侧边栏和标签栏.通过对页面上这三部分的学习,咱们对混合应用的一个页面有了大体上的认识.从这一章开始,咱们学习OnsenUI混合项目开发过程中会用到的各种各样的组 ...
- Web层框架对网站中所有异常的统一解决
一个网站的异常信息作为专业的人士,是不会轻易暴露给用户的,因为那样狠不安全,显得你漏是一回事,只要还是考虑到网站的数据安全问题,下面给大家分享一下一些常见的web层框架是如何处理统一的异常. 之前都是 ...
- APP品牌具体有哪几个要素?又是如何操作的?
对于品牌的一些认识 首先我们要知道,品牌是由用户与公司及其产品&服务互动后所产生的,失去了与用户互动并且承认的是伪品牌,对于开发者来说,APP的品牌要先从标志与颜色考虑起,但实话实说,标志与颜 ...
- Spring+SpringMVC+MyBatis+easyUI整合优化篇(十四)谈谈写博客的原因和项目优化
阶段总结 又到了优化篇的收尾阶段了,这其实是一篇阶段总结性的文章,今天是4月29号,距离第一次发布博客已经两个月零5天,这两个多月的时间,完成了第一个项目ssm-demo的更新,过程中也写了33篇博客 ...
- Python错误集
1-->IndentationError:expected an indented block >IndentationError: unindent does not match a ...
- C# Redis学习系列三:Redis配置主从
Redis配置主从 主IP :端口 192.168.0.103 6666 从IP:端口 192.168.0.108 3333 配置从库 (1)安装服务: redis-server ...
- SpringAOP原理
原理 AOP(Aspect Oriented Programming),也就是面向方面编程的技术.AOP基于IoC基础,是对OOP的有益补充.AOP将应用系统分为两部分,核心业务逻辑(Core bus ...
- UDP协议详解
1.UDP协议的作用 IP协议无法区别同一个主机系统上的多个应用程序.UDP采用端口标识同一主机上的不同应用程序. 无法采取进程ID来标识不同应用程序的原因: 1)系统中应用程序的进程ID分配和销毁是 ...