你好,欢迎来到电脑编程技巧与维护杂志社! 杂志社简介广告服务读者反馈编程社区  
合订本订阅
 
 
您的位置:杂志经典 / 编程语言
定制自己Listener的一般方法
 

  : 本文在Java 1.1的事件处理委托模型的基础上,得出了创建自己Listener的一般方法,并通过例程给出了不同情况下的Listener创建的具体实现。

关键词: 事件处理,委托模型,事件源,监听器

 

 

一、构造Listener的基本要素

Java1.1中最显著的特色便是引入了采用listener机制的事件委托模型。在实际的开发过程中,仅靠系统提供的listener有时并不能满足用户的需求。就此,本文给出了订制自己Listener的一般方法。

的事件委托模型中,一个对象中发生的事件自己一般不作处理,而是委托给外部实体处理。各个对象之间发送事件实现互相通讯,发送事件的对象称事件源,接受事件的对象称监听器(listener)。发送事件的方式有事件的单目广播和多目广播。

事件源是产生事件的构件,java中所有AWT构件均为事件源。监听器是接收和处理事件的构件,它通过向事件源注册对XxxEvent类型事件可以实现对事件源中发生的事件的注册。

接口是java中很有意思的一个概念,它大致的规划处多个类共有行为,而把对这些行为的特殊实现留给类本身。接口中定义了一些抽象方法。一个XxxEvent的接口,可以将XxxEvent监听器和XxxEvent 事件源联系起来。

二、建立自己的Listener的一般方法

1)建立自己的事件类,用于封装要向监听器发送的数据。如class MyEvent{}

2)预定义一个接口,规定要发送的事件以及对此事件的不同情况进行的操作。

如果事件源所发送的事件是在java.awt.event 包中定义的事件类,则监听器可以使用系统提供的Listener接口实现对事件源的监听,可跳过以上两步。

3)构造一个能引发某类型事件的事件源。事件源中必须规定监听器的注册、注销方法和发送事件的方法。例如在MyEvent事件源中有,

public void addMyEventListener(MyEventListener l){ }

    public void removeMyEventListener(MyEventListener l){ }

这里, addMyEventListener方法是把MyEvent监听器的一个引用添加到listener中,而removeMyEventListener则是从listener中删除一个MyEvent监听器的引用。

当满足了引发事件的条件时,将引发事件向监听器发送,在发送事件的方法应有向监听器发送事件的语句。形如    listener.action1Happened(e); 

4)构造监听器

    任何类,只要它实现了MyEventListener接口成为一个MyEvent事件监听器,就可以监听MyEventSource类构件中的MyEvent事件。它必须对接口方法做出具体实现。

5)监听器向事件源的注册

    构造了事件源、监听器后,要使监听器听到事件源中的事件,监听器还必须首先使用事件源中所规定的方法向事件源注册,形如,

    source.addMyEventListener(processer); //processersource注册

三、几种常见的定制listener的方法

1)使用系统接口接收来自非标准构件的系统事件

    很多情况下,用户要根据自己的需要制作一些特殊的构件。由于系统提供了丰富的事件类型,通常,可以让自己构件的特定动作引发一个系统的事件,发送到已注册的监听器。这样,就可以直接使用系统提供的事件接口,实现对自制构件的监听,利用AWTEventMulticaster类方便地实现事件的单目、多目广播。下例的自制图形按钮支持事件的多目广播。凡是实现了ActionListener接口的构件,通过向该按钮的注册,均可监听其动作。

public class   MyImageButton extends Canvas {

      ActionListener actionListener=null;

  ……

    public void addActionListener(ActionListener l) {//规定注册方法

           actionListener = AWTEventMulticaster.add(actionListener, l);

     }

    public void removeActionListener(ActionListener l) {//规定注销方法

           actionListener = AWTEventMulticaster.remove(actionListener, l);

     }

    public void processMouseEvent(MouseEvent event){//引发事件

……                    ……

if (actionListener != null) {//鼠标放开时发送ActionEvent事件

           ActionEvent  evt=new actionEvent(this,ActionEvent.ACTION_PERFORMED,name);

                actionListener.actionPerformed(evt);

        } 

}  

}  

 

2)使用自定义接口定制单目广播的Listener

    有些情形,我们需要把一个类实例若干状态的改变,及时地通知另外的类实例,以便它们及时的做出响应。这时,就需要自定义一个接口,规范数据发送和接收双方的行为,保证数据的正确传递与处理。要发送的数据可以封装到一个事件类中发送,也可以按参量表的形式发送。事实上,也就是建立一个自己的Listener。例中Speedbar 类可以向已注册的类传递参量。Speedbar类实例把其中鼠标的位置转换为一个整形值发送已向其注册的MainPanel类实例中,让其处理。该类只支持单目广播。

