您现在的位置: 中国男护士网 >> 考试频道 >> 计算机等级 >> 二级辅导 >> JAVA >> 辅导 >> 正文    
  JAVA教程第五讲AWT图形用户界面设计5.2 【注册男护士专用博客】          

JAVA教程第五讲AWT图形用户界面设计5.2

www.nanhushi.com     佚名   不详 

5.2 AWT事件处理模型

  上一节中的主要内容是如何放置各种组件,使图形界面更加丰富多彩,但是还不能响应用户的任何操作,要能够让图形界面接收用户的操作,就必须给各个组件加上事件处理机制。在事件处理的过程中,主要涉及三类对象:

  
◇ Event-事件,用户对界面操作在java语言上的描述,以类的形式出现,例如键盘操作对应的事件类是KeyEvent。

  ◇ Event Source-事件源,事件发生的场所,通常就是各个组件,例如按钮Button。

  ◇ Event handler-事件处理者,接收事件对象并对其进行处理的对象

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

  由于同一个事件源上可能发生多种事件,因此java采取了授权处理机制(Delegation Model),事件源可以把在其自身所有可能发生的事件分别授权给不同的事件处理者来处理。比如在Canvas对象上既可能发生鼠标事件,也可能发生键盘事件,该Canvas对象就可以授权给事件处理者一来处理鼠标事件,同时授权给事件处理者二来处理键盘事件。有时也将事件处理者称为监听器,主要原因也在于监听器时刻监听着事件源上所有发生的事件类型,一旦该事件类型与自己所负责处理的事件类型一致,就马上进行处理。授权模型把事件的处理委托给外部的处理实体进行处理,实现了将事件源和监听器分开的机制。事件处理者(监听器)通常是一个类,该类如果要能够处理某种类型的事件,就必须实现与该事件类型相对的接口。例如例5.9中类ButtonHandler之所以能够处理ActionEvent事件,原因在于它实现了与ActionEvent事件对应的接口ActionListener。每个事件类都有一个与之相对应的接口。

  将事件源对象和事件处理器(事件监听器)分开。如图5.2所示
    
  打个不太恰当的比喻,比如说有一位李先生,李先生可能会发生很多法律纠纷,可能是民事法律纠纷,也可能是刑事法律纠纷,那么李先生可以请律师,他可以授权王律师负责帮他打民事法律的官司,同时也可以授权张律师帮他打刑事法律的官司。这个请律师的过程从李先生的角度来看,就是授权的过程,而从王律师和张律师的角度来看,一旦被授权,他们就得时刻对李先生负责,"监听"着李先生,一旦发生民事纠纷了,王律师就要马上去处理,而一旦发生刑事纠纷了,张律师就要马上进行处理。此时此刻,李先生就是事件源,王律师是一个事件处理者,张律师是另外一个事件处理者,民事纠纷和刑事纠纷就是不同类型的事件。
  

 例5.9
    import java.awt.*;
    import java.awt.event.*;
    public class TestButton {
    public static void main(String args[])
    {
      Frame f = new Frame("Test");
      Button b = new Button("Press Me!");
      b.addActionListener(new ButtonHandler()); /*注册监听器进行授权,该方法的参数是事件处理者对象,要处理的事件类型可以从方法名中看出,例如本方法要授权处理的是ActionEvent,因为方法名是addActionListener。*/
      f.setLayout(new FlowLayout()); //设置布局管理器
      f.add(b);
      f.setSize(200,100);
      f.setVisible(true);
      }
    }
    class ButtonHandler implements ActionListener {
    //实现接口ActionListener才能做事件ActionEvent的处理者
    public void actionPerformed(ActionEvent e)
    //系统产生的ActionEvent事件对象被当作参数传递给该方法
    {
      System.out.println("Action occurred");
    //本接口只有一个方法,因此事件发生时,系统会自动调用本方法,需要做的操作就把代码写在则个方法里。
    }
    }

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

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

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

5.2.1 事件类

  与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(文本事件,文本对象改变)

