事件

本文详细介绍了Java中的事件处理机制,包括事件的发生与处理分离原则、自定义事件的创建方法及其实现步骤。并通过实例展示了如何定义事件、监听器以及事件处理程序。

在一个类Class1中写一个事件event1,  
  当Class1中的某个值变化时,就触发event1,  
   
  然后写另外一个类Class2,监听Class1中的event1事件,  
   
  public   class   A{  
          private   Vector   aListeners   =   new   Vector();  
          private   int   value;  
          public   int   getValue(){  
                  return   value;  
          }  
          public   void   setValue(int   newValue){  
                  if(value!=newValue){  
                          value   =   newValue;  
                          AEvent   evt=   new   AEvent(this,value);  
                          //如果值改变的话,就触发事件  
                          fireAEvent(evt);  
                  }  
          }  
          public   synchronized   void   addAListener(AListener   a){  
                  aListeners.addElement(a);  
          }  
          public   synchronized   void   removeAListener(Alistener   a){  
                  aListeners.removeElement(a);  
          }  
          public   void   fireAEvent(AEvent   evt){  
                  Vector   currentListeners   =   null;  
                  synchronized(this){  
                          currentListeners   =   (Vector)aListeners.clone();  
                  }  
                  for(int   i   =0;i<currentListeners.size();i++){  
                          AListener   listener   =   (AListener)currentListeners.elementAt(i);  
                          listener.performed(evt);  
                  }  
          }  
  }  
  //定义接口,当事件触发时调用  
  public   interface   AListener   extends   java.util.EventListener{  
          public   abstract   void   performed(AEvent   e);  
  }  
  //定义事件  
  public   class   AEvent   extends   EventObject{  
          private   int   value;  
          public   AEvent(Object   source){  
                  this(source,null);  
          }  
          public   AEvent(Object   source,int   newValue){  
                  super(source);  
                  value   =   newValue;  
          }  
  }  
  class   B{  
          public   B(){  
                  A   a   =   new   A();  
                  a.addAListener(new   AListener(){  
                          public   performed(AEvent   e){  
                                  //要处理的  
                          }  
                  });  
          }  
           
  }  

 

JAVA的事件处理机制的核心内容是:事件的发生与事件的处理相分离。也就是说,某一个组件发生了一些变化,则该组件只需要产生一个事件,而不用关心该事件如何被处理。其它组件如果对该事件感兴趣,则编写相应的事件处理代码。

举个例子:点击一个按钮,改变JPanel的背景色。事件的发生代码一定是写在按钮类里面的(由于这个事件已经被AWT定义好了,因此不用我们操心,后面会讲到自定义事件),而事件的处理代码一定是写在JPanel类里面的(我们会在继承于JPanel的一个类中定义一个ActionListener,实现actionPerformed方法),最后把这个ActionListener添加到JButton中,表示JPanel对JButton的点击事件感兴趣。

下面来谈一谈自定义事件,这才是本文的重点。首先请想一下,Event到底是什么?我认为,Event就是变化,比如鼠标移动了,窗口最大化了,甚至一个类的属性被改变了……但变化不是Event!那什么样的变化才能算是一个Event呢?其他组件感兴趣的变化才是一个Event。比如上面的点击按钮改变背景色,JButton被点击后,JPanel的颜色发生了变化,即JPanel对JButton的点击很感兴趣,因此,该点击才算是一个事件,才应该用到JAVA的事件处理机制:事件的发生与处理相分离!如果某一个类的变化只有他自己感兴趣,别的类都不感兴趣,那么就没必要使用JAVA的事件处理机制,直接把事件的处理代码写在该类中就可以了(JButton等类是系统定义的,我们很难去修改他的源代码,因此还是用事件处理机制比较好,我这里主要强调自定义的类)。

作为一个自定义的类,如果发生了某些变化,该如何处理这些变化呢?是自己写代码处理,还是利用JAVA的事件处理机制,把处理代码写到别的类里面呢?还是我上面那句话,要看看这个类的变化,其他类是否感兴趣。如果其他类都不感兴趣,那么毫无疑问自己解决就行了;如果只有有限的几个类感兴趣,那么自己解决或者使用JAVA的事件机制都行;如果对此感兴趣的其他类情况未知,数量未知,那么一定要调用JAVA的事件处理机制,自己是搞不定的。举个不太恰当的例子:比如刘德华的手破了流血了(一个只有自己感兴趣的事件),那么自己包扎一下就行了(自己处理);如果刘德华死了(他老婆和他感情很深,决定殉情),那么关于这一事件的处理,也可以由刘德华自己搞定(先杀掉老婆,在自杀);如果刘德华死了,世界上有无数多的fans决定一起殉情,这种情况就不是由刘德华一个人能搞定的了(华仔不能拿着一把菜刀寻遍全世界,把所有愿意殉情的fans都杀死再自杀吧,工程太浩大了~),只能采用JAVA事件处理机制,把刘德华的死讯通知全世界,愿意殉葬的fans自己自杀(如何处理事件完全由自己决定,不由华仔决定)。

