前言 在Java程序设计中,通常合理的增加一个类或接口可以简化编码,获得可读性强,结构明晰的的代码。这一点在Java的事件监听机制上获得了体现。本文以JR Client用户治理界面的部分功能实现为例,阐述如何自定义一个监听并实现它。
何时需要监听
在UI设计中,假如一个类中组件的事件(通常为用户在界面上触发的事件)与另一个类中的容器或组件相关,这时可以使用监听。前者是监听处理类,后者是监听实现类,另外还需要定义监听接口。
如何实现监听
1. 定义监听接口
添加触发事件的方法。假如有多个方法,宜再增加一个Adapter抽象类继续该接口。使用时可以用Adapter类替代接口以减少接口方法的实现。接口例子如下:
/**
* @author efly
* @version 1.0.0,12/17/02
*/
public interface EUserNodeListener {
/**
* 触发用户节点名称改变
*/
public void fireNodeNameChanged(String name);
}
2. 监听处理类
从编码的角度看,监听实现类是ProdUCer,监听处理类是Consumer;然而从时间处理的角度看,这个过程正好相反:事件是从监听处理类“流”到监听实现类。
让我们看看监听处理类是如何消费的。首先它定义注册监听的方法供监听实现类调用:
private EUserNodeListener eUserNodeHandler;
public void addEUserNodeListener(EUserNodeListener nodeListener) {
eUserNodeHandler = nodeListener;
}
这个消费者不管监听者是谁,是哪儿生产的。拿来就用??拿来主义:
name_t.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent event) {
eUserNodeHandler.fireNodeNameChanged(name_t.getText());
}
});
3. 监听实现类
监听实现很轻易,归功于Java的匿名类机制。匿名类是内部类的一种。监听实现类实现了监听接口:
eUserComp.addEUserNodeListener(new EUserNodeListener() {
public void fireNodeNameChanged(String name) {
org[0].setText(name);
}
});
4. 剖析事件流
从事件的流向看,监听处理类是事件生产者,监听实现类是事件消费者。结合UI分析一下事件是如何传递的。
治理员在用户治理界面上选择/增加一个用户,相应的用户信息界面在树右边的面板上显示。
姓名的文本框为文本改变的事件处理者,它是监听处理类中定义的成员变量。当文本改变时,触发监听事件。而在监听实现类中已经向监听处理类注册了监听,事件即传递到监听实现类的匿名类。匿名类调用触发事件的方法??树组件中被选择的用户被改变节点名称为用户名称,至此完成了整个事件的传递。
不使用监听的实现
不使用监听同样可以实现上述的事件传递。监听的实现(不是全部的实现类)向监听处理类注册监听实际上是把自己作为了监听处理类的匿名成员??是匿名类给它蒙上了神秘的棉纱。可以通过向监听处理类注册完整的实现类来完成相同的事件传递机制。在这里,我们改变称谓(不使用监听一词),即UI左边的Tree结构所代表的是class A,上文中的监听实现类;UI右边的Composite所代表的是class B,上文中的监听实现类。实现如下:
class A{
…
}
class B{
private A a;
B(A a){
this.a=a;
}
…
name_t.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent event) {
a.getTree().getSelection()[0].setText(name_t.getText());
}
});
…
}
结束语 在本例中,作者使用的是监听的实现方式。监听可以减少代码的编写量,并使得程序结构清楚。在多数场合,使用监听更合理。在本例中使用了很多局部变量,如Tree结构即是一个方法的局部变量。倘若不使用监听的匿名类实现,使用非监听后者的方式不易于得到局部的Tree变量。
资料
关于JRC Client的源码下载和教程可浏览http://jrc.gro.cLinux.org项目主页。本例中的源码在JRC0.4.00版本中。