1. 不同类型事件对应不同类型的监听器接口:
1) 总的来说就是实现了该种类型的接口,就能监听并处理该种类型的事件;
2) 常见的事件类型有ActionEvent、WindowEvent、TextEvent(文本框中产生的事件,比如正在输入文字等)、MouseEvent(鼠标事件)等;
3) AWT都分别为各种事件类型准备了监听器接口:ActionListener、WindowListener、TextListener等,可以发现命名规律就是XxxEvent对应XxxListener接口;
4) 除了MouseEvent之外,MouseEvent对应了两种监听器接口,一个是普通的MouseListener(监听并处理普通的鼠标事件,如点击、松开等),但是鼠标是一种特殊的输入设备,还具有拖动的效果,因此针对这种事件AWT还专门准备了MouseMotionListener接口专门用来监听这种事件;
!!因此对于MouseEvent事件比较特殊,普通鼠标事件和鼠标拖动事件都属于MouseEvent这一种类别,但是实际上系统会把这两种动作的事件发送给不同的监听器,一种是MouseListener监听器,一种是MouseMotionListener监听器,实际编程时要注意,不要以为还有一种MouseMotionEvent的事件!!
2. 监听器接口的方法:
1) 每种监听器接口对应了一种类型的事件,比如ActionListener接口就代表了动作事件这一类事件,但接口中定义的每种方法分别用来处理该种类型事件的一小类;
2) 比如WindowListener接口中定义了7个方法,分别对应了窗口类型事件的7种事件,比如窗口打开、缩小、关闭等,监听器会根据具体发生的事件来调用对应的方法来处理,这个过程是自动的,当事件发生时并不是用户调用这些方法处理,而是“监听器”自动调用;
!!其实也不是监听器自己调用的,而是虚拟机(Java操作系统)调用的,即用户写的方法由操作系统来调用,这就是典型的回调函数,将用户的方法作为参数传入操作系统提供的系统函数来执行,即操作系统的0级代码调用用户写的3级代码,就是这种关系;
!!只不过Java没有函数的概念,全部都包装成面向对象的类了;
3) 既然要实现监听器接口,那就必须实现里面的全部方法,比如WindowListener里面的全部7个方法,一个都不能少(否则编译报错),但有些接口,比如ActionListener只有一个方法,那该接口就是一种函数式接口,可以使用Lambda表达式进行函数闭包;
!!虽然ActionListener只有一个方法,但并不代表ActionEvent就只有一种事件,其实有很多,按钮单击、菜单项单击等等,只不过具体发生的是什么事件需要在方法体中判断了;
3. ActionListener:
1) 只有一个方法来处理所有的ActionEvent事件:public void actionPerformed(ActionEvent e);
2) Java的Event类型的继承结构是EventObject -> AWTEvent -> 各种Event(ActionEvent、WindowEvent等);
3) 常用方法:public String ActionEvent.getActionCommand(); // 获取触发ActionEvent的组件的命令名(比如对于按钮就返回按钮上的文本)
4. WindowListener示例:
1) 监听器可以同时监听多个组件就意味着监听器也可以实现多种Listener接口,同时监听多个、不同类型事件的组件;
2) 该示例中的监听器同时实现两种接口,一个ActionListener另一个WindowListener,并真正意义上实现程序可关闭;
3) 其实只要调用System.exit(0)就可以实现正常关闭;
4) 示例:
public class AwtTest { Frame f = new Frame("WindowEvent Test"); TextArea ta = new TextArea(6, 40); Button btn = new Button("button"); class Listener implements ActionListener, WindowListener { @Override public void actionPerformed(ActionEvent e) { // TODO Auto-generated method stub ta.append("Button pushed!\n"); } @Override public void windowOpened(WindowEvent e) { // 打开 // TODO Auto-generated method stub ta.append("Window opened!\n"); } @Override public void windowClosing(WindowEvent e) { // 正在关闭 // TODO Auto-generated method stub ta.append("Window closing!\n"); System.exit(0); } @Override public void windowClosed(WindowEvent e) { // 已关闭 // TODO Auto-generated method stub ta.append("Window closed!\n"); } @Override public void windowIconified(WindowEvent e) { // 最小化 // TODO Auto-generated method stub ta.append("Window iconified!\n"); } @Override public void windowDeiconified(WindowEvent e) { // 恢复 // TODO Auto-generated method stub ta.append("Window deiconified!\n"); } @Override public void windowActivated(WindowEvent e) { // 得到焦点 // TODO Auto-generated method stub ta.append("Window activated!\n"); } @Override public void windowDeactivated(WindowEvent e) { // 失去焦点 // TODO Auto-generated method stub ta.append("Window deactivated!\n"); } } public void init() { f.add(ta); f.add(btn, BorderLayout.SOUTH); Listener l = new Listener(); f.addWindowListener(l); btn.addActionListener(l); f.pack(); f.setVisible(true); } public static void main(String[] args) { new AwtTest().init(); } }
!当System.exit的退出码为0时表示程序正常退出;
!!通常不建议一个监听器实现多个Listener接口,因为这不符合科学的设计模式,还是分工分模块为好,尽量减弱软件的模块耦合度;
5. 事件适配器:
1) 由于要实现Listener接口就必须实现其中的全部方法,但大多数情况下并不需要实现全部方法而只想实现感兴趣的那几个方法,但即使其他方法不感兴趣也不得不加上那几个方法的空方法体,显得非常多此一举;
2) 因此AWT还提供了事件适配器,它就是一个类,只不过实现了对应的监听器接口,并为每个方法提供过了一个空的方法体,因此要实现监听器功能的时候就没必要直接实现对应的接口了,只要继承相应的适配器,然后选择你感兴趣的方法实现就行了,不需要实现接口中的所有方法;
3) 接口和适配器命名的规则:XxxListener对应XxxAdapter
4) 示例:只需要实现感兴趣的方法就行哦!
public class AwtTest { Frame f = new Frame("WindowAdapter Test"); class Listener extends WindowAdapter { @Override public void windowClosing(WindowEvent e) { // TODO Auto-generated method stub // super.windowClosing(e); System.exit(0); } } public void init() { f.addWindowListener(new Listener()); f.pack(); f.setVisible(true); } public static void main(String[] args) { new AwtTest().init(); } }