那么自定义事件的代码该如何写呢?首先自定义一个MyEvent类,再自定义一个MyListener类,该类中有一个事件处理函数myPerformed。在发生事件的类里面定义一个MyListener[]数组,用于存放监听器。还要定义一个addMyListener()方法,方便别的组件注册监听器。最后在发生事件的地方遍历MyListener数组,调用每一个元素的myPerformed(MyEvent e)方法即可!

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Java开发中的事件驱动模型实例详解

2007-09-18 08:56 作者:陈宇 出处:论坛整理 责任编辑:方舟
  或许每个 软件从业者都有从学习控制台应用程序到学习可视化编程的转变过程,控制台应用程序的优点在于可以方便的练习某个语言的语法和开发习惯(如.net和java),而可视化编程的学习又可以非常方便开发出各类人机对话界面(HMI)。可视化编程或许是一个初学者开始对软件感兴趣的开始,也可能是一个软件学习的里程碑点,因为我们可以使用各类软件集成开发环境(IDE)方便的在现成的界面窗口上拖放各类组件(Component),这类组件包括我们常见的按钮(Button),单选按钮(Radio Button),复选框等(Checkbox)。这样的拖放式开发方式不但方便,而且窗口会立竿见影的显示在我们的面前,这对于一个软件初学者而言或许是一件非常有成就感的事情。

  但是很多软件学习者在学习可视化开发的过程中,只是非常表面的来理解可视化编程,他们可能认为能够使用拖放方式完成一个界面就非常值得称道,但是很少有人会认真的去理解编程语言对于可视化编程组件的支持和整合,在Softworks软件人才培训中心的两年教学过程,我深刻的感受到了这一点,因此下文将会结合我的教学经验来讲解可视化编程过程中最为关键的“事件驱动模型”。

  1.什么是事件驱动模型?

  在讲解事件驱动模型之前,我们现在看看事件驱动模型的三大要素:

  ·事件源:能够接收外部事件的源体。

  ·侦听器:能够接收事件源通知的对象。

  ·事件处理程序:用于处理事件的对象。

  学员应该要理解任何基于事件驱动模型的开发技术都包含以上三大要素,不管是.net还是java技术,甚至是以前我们使用的Visual Basic和Delphi语言都有基于以上三大要素的事件驱动模型开发流程。

  现在我们来看一个生活中的示例,如果有一天你走在路上一不小心被天上掉下来的花瓶砸到了,并且晕死了过去。那么整个过程其实就是一个事件处理流程,而且我们可以非常方便的分析出刚才所提到的事件驱动模型中的三大要素。

  1.被砸晕的这个人其实就是事件源,因为他是能够接受到外部的事件的源体。

  2.侦听器就是这个人的大脑神经,因为它会感知到疼痛。

  3.事件处理就是这个人晕死了过去。

  由于事件驱动模型在我们日常生活中是无处不在的,因此Java和其他的编程语言都将这一过程运用到了可视化编程中了。

  2.Java编程语言中的事件驱动模型

  在Java编程技术中,最常用的可视化编程当属Java Swing技术,Java Swing为开发者提供了很多现成的组件,如:按钮(JButton),单选按钮(JRadioButton)等。为了管理用户与组成程序图形用户界面的组件间的交互,必须理解在Java中如何处理事件。

  假设用户单击了程序图形用户界面中的一个按钮,其实该按钮就是这个事件的源(可以引发事件的物体)。所有的Java Swing对象都有感知自己被操作的能力,因此JButton按钮也具有这样能力。一个事件通常必须有一个源对象,这里就是JButton对象。当单击按钮时,JButton组件类会生成一个用于存放该事件参数的ActionEvent的对象,该对象包含了事件及事件源的信息。图1-1显示了这种机制。

  

  图 1-1

  当JButton感知到自己被点击以后会将这种感觉传递给某个侦听器对象,该侦听器对象原先已被告知对该类事件感兴趣,侦听器对象仅是一种侦听特定事件的对象。这里的“将事件传递给侦听器”仅意味着事件源调用侦听器对象中的一个特定方法,并以事件对象作为实参。侦听器对象可以侦听一个特定对象的事件(比如一个按钮)。

  其实可以使任何类的对象成为侦听器对象,只要使该类实现侦听器接口。你将会发现有各种各样的侦听器接口,以满足不同类型事件的需要。在这个单击按钮的例子中,需要实现ActionListener接口以便接收按钮事件。在侦听器接口声明的方法中,实现了接受这个事件对象并响应该事件的代码。在本例中,在事件发生时,调用了ActionListener接口中的actionPerformed()方法。每种侦听器接口都定义了特定的方法,用来接收该侦听器计划要处理的事件。

  仅仅实现侦听器接口还不足以将侦听器对象连接到事件源上,仍需要把侦听器与希望处理的事件单个源或多个源连接起来。通过调用事件源对象的特定方法,可以注册带有事件源的侦听器对象。例如,为了注册侦听单击按钮事件的侦听器,需要调用JButton对象的addActionListener()方法,该操作可以使侦听对象和事件源绑定。

  每个事件响应时只涉及到对该事件感兴趣的侦听器。由于侦听器只要求实现一个合适的接口,所以实际上,可以在任何希望的地方接收和处理事件。在Java中使用侦听器对象处理事件的方式,称为委托事件模型,这是因为对于诸如按钮这种组件引起的事件响应,并不是由引起事件的对象本身处理,而是委托独立的侦听器对象进行处理,刚才的actionPerformed()其实就是一个委托处理方法。现在让我们来看一下,JButton是如何将用户的点击转化成方法处理的(如图1-2)。

  图1-2

  

  JButton组件初始化代码片断:

    private void initialize() {

        frame = new JFrame();

        frame.getContentPane ().setLayout (null);

        frame.setBounds (100, 100, 247, 165);

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        frame.setTitle ("事件驱动程序");

        //btnPress就是这次点击操作中的事件源

        btnPress = new JButton();

        btnPress.setText ("Press");

        btnPress.setName ("Press");

        btnPress.setBounds (63, 98, 99, 23);

        //向事件源btnPress植入侦听器对象ButtonEventHandler

        btnPress.addActionListener (new ButtonEventHandler(this));

        frame.getContentPane ().add(btnPress);

        frame.getContentPane ().add(txtMessage);

    }

  侦听器创建的代码片断:

