zoukankan      html  css  js  c++  java
  • AWT初步— 事件处理模型

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

    • 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中所提供的各个组件,我们都需要了解该组件经常发生的事件以及处理该事件的相应的监听器接口。

                                                                        

  • 相关阅读:
    google glog 使用方法
    LIBRARY_PATH和LD_LIBRARY_PATH环境变量的区别
    c++ ‘nullptr’ 在此作用域中尚未声明
    Impala 使用的端口
    忽略“Signal: SIGSEGV (Segmentation fault)”
    查看python脚本的运行pid,让python脚本后台运行
    阿里云主机运行速度慢的解决办法
    在Git.oschina.net中配置TortoiseGit使用sshkey,无需输入账号和密码
    抓取国家的学校编码数据
    CAS统一登录认证好文汇集贴
  • 原文地址:https://www.cnblogs.com/linlin0/p/6293725.html
Copyright © 2011-2022 走看看