之前学习的内容只能形成一个用户界面,而用户不能对其有实际的操作,也就是说用户界面没有任何功能。要能够让图形界面接收用户的操作,就必须给各个组件加上事件处理机制。在事件处理的过程中,主要涉及三类对象:

  • Event-事件,用户对界面操作在java语言上的描述,以类的形式出现,例如键盘操作对应的事件类是KeyEvent。 
  • Event Source-事件源,事件发生的场所,通常就是各个组件,例如按钮Button。
  • Event handler-事件处理者,接收事件对象并对其进行处理的对象。

  例如,如果用户用鼠标单击了按钮对象button,则该按钮button就是事件源,而java运行时系统会生成ActionEvent类的对象actionE,该对象中描述了该单击事件发生时的一些信息,然后,事件处理者对象将接收由java运行时系统传递过来的事件对象actionE并进行相应的处理。

同一个事件源上可能发生多种事件,因此java采取了授权处理机制(Delegation Model),事件源可以把在其自身所有可能发生的事件分别授权给不同的事件处理者来处理。

有时也将事件处理者称为监听器,主要原因也在于监听器时刻监听着事件源上所有发生的事件类型,一旦该事件类型与自己所负责处理的事件类型一致,就马上进行处理。授权模型把事件的处理委托给外部的处理实体进行处理,实现了将事件源和监听器分开的机制。事件处理者(监听器)通常是一个类,该类如果要能够处理某种类型的事件,就必须实现与该事件类型相对的接口。例如类ButtonHandler之所以能够处理ActionEvent事件,原因在于它实现了与ActionEvent事件对应的接口ActionListener。每个事件类都有一个与之相对应的接口。

使用授权处理模型进行事件处理的一般方法归纳如下:

  1.对于某种类型的事件XXXEvent, 要想接收并处理这类事件,必须定义相应的事件监听器类,该类需要实现与该事件相对应的接口XXXListener;

具体的实现方法又有4种。

  2.事件源实例化以后,必须进行授权,注册该类事件的监听器,使用addXXXListener(XXXListener ) 方法来注册监听器。

  • 事件类

与AWT有关的所有事件类都由java.awt.AWTEvent类派生,它也是EventObject类的子类。AWT事件共有10类,可以归为两大类:低级事件和高级事件。

  java.util.EventObject类是所有事件对象的基础父类,所有事件都是由它派生出来的。AWT的相关事件继承于java.awt.AWTEvent类,这些AWT事件分为两大类:低级事件和高级事件,低级事件是指基于组件和容器的事件,当一个组件上发生事件,如:鼠标的进入,点击,拖放等,或组件的窗口开关等,触发了组件事件。高级事件是基于语义的事件,它可以不和特定的动作相关联,而依赖于触发此事件的类,如在TextField中按Enter键会触发ActionEvent事件,滑动滚动条会触发AdjustmentEvent事件,或是选中项目列表的某一条就会触发ItemEvent事件。

低级事件
  ComponentEvent( 组件事件:组件尺寸的变化,移动)
  ContainerEvent( 容器事件:组件增加,移动)
  WindowEvent( 窗口事件:关闭窗口,窗口闭合,图标化)
  FocusEvent( 焦点事件:焦点的获得和丢失)
  KeyEvent( 键盘事件:键按下、释放)
  MouseEvent( 鼠标事件:鼠标单击,移动)

高级事件(语义事件)
  ActionEvent(动作事件:按钮按下,TextField中按Enter键)
  AdjustmentEvent(调节事件:在滚动条上移动滑块以调节数值)
  ItemEvent(项目事件:选择项目,不选择"项目改变")
  TextEvent(文本事件,文本对象改变)

  • 事件监听器

每类事件都有对应的事件监听器,监听器是接口,根据动作来定义方法。

  例如,与键盘事件KeyEvent相对应的接口是:
  public interface KeyListener extends EventListener {
     public void keyPressed(KeyEvent ev);
     public void keyReleased(KeyEvent ev);
     public void keyTyped(KeyEvent ev);
  }

  注意到在本接口中有三个方法,那么java运行时系统何时调用哪个方法?其实根据这三个方法的方法名就能够知道应该是什么时候调用哪个方法执行了。当键盘刚按下去时,将调用keyPressed( )方法执行,当键盘抬起来时,将调用keyReleased( )方法执行,当键盘敲击一次时,将调用keyTyped( )方法执行。