public interface SpeedListener{

    public void getSpeedValue(int value);

}

public class   Speedbar extends Canvas {

protected SpeedListener speedListener=null;

    ……

    public void addSpeedListener(SpeedListener l) { speedListener =  l;}////定注册方法

    public void removeSpeedListener(SpeedListener l) {speedListener = null;}

//规定注销方法

public void processMouseEvent(MouseEvent event){//发送事件的方法

        ……

if (speedListener != null) {    speedListener.getSpeedValue(currentValue);}

    }

public class MainPanel extends Panel implements SpeedListener{

    ………

    public void getSpeedValue(int value){}   

//对接口方法的实现,对传入值的具体处理     

}

 

3)使用自定义接口定制多目广播的Listener

    很多情形,我们要把一个类实例若干状态的改变,及时地通知其它的多个类实例。这时,需要建立一个多目广播的listener。建立的方法和建立单目广播listener大同小异。一般采用向量表的方法在事件源中规定多个注册、注销方法,并在引发事件的方法中向多个注册的监听器发送事件。

下例中的InputField 类可以同时向已注册的多个类传递参量。InputField类实例把其中输入的字符、当前的插入位置、选定文本的内容及起始终止位置,实时地发送到已向其注册的ShowSelectExample类实例。

首先,定义了一个接口InputReader,它在参量的发送者和参量的接收着建立了一个双方共同遵守的协议。它和系统的Listener接口起着相同的作用,只不过系统的Listener中规定传递的参量是java.awt.envent包中定义的事件类,而InputReader接口中规定传递的是一组未被封装的数据。 

public interface InputReader { //

    public void showSelection(int x,int y,String s);

    public void showInput(int position,String s);

}  

在多目事件源InputField类中,规定了注册和注销方法enableRecieverdisableReciever方法,其本质是允许监听器向事件源的注册,以便事件源知道向那些对象发送数据。   

public void enableReciever(InputReader cr){//规定注册方法

        inputReader=cr;

inputReaderPool.addElement(inputReader);

    }

public void disableReciever(InputReader cr){ //规定注销方法

        inputReader=cr;

inputReaderPool.removeElement(inputReader);

}  

当事件发生时,InputField类使用向量的方法向多个注册的监听器发送事件。 InputReaderPool是一个向量对象,它用来保存向事件源注册的类实例。如果某一时刻只向一个类传递参量,则不必使用向量。     

        for (int i=0;i<inputReaderPool.size();i++){

            inputReader=(InputReader) inputReaderPool.elementAt(i);                                     inputReader.showInput(pos,str);

}  

 

监听器向事件源注册后,便可以监听来自InputField类实例的参量。 本例中,有两个监听器关心来自InputField类实例的参量。

public class Example extends Frame implements InputReader{

    public Example(){

        ……

        inputField.enableReciever(this);    //Example类实例向InputField注册

        inputField.enableReciever(showSelect); // ShowSelect类实例向InputField注册

    }

    public void showSelection(int x,int y,String s){    }//空实现接口方法, 不做处理

    public void showInput(int pos,String s){ showInput.setText(s);} //实现接口方法,处理

}

参考文献

[1] Laurence .JavaBeans从入门到精通.北京: 电子工业出版社,1998

[2]Joseph Weber .Java 1.1使用大全(第三版).北京:电子工业出版社.1998

[3] Philip Heller .Java高级开发指南.北京:电子工业出版社,1997

  推荐精品文章

·2024年9月目录 
·2024年8月目录 
·2024年7月目录 
·2024年6月目录 
·2024年5月目录 
·2024年4月目录 
·2024年3月目录 
·2024年2月目录 
·2024年1月目录
·2023年12月目录
·2023年11月目录
·2023年10月目录
·2023年9月目录 
·2023年8月目录 

  联系方式
TEL:010-82561037
Fax: 010-82561614
QQ: 100164630
Mail:gaojian@comprg.com.cn

  友情链接
 
Copyright 2001-2010, www.comprg.com.cn, All Rights Reserved
京ICP备14022230号-1,电话/传真:010-82561037 82561614 ,Mail:gaojian@comprg.com.cn
地址:北京市海淀区远大路20号宝蓝大厦E座704,邮编:100089