5.2.2 事件监听器

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

  例如,与键盘事件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( )方法执行。

  又例如窗口事件接口:
  public interface WindowListener extends EventListener{
     public void windowClosing(WindowEvent e);
     //把退出窗口的语句写在本方法中
     public void windowOpened(WindowEvent e);
     //窗口打开时调用
     public void windowIconified(WindowEvent e);
     //窗口图标化时调用
     public void windowDeiconified(WindowEvent e);
     //窗口非图标化时调用
     public void windowClosed(WindowEvent e);
     //窗口关闭时调用
     public void windowActivated(WindowEvent e);
     //窗口激活时调用
     public void windowDeactivated(WindowEvent e);
     //窗口非激活时调用
  }

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

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

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

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

5.2.3 AWT事件及其相应的监听器接口(1)

  表5.1列出了所有AWT事件及其相应的监听器接口,一共10类事件,11个接口。下面这张表应能牢牢记住。

表5.1

事件类别 描述信息 接口名 方法
 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)

5.2.3 AWT事件及其相应的监听器接口(2)

  例5.10说明事件处理模型的应用。

例5.10
  import java.awt.*;
  import java.awt.event.*;
    public class ThreeListener implements MouseMotionListener,MouseListener,WindowListener {
    //实现了三个接口
    private Frame f;
    private TextField tf;
    public static void main(String args[])
    {
     ThreeListener two = new ThreeListener();
     two.go(); }

    public void go() {
    f = new Frame("Three listeners example");
    f.add(new Label("Click and drag the mouse"),"North");
    tf = new TextField(30);
    f.add(tf,"South"); //使用缺省的布局管理器
    f.addMouseMotionListener(this); //注册监听器MouseMotionListener
    f.addMouseListener(this); //注册监听器MouseListener
    f.addWindowListener(this); //注册监听器WindowListener
    f.setSize(300,200);
    f.setVisible(true);
      }

    public void mouseDragged (MouseEvent e) {
    //实现mouseDragged方法
    String s = "Mouse dragging : X="+e.getX()+"Y = "+e.getY();
    tf.setText(s);
      }
    public void mouseMoved(MouseEvent e){}
    //对其不感兴趣的方法可以方法体为空
    public void mouseClicked(MouseEvent e){}
    public void mouseEntered(MouseEvent e){
      String s = "The mouse entered";
      tf.setText(s);
        }

    public void mouseExited(MouseEvent e){
      String s = "The mouse has left the building";
      tf.setText(s);
        }

    public void mousePressed(MouseEvent e){}
    public void mouseReleased(MouseEvent e){ }
    public void windowClosing(WindowEvent e) {
    //为了使窗口能正常关闭,程序正常退出,需要实现windowClosing方法
      System.exit(1);
        }

    public void windowOpened(WindowEvent e) {}
    //对其不感兴趣的方法可以方法体为空
    public void windowIconified(WindowEvent e) {}
    public void windowDeiconified(WindowEvent e) {}
    public void windowClosed(WindowEvent e) {}
    public void windowActivated(WindowEvent e) { }
    public void windowDeactivated(WindowEvent e) {}

    }

  上例中有如下几个特点:
  1.可以声明多个接口,接口之间用逗号隔开。
    ……implements MouseMotionListener, MouseListener, WindowListener;
  
  2.可以由同一个对象监听一个事件源上发生的多种事件:
  f.addMouseMotionListener(this);
  f.addMouseListener(this);
  f.addWindowListener(this);
  则对象f 上发生的多个事件都将被同一个监听器接收和处理。

  3.事件处理者和事件源处在同一个类中。本例中事件源是Frame f,事件处理者是类ThreeListener,其中事件源Frame f是类ThreeListener的成员变量。

  4.可以通过事件对象获得详细资料,比如本例中就通过事件对象获得了鼠标发生时的坐标值。
  public void mouseDragged(MouseEvent e) {
   String s="Mouse dragging :X="+e.getX()+"Y="+e.getY();
   tf.setText(s);
  }

  Java语言类的层次非常分明,因而只支持单继承,为了实现多重继承的能力,Java用接口来实现,一个类可以实现多个接口,这种机制比多重继承具有更简单、灵活、更强的功能。在AWT中就经常用到声明和实现多个接口。记住无论实现了几个接口,接口中已定义的方法必须一一实现,如果对某事件不感兴趣,可以不具体实现其方法,而用空的方法体来代替。但却必须所有方法都要写上。