AWT的组件类中提供注册和注销监听器的方法:

  注册监听器:
  public void add<ListenerType> (<ListenerType>listener);

  注销监听器:
  public void remove<ListenerType> (<ListenerType>listener);

  例如Button类:
  public class Button extends Component {
     ……
     public synchronized void addActionListener(ActionListener l);
     public synchronized void removeActionListener(ActionListener l);
     ……}

AWT事件及其相应的监听器接口

事件类别
描述信息
接口名
方法
 ActionEvent 激活组件   ActionListener  actionPerformed(ActionEvent)
 ItemEvent 选择了某些项目   ItemListener  itemStateChanged(ItemEvent)
 MouseEvent 鼠标移动   MouseMotionListener  mouseDragged(MouseEvent)
 mouseMoved(MouseEvent)
鼠标点击等   MouseListener  mousePressed(MouseEvent)
 mouseReleased(MouseEvent)
 mouseEntered(MouseEvent)
 mouseExited(MouseEvent)
 mouseClicked(MouseEvent)
 KeyEvent 键盘输入   KeyListener  keyPressed(KeyEvent)
 keyReleased(KeyEvent)
 keyTyped(KeyEvent)
 FocusEvent 组件收到或失去焦点   FocusListener  focusGained(FocusEvent)
 focusLost(FocusEvent)
 AdjustmentEvent 移动了滚动条等组件   AdjustmentListener  adjustmentValueChanged(AdjustmentEvent)
 ComponentEvent 对象移动缩放显示隐藏等   ComponentListener  componentMoved(ComponentEvent)
 componentHidden(ComponentEvent)
 componentResized(ComponentEvent)
 componentShown(ComponentEvent)
 WindowEvent 窗口收到窗口级事件   WindowListener  windowClosing(WindowEvent)
 windowOpened(WindowEvent)
 windowIconified(WindowEvent)
 windowDeiconified(WindowEvent)
 windowClosed(WindowEvent)
 windowActivated(WindowEvent)
 windowDeactivated(WindowEvent)
 ContainerEvent 容器中增加删除了组件   ContainerListener  componentAdded(ContainerEvent)
 componentRemoved(ContainerEvent)
 TextEvent 文本字段或文本区发生改变   TextListener  textValueChanged(TextEvent)
 
  • 事件适配器

      为什么要事件适配器

一个组件可以注册多个监听器,这些监听器响应某个事件的顺序是不确定的与该监听器注册的顺序没有关系。但是监听器类去实现其对应的接口时必须要实现其所有方法,但某些方法是用不到的。

WindowAdapter 是一个抽象类,实现了WindowListener 的所有方法,当 组件注册了 WindowAdapter 适配器后,不需要再去实现所有的成员方法,只需要重写需要用到方法就可以了,这样可以保证代码的整洁。

Java语言为一些Listener接口提供了适配器(Adapter)类。可以通过继承事件所对应的Adapter类,重写需要方法,无关方法不用实现。事件适配器为我们提供了一种简单的实现监听器的手段, 可以缩短程序代码。但是,由于java的单一继承机制,当需要多种监听器或此类已有父类时,就无法采用事件适配器了。

1.事件适配器--EventAdapter

  java.awt.event包中定义的事件适配器类包括以下几个:
  1.ComponentAdapter( 组件适配器)
  2.ContainerAdapter( 容器适配器)
  3.FocusAdapter( 焦点适配器)
  4.KeyAdapter( 键盘适配器)
  5.MouseAdapter( 鼠标适配器)
  6.MouseMotionAdapter( 鼠标运动适配器)
  7.WindowAdapter( 窗口适配器)

 2. 用内部类实现事件处理

  内部类(inner class)是被定义于另一个类中的类,使用内部类的主要原因是由于:

  • 一个内部类的对象可访问外部类的成员方法和变量,包括私有的成员。  
  • 实现事件监听器时,采用内部类、匿名类编程非常容易实现其功能。  
  • 编写事件驱动程序,内部类很方便。    因此内部类所能够应用的地方往往是在AWT的事件处理机制中。

