关于在XML中为Swing组件指定事件监听器的解决方案


已有方案存在的问题:会把事件监听器作为普通属性来看待,会引起误解。但对于不同的时间,处理方法不同,比如:
ActionListener的处理方法为actionPerformed(ActionEvent e);
对于MouseListener有几个处理方法:mouseEnter,mouseExit,mouseOver等等。
由此引起事件处理器形式不统一。为了让xps跟html形式类似,即对于一个组件可以通过如下形式指定:
<JButton onClick="#handleClick" onMouseEnter="#handleMouseEnter"/>
而handleMouseEnter,handleClick等方法只是一个普通类(不需要实现相应的接口)的实例成员方法(此实例可在xps开头处指定)。
因此最终实现的目标是这样的:
<JPanel controller="org.your.controller.Controller">
    <items>
        <JButton onClick="#
handleClick"  text="button"/>   
</items>
</JPanel>
org.your.controller.Controller是自定义的控制器,handleClick是 org.your.controller.Controller类中的一个成员方法
但要求
handleClick具有这样的签名:public void handleClick(ActionEvent event);
这样swing的UI界面的构造可跟事件处理逻辑完全分开。
为实现这种形式,的定义一个实现所有swing以及awt中EventListener
即定义一个这样的类
public class Handler implements MouseListener,ComponentListener,KeyListener...(不再列出)
这样一个Handler类的实例可以处理任何事件。
但是 Handler自己并不处理这些事件,而是不这些事件交给 org.your.controller.Controller实例中的相应方法
例如对于ActionEvent的监听器ActionListener,Handler 的实现应该这样
@Override
void actionPerformed(ActionEvent event){
    Object ctrl = getController();
    //接下来利用java的反射调用控制器中的相应方法

    //寻找控制器中名为actionPerformed方法
    Method method = findMethod("actionPerfomed",ctrl.getClass());
    if(method != null && method.getParameters().length == 1
        &&
method.getParameters() [0].equals(ActionEvent.class) )//检查方法是否符合规范
    
    //将事件交给控制器

     method.invoke(ctrl,event);
}

注意,对于控制器类没有做任何假设,它不需要实现任何接口,不需要继承任何类,
如果控制器重定义了相应的方法则调用之,否则Handler就当控制器不打算处理这个事件。则什么都不做。
对于控制器
事件处理方法的访问控制的说明:此处必须为保证为public。最起码保证Handler类可以访问那个方法。
当如果java虚拟机给了Handler类的代码足够的权限,即使是private的方法Handler也能调用,但毕竟Handler不是java核心API
其代码的权限可能会被限制
,因此为保证代码可以再不同环境中运行,访问控制必须为public

你可能感兴趣的:(关于在XML中为Swing组件指定事件监听器的解决方案)