//侦听器对象ButtonEventHandler(用来侦听按钮的点击操作)

    class ButtonEventHandler implements ActionListener {

        //窗体对象

        private EventDemo form = null;

        //通过构造体传入窗体对象,

        //作用在于让侦听器对象明白事件源处于

        //哪个窗体容器中

        public ButtonEventHandler(EventDemo form) {

            this.form = form;

        }

 

        //委托方法

        public void actionPerformed(ActionEvent e) {

           //该方法将会把事件的处理权交给窗体容器类的

//btnPress_Click方法处理。

            this.form.btnPress_Click(e);

        }

    }

 

 真正的事件处理代码片断:

     /**

     * 按钮btnPress的事件处理方法。

     *

     * @param e 事件参数

     */

    private void btnPress_Click(ActionEvent e) {

       

        String message = "你点击的按钮名叫:"

            + ((JButton) e.getSource()).getName();

       

        this.txtMessage.setText(message);

    }

 

  代码工作原理:

  JButton组件初始化代码片断已经明确阐述了按钮被创建后放置于窗体上,关键在于本代码片断的以下语句:

  btnPress.addActionListener(new ButtonEventHandler(this));

  该语句就是向事件源植入了侦听器对象ButtonEventHandler,该类实现了ActionListener结构,因此JButton类的对象btnPress这个时候已经具有了处理用户点击按钮的能力了。

  当用户点击btnPress这个按钮的时候,按钮对象会直接把这次点击感觉传递给ButtonEventHandler的actionPerformed方法处理,为养成较好的编程习惯,我们中心并不建议学员直接在该委托方法中编写代码,而是需要将该事件处理再次转发给窗体中的某个方法来处理,这个方法的命名也必须是有规则的,就是事件源名+下划线+事件名(btnPress_Click),并且该方法必须具有事件参数ActionEvent,因为在该对象中明确指明了,哪个按钮受到了点击了。e.getSource()方法返回了被点击按钮的对象,由于这次被点击的是一个按钮,因此我们需要使用JButton对e.getSource()的返回值进行强转,随后通过getName()方法得到这个按钮的名字。至此整个点击事件处理完了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值