• 反射在Java Swing编程中的应用之java 模仿.net事件处理


    学习过Java Swing的读者一定对于Swing中相对较为复杂的事件驱动模型比较困惑,虽然事件驱动模型在Java Swing中被完完全全的体现出来了,但是对于一个软件初学者而言这样的近乎“裸体”的事件驱动模型确实是很难理解的。

    Microsoft公司.Net框架与Java Swing的GUI编程相比要简单很多,同样是事件驱动模型.Net框架就进行了大量的封装处理,.Net把这种封装称之为委托器(Delegate)其代码如下:

    //当btnSubmit按钮被点击以后要求交给btnSubmit_Click方法处理
    // EventHandler在中间启到委托器的作用,
    //它负责将事件分发到指定的方法中进行处理
    this.btnSubmit.Click += new EventHandler(this.btnSubmit_Click);
    //事件处理方法
    // object sender:事件源,这里指btnSubmit对象
    // EventArgs e:事件处理参数,它保存了需要提供给程序员的必要信息
    private void btnSubmit_Click(object sender, EventArgs e)
    {
      //打印This is a button语句
      System.Diagnostics.Debug.WriteLine("This is button");
    }

    作为对比,我们来看看Java Swing的事件处理和委托就要复杂很多:代码如下:(您若还不是很了解Swing事件驱动的话,可以参考我的另外一篇文章:事件驱动模型实例详解(Java篇)):

    /为btnSubmit增加侦听器SelectHandler,当btnSubmit被点击以后
    //有侦听器的actionPerformed负责处理该点击事件的业务
    //由于事件源btnSubmit和侦听器类SelectHandler处于两个不同的类中
    //为了让SelectHandler类取得页面的信息,我们需要将窗体对象(this)
    //传入到侦听器中
    btnSubmit.addActionListener(new SelectHandler(this));
    //侦听器SelectHandler,它必须实现动作事件ActionListener接口
    //以达到事件分发的作用
    class SelectHandler implements ActionListener {
      private CommonDialogDemo form = null;
      //将窗体对象CommonDialogDemo通过构造函数传入SelectHandler类中
      public SelectHandler(CommonDialogDemo form) {
       this.form = form;
      }
      //事件处理方法,当btnSubmit被点击,自动执行以下打印代码
      publicvoid actionPerformed(ActionEvent e) {
       System.out.println("This is button");
      }
    }

    根据以上代码,我们可以清晰的看到Java Swing要比.Net的麻烦的多,而且更不能让人忍受的就是,一个页面如果有多个按钮的话,我们必须针对每个按钮编写多个事件侦听类,而且这些类一般都会被设为内部类学过软件建模的读者可能知道,内部在软件建模在软件工程中是不推荐使用的,所以这样的代码编写明显会增加设计冗余度和复杂度,因此我们可以考虑自己编写一个类似于.Net中EventHandler一样的事件委托类来处理事件分发。

    由于我们无权修改Java的编译器,所以我在这里将会借助于反射技术,利用一个事件委托类处理所有的点击事件,代码如下:

    public class EventHandler  implements ActionListener {
      //组件所在的窗体对象
      private Object form = null;
      //受到委托的方法名
      private String methodName = null;
      /**
      *构造函数
      *
      *@paramform 组件所在的窗体对象
      *@parammethodName 受到委托的方法名
      */
      public EventHandler(Object form,String methodName) {
       this.form = form;
       this.methodName = methodName;
      }
      /**
      *事件处理委托方法
      */
      publicvoid actionPerformed(ActionEvent e) {
       //得到窗体对象的类型
       Class formType = this.form.getClass();
       try {
        //得到指定委托方法的类型
        Method method =
    formType.getMethod(this.methodName, new Class[] {e.getClass()});
        //调用指定的方法
        method.invoke(this.form, new Object[] {e});
       }catch(Exception ex) {
        return;
       }
      }
    }
    public Method getMethod(String name, 方法名字
                            Class... parameterTypes)方法参数类型。
                     throws NoSuchMethodException,
                            SecurityException
    Returns a Method object that reflects the specified public member method of the class or interface represented by this Class object. The name parameter is a Stringspecifying the simple name the desired method. The parameterTypes parameter is an array of Class objects that identify the method's formal parameter types, in declared order. If parameterTypes is null, it is treated as if it were an empty array.

    If the name is "<init>"or "<clinit>" a NoSuchMethodException is raised. Otherwise, the method to be reflected is determined by the algorithm that follows. Let C be the class represented by this object:

    1. C is searched for any matching methods. If no matching method is found, the algorithm of step 1 is invoked recursively on the superclass of C.
    2. If no method was found in step 1 above, the superinterfaces of C are searched for a matching method. If any such method is found, it is reflected.
    To find a matching method in a class C:  If C declares exactly one public method with the specified name and exactly the same formal parameter types, that is the method reflected. If more than one such method is found in C, and one of these methods has a return type that is more specific than any of the others, that method is reflected; otherwise one of the methods is chosen arbitrarily.

    Method方法:

    public Object invoke(Object obj,
                         Object... args)
    Invokes the underlying method represented by this Method object, on the specified object with the specified parameters. Individual parameters are automatically unwrapped to match primitive formal parameters, and both primitive and reference parameters are subject to method invocation conversions as necessary.

    If the underlying method is static, then the specified obj argument is ignored. It may be null.

    If the number of formal parameters required by the underlying method is 0, the supplied args array may be of length 0 or null.

    If the underlying method is an instance method, it is invoked using dynamic method lookup as documented in The Java Language Specification, Second Edition, section 15.12.4.4; in particular, overriding based on the runtime type of the target object will occur.

    If the underlying method is static, the class that declared the method is initialized if it has not already been initialized.

    If the method completes normally, the value it returns is returned to the caller of invoke; if the value has a primitive type, it is first appropriately wrapped in an object. However, if the value has the type of an array of a primitive type, the elements of the array are not wrapped in objects; in other words, an array of primitive type is returned. If the underlying method return type is void, the invocation returns null.

    Parameters:
    obj - the object the underlying method is invoked from 调用此方法的对象
    args - the arguments used for the method call  执行方法所需的参数。
    Returns:
    the result of dispatching the method represented by this object on obj with parameters args

    通过以上2个函数解释,可以明白下面的话是干什么的了:

     Method method =
    formType.getMethod(this.methodName, new Class[] {e.getClass()});
        //调用指定的方法
        method.invoke(this.form, new Object[] {e});
    .
    int[] a =new int[1]{1};开辟了1个大小的int数组,并初始化为1.
    int[] array = {1,2,3,4,5};

     

    现在我们来编写一个测试程序,代码如下:

    package package1;
    
    import java.awt.event.ActionEvent;
    
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JOptionPane;
    
    public class TestMain extends JFrame{
        public TestMain()
        {
            super("test");
            JButton btn=new JButton("button");
            btn.addActionListener(new EventHandler(this,"btn_click"));
            getContentPane().add(btn);
            setSize(500,400); 
            setVisible(true);
            
        }
        public void btn_click(ActionEvent e)
        {
            System.out.println("this is button click");
            JOptionPane.showMessageDialog(null,"button clicked");
        }
    
        public static void main(String[] args) {
            
            new TestMain();
     
        }
    
    }

    从以上代码中我们可以清晰的看到,事件处理和事件委托处于同一窗体中了,(即:事件委托和处理事件的函数写在了同一个类中。).Net方便的Delegate处理被我们用反射实现了。

  • 相关阅读:
    js 正则表达式之环视结构
    Js 控制随机数概率
    js 随机点名
    事件处理机制
    事件处理程序 (DOM0级)
    事件处理程序(HTML)
    js正则表达式 URL格式匹配详解
    CSS中的圣杯布局与双飞翼布局
    CSS中的vertical-align属性
    CSS中元素的显示模式
  • 原文地址:https://www.cnblogs.com/youxin/p/2791801.html
Copyright © 2020-2023  润新知