3.匿名类(Anonymous Class)

  当一个内部类的类声名只是在创建此类对象时用了一次,而且要产生的新类需继承于一个已有的父类或实现一个接口,才能考虑用匿名类,由于匿名类本身无名,因此它也就不存在构造方法,它需要显示地调用一个无参的父类的构造方法,并且重写父类的方法。所谓的匿名就是该类连名字都没有,只是显示地调用一个无参的父类的构造方法。

  • 事件类具体的实现方法有以下几种:

    (1)内部类实现监听器接口

    • 实现代码
    public class Demo01 {
    
        public static void main(String[] args) {
    final Frame frame = new Frame("事件");
    frame.setBounds(100, 100, 300, 180);
    frame.setVisible(true); //匿名内部类 frame.addWindowListener(new WindowListener (){ @Override
    public void windowActivated(WindowEvent e) {
    // TODO Auto-generated method stub } @Override public void windowClosed(WindowEvent e) {
    // TODO Auto-generated method stub } @Override
    //进行窗口的关闭时被调用
    public void windowClosing(WindowEvent e) {
    //在匿名类内部访问外部变量,则该变量一定是 final
    System.out.println("closeing"); frame.dispose();//关闭当前窗口 } @Override
    public void windowDeactivated(WindowEvent e) {
    // TODO Auto-generated method stub } @Override
    public void windowDeiconified(WindowEvent e) {
    // TODO Auto-generated method stub } @Override
    public void windowIconified(WindowEvent e) {
    // TODO Auto-generated method stub } @Override
    public void windowOpened(WindowEvent e) {
    // TODO Auto-generated method stub } }); } }

    要关闭窗口,则要用到 WindowEvent 类,并且去实现 WindowListener 接口,然后创建WindowListener的对象,再用 frame 去调用 addWindowListener()方法,该对象作为参数,即注册了一个事件监听器。

    在匿名内部类的成员方法中 用 frame 调用dispose() 方法来关闭当前窗口。

    关闭按钮为一个事件源,当用户点击关闭按钮后,会触发 closeing 这一事件,此时监听器会捕获这一事件,当监听器(接口)捕获到 closeing 事件时,会去调用它的 closing 方法。程序会执行关闭 frame 这一方法来关闭当前窗口。

    (2)容器类(外部类)实现监听器接口

    • 实现代码
    public class Demo02 implements WindowListener{
    //定义 Frame 类的成员变量
    public Frame frame ;
    //构造函数
    public Demo02(Frame frame){ this.frame = frame;
    }
    public static void main(String[] args) {
    final Frame frame = new Frame("事件");
    //实例化监听器(容器)类,并将 frame 对象作为参数传递过去
    Demo02 d = new Demo02(frame);
    //注册监听器
    frame.addWindowListener(d); frame.setBounds(100, 100, 400, 280);
    frame.setVisible(true);
    }
    @Override
    public void windowActivated(WindowEvent e) {
    // 不需要的方法体为空
    }
    @Override
    public void windowClosed(WindowEvent e) {
    // TODO Auto-generated method stub }
    @Override
    public void windowClosing(WindowEvent e) {
    frame.dispose();
    }
    @Override
    public void windowDeactivated(WindowEvent e) {
    // TODO Auto-generated method stub }
    @Override
    public void windowDeiconified(WindowEvent e) {
    // TODO Auto-generated method stub }
    @Override
    public void windowIconified(WindowEvent e) {
    // TODO Auto-generated method stub }
    @Override
    public void windowOpened(WindowEvent e) {
    // TODO Auto-generated method stub }
    }

    使用 1 个容器类也可以实现多个监听器接口,但要注意的是在AWT中就经常用到声明和实现多个接口。记住无论实现了几个接口,接口中已定义的方法必须一一实现,如果对某事件不感兴趣,可以不具体实现其方法,而用空的方法体来代替。但却必须所有方法都要写上。

    (3)自定义子类实现内部接口

    • 代码实现
    public class MyWindowListener implements WindowListener{
    public Frame frame;
    //以frame 对象作为参数的构造方法
    public MyWindowListener(Frame frame){
    this.frame = frame;
    } @Override
    public void windowActivated(WindowEvent e) {
    // TODO Auto-generated method stub }
    @Override
    public void windowClosed(WindowEvent e) {
    // TODO Auto-generated method stub
    }
    @Override
    public void windowClosing(WindowEvent e) {
    frame.dispose();
    } @Override
    public void windowDeactivated(WindowEvent e) {
    // TODO Auto-generated method stub } @Override
    public void windowDeiconified(WindowEvent e) {
    // TODO Auto-generated method stub }
    @Override
    public void windowIconified(WindowEvent e) {
    // TODO Auto-generated method stub
    }
    @Override
    public void windowOpened(WindowEvent e) { }
    }

    因为在前面编写的第一个程序中已经进行了 Frame 类的实例化,所以此段代码中只做声明就可以了,运行时系统会自动访问前边的frame对象完成操作,不需要进行实例化以及 设置frame 用frame 对象去注册监听器等操作。 实质上以上第二种和第三种方法可以视为相同。

    (4)采用适配器

    • 代码实现
    public class Demo03 {
    
        public static void main(String[] args) {
    final Frame frame = new Frame("事件");
    frame.setBounds(100, 100, 300, 180);
    frame.setVisible(true);
    //匿名内部类
    frame.addWindowListener(new WindowAdapter(){
    //重写需要的方法
    @Override
    public void windowClosing(WindowEvent arg0) { frame.dispose();
    } });
    }
    }

    WindowAdapter 是一个抽象类,实现了WindowListener 的所有方法(空实现),当 组件注册了 WindowAdapter 适配器后,不需要再去实现所有的成员方法,只需要重写需要用到方法就可以了,这样可以保证代码的整洁。

  • AWT组件库(1)

1. 按钮(Button)

  按钮是最常用的一个组件,其构造方法是:Button b = new Button("Quit");
  当按钮被点击后,会产生ActionEvent事件,需ActionListener接口进行监听和处理事件。
  ActionEvent的对象调用getActionCommand()方法可以得到按钮的标识名,缺省按钮名为label。
  用setActionCommand()可以为按钮设置组件标识符。

2.复选框 (Checkbox)

  复选框提供简单的"on/off"开关,旁边显示文本标签。
  
  构造方法如下:
  setLayout(new GridLayout(3,1));
  add(new Checkbox("one",null,true));
  add(new Checkbox("two"));
  add(new Checkbox("three"));
  复选框用ItemListener 来监听ItemEvent事件,当复选框状态改变时用getStateChange()获取当前状态。使用getItem()获得被修改复选框的字符串对象。

3.复选框组(CheckboxGroup)

  使用复选框组,可以实现单选框的功能。方法如下:
  setLayout(new GridLayout(3, 1));
  CheckboxGroup cbg = new CheckboxGroup();
  add(new Checkbox("one", cbg, true));
  add(new Checkbox("two", cbg, false));
  add(new Checkbox("three", cbg, false));

  • AWT组件库(2)

4. 下拉式菜单(Choice)

  下拉式菜单每次只能选择其中的一项,它能够节省显示空间,适用于大量选项。
  Choice Colorchooser=new Choice();
  Colorchooser.add("Green");
  Colorchooser.add("Red");
  Colorchooser.add("Blue");
  Choice 用ItemListener接口来进行监听

 5. Canvas

  一个应用程序必须继承Canvas类才能获得有用的功能,比如创建一个自定义组件。如果想在画布上完成一些图形处理,则Canvas类中的paint()方法必须被重写。
  Canvas组件监听各种鼠标,键盘事件。当在Canvas组件中输入字符时,必须先调用requestFocus()方法。

6. 单行文本输入区(TextField)

  只能显示一行,当回车键被按下时,会发生ActionEvent事件,可以通过ActionListener中的actionPerformed()方法对事件进行相应处理。可以使用setEditable(boolean)方法设置为只读属性。

  单行文本输入区构造方法如下:
  TextField tf1,tf2,tf3,tf4:
  tf1=new TextField();
  tf2=new TextField("",20); //显示区域为20列
  tf3=new TextField("Hello!"); //按文本区域大小显示
  tf4=new TextField("Hello!",30); //初始文本为Hello!, 显示区域为30列

  • AWT组件库(3)

7. 文本输入区(TextArea)

  TextArea可以显示多行多列的文本。使用setEditable(boolean)方法,可以将其设置为只读的。在TextArea中可以显示水平或垂直的滚动条。
要判断文本是否输入完毕,可以在TextArea旁边设置一个按钮,通过按钮点击产生的ActionEvent对输入的文本进行处理。

8. 列表(List)

  列表中提供了多个文本选项,列表支持滚动条,可以浏览多项
  List lst=new List(4,false); //两个参数分别表示显示的行数、是否允许多选
  lst.add("Venus");
  lst.add("Earth");
  lst.add("JavaSoft");
  lst.add("Mars");
  cnt.add(lst);

 9. 框架(Frame)

  Frame是顶级窗口,可以显示标题,重置大小。当Frame被关闭,将产生WindowEvent事件,Frame无法直接监听键盘输入事件。

 10. 对话框(Dialog)

  它是Window类的子类。对话框和一般窗口的区别在于它依赖于其它窗口。对话框分为非模式(non-modal)和模式(modal)两种。

 11. 文件对话框(Filedialog)

  当用户想打开或存储文件时,使用文件对话框进行操作。主要代码如下:
  FileDialog d=new FileDialog(ParentFr,"FileDialog");
  d.setVisible(true);
  String filename=d.getFile();

 12. 菜单(Menu)

  无法直接将菜单添加到容器的某一位置,也无法使用布局管理器对其加以控制。菜单只能被添加?quot;菜单容器"(MenuBar)中。

 13. MenuBar

  只能被添加到Frame对象中,作为整个菜单树的根基。
  Frame fr = new Frame("MenuBar");
  MenuBar mb = new MenuBar();
  fr.setMenuBar(mb);
  fr.setSize(150,100);
  fr.setVisible(true);

 14. Menu

  下拉菜单。它可以被添加到MenuBar中或其它Menu中。
  Frame fr = new Frame("MenuBar");
  MenuBar mb = new MenuBar();
  fr.setMenuBar(mb);
  Menu m1 = new Menu("File");
  Menu m2 = new Menu("Edit");
  Menu m3 = new Menu("Help");
  mb.add(m1);
  mb.add(m2);
  mb.setHelpMenu(m3);
  fr.setSize(200,200);
  fr.setVisible(true);
   

 15. MenuItem

  MenuItem是菜单树中的"叶子节点"。MenuItem通常被添加到一个Menu中。对于MenuItem对象可以添加ActionListener,使其能够完成相应的操作。
  Menu m1 = new Menu("File");
  MenuItem mi1 = new MenuItem("Save");
  MenuItem mi2 = new MenuItem("Load");
  MenuItem mi3 = new MenuItem("Quit");

  m1.add(mi1);
  m1.add(mi2);
  m1.addSeparator();
  m1.add(mi3);

  • 总结

组件是各种各样的类,封装了图形系统的许多最小单位,例如按钮、窗口等等;而容器也是组件,它的最主要的作用是装载其它组件,但是象Panel这样的容器也经常被当作组件添加到其它容器中,以便完成杂的界面设计。布局管理器是java语言与其它编程语言在图形系统方面较为显著的区别,容器中各个组件的位置是由布局管理器来决定的,共有5种布局管理器,每种布局管理器都有自己的放置规律。事件处理机制能够让图形界面响应用户的操作,主要涉及到事件源、事件、事件处理者等三方,事件源就是图形界面上的组件,事件就是对用户操作的描述,而事件处理者是处理事件的类。因此,对于AWT中所提供的各个组件,我们都需要了解该组件经常发生的事件以及处理该事件的相应的监听器接口。

AWT初步— 事件处理模型的更多相关文章

  1. Java NIO 与 基于reactor设计模式的事件处理模型

    Java NIO非堵塞应用通常适用用在I/O读写等方面,我们知道,系统运行的性能瓶颈通常在I/O读写,包括对端口和文件的操作上,过去,在打开一个I/O通道后,read()将一直等待在端口一边读取字节内 ...

  2. AWT/Swing——事件处理

    前言 当用户点击图形界面上的一个按钮或者其他Component时要有所响应,这才是实现了图形界面的交互功能.如何做出这些响应我们就需要了解事件的处理机制.下面将分为以下内容介绍AWT(Swing)中事 ...

  3. AWT初步—Frame和 Panel

    初识 AWT       GUI 和 AWT GUI:Graphics User Interface  图形用户界面 AWT:Abstract Window Toolkit  抽象窗口工具集 之前的程 ...

  4. Swing与AWT在事件模型处理上是一致的。

    Swing与AWT在事件模型处理上是一致的. Jframe实际上是一堆窗体的叠加. Swing比AWT更加复杂且灵活. 在JDK1.4中,给JFRAME添加Button不可用jf.add(b).而是使 ...

  5. Swing与AWT在事件模型处理上是一致的

    Swing与AWT在事件模型处理上是一致的. Jframe实际上是一堆窗体的叠加. Swing比AWT更加复杂且灵活. 在JDK1.4中,给JFRAME添加Button不可用jf.add(b).而是使 ...

  6. javascript——事件处理模型(DOM 和 IE)

    javascript的事件处理模型分为 DOM事件处理模型和 IE事件处理模型. 一.DOM事件流模型 DOM事件流分为三个阶段:捕获阶段.目标阶段.冒泡阶段. 捕获阶段:自上而下,由document ...

  7. Nginx学习笔记(一):Nginx 进程模型 / 事件处理模型

    Nginx 进程模型 ​​​​ 多进程模型 进程间相互独立,无需加锁,且互不影响: 一个进程退出了不影响其他的进程运行,降低风险: 当请求到来,多个 worker 通过竞争 accrpt_mutex ...

  8. JavaScript事件:事件处理模型(冒泡、捕获)、取消冒泡、阻止默认事件

    (一)事件处理模型---事件冒泡.捕获 (1)事件冒泡 24 <body> 25 <div class="warpper"> 26 <div clas ...

  9. I/O事件处理模型之Reactor和Proactor 【转】

    http://blog.ddup.us/?p=280 这篇博客说的很清楚,赞一个: 在编写服务端软件的时候,如何处理各种I/O事件是其中很重要的一部分.在Unix Network Programmin ...

随机推荐

  1. MySQL性能调优与诊断

    * 本篇随笔为<涂抹MySQL>一书的阅读摘抄,详细请查看正版书籍 关键性指标 IOPS(Input/Output operations Per Second) 每秒处理的I/O请求次数 ...

  2. 使用tinymce富文本

    1.tinymce入门参考 https://www.tiny.cloud/docs/general-configuration-guide/basic-setup/ 2.tinymce安装选项 htt ...

  3. 对 UDP 的一些思考

    先放两个链接 快速可靠协议-KCP 可靠 UDP 传输 最近在玩王者荣耀,发觉两件事: 1. 可以 4G 和 wifi 无痛切换 2. 当网络不好的时候,发出去的消息并不保证到达服务器.比如你在很卡的 ...

  4. Java学习笔记30(集合框架四:List接口)

    List接口继承自Collection接口 具有重要的三大特点: 1.有序集合:存入和取出的顺序一致 2.此接口的用户可以对列表中每个元素插入位置精确的控制:可以通过索引操作 3.可以存储重复元素 L ...

  5. Linux - history命令的常用方法

    history命令 打印所有命令记录:history 打印最近10条记录:history 10 执行第123条命令记录:!123 重复执行上一条命令:!! 执行最后一次以ls开头的命令:!ls 逐屏列 ...

  6. 惊艳,Dubbo域名已改,也不再局限于Java!

    今天作者想去 Dubbo 官网查下相关资料,发现官方域名由 dubbo.io 直接跳转至 dubbo.apache.org 下了,然后突然回想起 Dubbo 已经在 2 月份正式进入了 Apache ...

  7. LeetCode--No.008 String to Integer (atoi)

    8. String to Integer (atoi) Total Accepted: 112863 Total Submissions: 825433 Difficulty: Easy Implem ...

  8. IdentityServer Token验证

    查看源码:https://github.com/IdentityServer/IdentityServer4/tree/release API使用Client Credentials的token验证是 ...

  9. 使用配置文件自定义Ribbon配置

    1.application.yml——Ribbon配置文件 debug: false spring: application: name: mcc-ribbon-properties cloud: c ...

  10. winhex十六进制常用快捷键

    Winhex的常用快捷键 摘要: Winhex 是一个专门用来对付各种日常紧急情况的工具.它可以用来检查和修复各种文件.恢复删除文件.硬盘损坏造成的数据丢失等.同时它还可以让你看到其他程序隐藏起来的文 ...