5.2.4 事件适配器

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

 1.事件适配器--EventAdapter

  下例中采用了鼠标适配器:
  import java.awt.*;
  import java.awt.event.*;
  public class MouseClickHandler extends MouseAdaper{
    public void mouseClicked(MouseEvent e) //只实现需要的方法
       { ……}
  }

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


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

  内部类(inner class)是被定义于另一个类中的类,使用内部类的主要原因是由于:
  ◇ 一个内部类的对象可访问外部类的成员方法和变量,包括私有的成员。

  ◇ 实现事件监听器时,采用内部类、匿名类编程非常容易实现其功能。
  ◇ 编写事件驱动程序,内部类很方便。  
  因此内部类所能够应用的地方往往是在AWT的事件处理机制中。

例5.11
   import java.awt.* ;
   import java.awt.event.*;
     public class InnerClass{
       private Frame f;
       private TextField tf;
       public InnerClass(){
       f=new Frame("Inner classes example");
       tf=new TextField(30);
     }

     public voidi launchFrame(){
       Label label=new Label("Click and drag the mouse");
       f.add(label,BorderLayout.NORTH);
       f.add(tf,BorderLayout.SOUTH);
       f.addMouseMotionListener(new MyMouseMotionListener());/*参数为内部类对象*/
       f.setSize(300,200);
       f.setVisible(true);
     }

     class MyMouseMotionListener extends MouseMotionAdapter{ /*内部类开始*/
       public void mouseDragged(MouseEvent e) {
         String s="Mouse dragging: x="+e.getX()+"Y="+e.getY();
         tf.setText(s); }
       } ;

       public static void main(String args[]) {
         InnerClass obj=new InnerClass();
         obj.launchFrame();
       }
     }//内部类结束
    }

3.匿名类(Anonymous Class)

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


例5.12
   import java.awt.* ;
   import java.awt.event.*;
    public class AnonymousClass{
     private Frame f;
     private TextField tf;
     public AnonymousClass(){
      f=new Frame("Inner classes example");
      tf=new TextField(30);
    }
    public void launchFrame(){
      Label label=new Label("Click and drag the mouse");
      f.add(label,BorderLayout.NORTH);
      f.add(tf,BorderLayout.SOUTH);
      f.addMouseMotionListener(new MouseMotionAdapter(){ //匿名类开始
       public void mouseDragged(MouseEvent e){
        String s="Mouse dragging: x="+e.getX()+"Y="+e.getY();
        tf.setText(s); }
      } ); //匿名类结束
      f.setSize(300,200);
      f.setVisible(true);
      }
       public static void main(String args[]) {
        AnonymousClass obj=new AnonymousClass();
        obj.launchFrame();
        }
      }

  其实大家仔细分析一下,例5.11和5.12实现的都是完全一样的功能,只不过采取的方式不同。5.11中的事件处理类是一个内部类,而5.12的事件处理类是匿名类,可以说从类的关系来说是越来越不清楚,但是程序也越来越简练。熟悉这两种方式也十分有助于大家编写图形界面的程序。

 

文章录入:杜斌    责任编辑:杜斌 
  • 上一篇文章:

  • 下一篇文章:
  • 【字体: 】【发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口
     

    联 系 信 息
    QQ:88236621
    电话:15853773350
    E-Mail:malenurse@163.com
    免费发布招聘信息
    做中国最专业男护士门户网站
    最 新 热 门
    最 新 推 荐
    相 关 文 章
    没有相关文章
    专 题 栏 目

      网友评论:(只显示最新10条。评论内容只代表网友观点,与本站立场无关!)                            【进男护士社区逛逛】
    姓 名:
    * 游客填写  ·注册用户 ·忘记密码
    主 页:

    评 分:
    1分 2分 3分 4分 5分
    评论内容:
  • 请遵守《互联网电子公告服务管理规定》及中华人民共和国其他各项有关法律法规。
  • 严禁发表危害国家安全、损害国家利益、破坏民族团结、破坏国家宗教政策、破坏社会稳定、侮辱、诽谤、教唆、淫秽等内容的评论 。
  • 用户需对自己在使用本站服务过程中的行为承担法律责任(直接或间接导致的)。
  • 本站管理员有权保留或删除评论内容。
  • 评论内容只代表网友个人观点,与本网站立场无关。