Module java.desktop
Package java.beans

Class EventHandler

java.lang.Object
java.beans.EventHandler
所有已实现的接口:
InvocationHandler

public class EventHandler extends Object implements InvocationHandler
EventHandler类提供了支持,用于动态生成事件监听器,其方法执行涉及传入事件对象和目标对象的简单语句。

EventHandler类旨在被交互式工具使用,例如应用程序构建器,允许开发人员在bean之间建立连接。通常,连接是从用户界面bean(事件源)到应用程序逻辑bean(目标)的。这种类型的最有效连接将应用程序逻辑与用户界面隔离开来。例如,连接从JCheckBox到接受布尔值的方法的EventHandler可以处理提取复选框状态并直接传递给方法,使方法与用户界面层隔离开来。

内部类是另一种更一般的处理用户界面事件的方式。 EventHandler类仅处理内部类可能实现的一部分功能。但是,与内部类相比,EventHandler在长期持久性方案中的效果更好。此外,在实现同一接口多次的大型应用程序中使用EventHandler可以减少应用程序的磁盘和内存占用。

使用EventHandler创建的监听器具有很小的占用空间的原因是EventHandler依赖的Proxy类共享相同接口的实现。例如,如果您使用EventHandler create方法创建应用程序中的所有ActionListener,则所有动作监听器将是单个类的实例(由Proxy类创建)。通常,基于Proxy类的监听器需要为每个监听器类型(接口)创建一个监听器类,而内部类方法则需要为每个监听器(实现接口的对象)创建一个类。

通常不直接处理EventHandler实例。相反,您可以使用EventHandlercreate方法之一来创建实现给定监听器接口的对象。此监听器对象在幕后使用EventHandler对象来封装有关事件、在事件发生时要发送消息的对象、要发送的消息(方法)以及方法的任何参数的信息。以下部分提供了使用create方法创建监听器对象的示例。

使用 EventHandler 的示例

EventHandler的最简单用法是安装一个调用目标对象上不带参数的方法的监听器。在以下示例中,我们创建一个ActionListener,它调用javax.swing.JFrame实例上的toFront方法。
myButton.addActionListener(
    (ActionListener)EventHandler.create(ActionListener.class, frame, "toFront"));
当按下myButton时,将执行语句frame.toFront()。通过定义ActionListener接口的新实现并将其实例添加到按钮,也可以获得相同效果,同时增加一些编译时类型安全性:
//使用内部类而不是 EventHandler 的等效代码。
myButton.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        frame.toFront();
    }
});
EventHandler的下一个最简单用法是从监听器接口中方法的第一个参数(通常是事件对象)中提取属性值,并将其用于设置目标对象的属性值。在以下示例中,我们创建一个ActionListener,将目标对象(myButton)的nextFocusableComponent属性设置为事件的“source”属性的值。
EventHandler.create(ActionListener.class, myButton, "nextFocusableComponent", "source")
这对应于以下内部类实现:
//使用内部类而不是 EventHandler 的等效代码。
new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        myButton.setNextFocusableComponent((Component)e.getSource());
    }
}
还可以创建一个EventHandler,只是将传入的事件对象传递给目标的操作。如果第四个EventHandler.create参数是空字符串,则事件将只是传递:
EventHandler.create(ActionListener.class, target, "doActionEvent", "")
这对应于以下内部类实现:
//使用内部类而不是 EventHandler 的等效代码。
new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        target.doActionEvent(e);
    }
}
EventHandler最常见的用法可能是从事件对象的source中提取属性值,并将此值设置为目标对象的属性值。在以下示例中,我们创建一个ActionListener,将目标对象的“label”属性设置为事件的“source”属性的“text”属性的值。
EventHandler.create(ActionListener.class, myButton, "label", "source.text")
这对应于以下内部类实现:
//使用内部类而不是 EventHandler 的等效代码。
new ActionListener {
    public void actionPerformed(ActionEvent e) {
        myButton.setLabel(((JTextField)e.getSource()).getText());
    }
}
事件属性可以用任意数量的使用"."字符分隔的属性前缀进行“限定”。出现在“.”字符之前的“限定”名称被视为应该应用于事件对象的属性名称,从最左边开始应用。

例如,以下动作监听器

EventHandler.create(ActionListener.class, target, "a", "b.c.d")
可以写成以下内部类(假设所有属性都有规范的getter方法并返回适当的类型):
//使用内部类而不是 EventHandler 的等效代码。
new ActionListener {
    public void actionPerformed(ActionEvent e) {
        target.setA(e.getB().getC().isD());
    }
}
目标属性也可以用任意数量的使用"."字符分隔的属性前缀进行“限定”。例如,以下动作监听器:
   EventHandler.create(ActionListener.class, target, "a.b", "c.d")
 
可以写成以下内部类(假设所有属性都有规范的getter方法并返回适当的类型):
   //使用内部类而不是 EventHandler 的等效代码。
   new ActionListener {
     public void actionPerformed(ActionEvent e) {
         target.getA().setB(e.getC().isD());
    }
}

由于EventHandler最终依赖于反射来调用方法,我们建议不要针对重载方法。例如,如果目标是类MyTarget的实例,该类定义如下:

   public class MyTarget {
     public void doIt(String);
     public void doIt(Object);
   }
 
然后方法doIt是重载的。EventHandler将根据源调用适当的方法。如果源为null,则两种方法都适用,调用的方法是未定义的。因此,我们建议不要针对重载方法。
自 JDK 1.4 起:
1.4
参见:
  • Constructor Summary

    Constructors
    Constructor
    Description
    EventHandler(Object target, String action, String eventPropertyName, String listenerMethodName)
    创建一个新的EventHandler对象;通常使用create方法之一来创建对象,而不是直接调用此构造函数。
  • Method Summary

    Modifier and Type
    Method
    Description
    static <T> T
    create(Class<T> listenerInterface, Object target, String action)
    创建listenerInterface的实现,其中监听器接口中的所有方法都将处理程序的action应用于target
    static <T> T
    create(Class<T> listenerInterface, Object target, String action, String eventPropertyName)
    /** 创建listenerInterface的实现,其中所有方法都将事件表达式eventPropertyName的值传递给语句的最终方法action,该方法应用于target
    static <T> T
    create(Class<T> listenerInterface, Object target, String action, String eventPropertyName, String listenerMethodName)
    创建listenerInterface的实现,其中名为listenerMethodName的方法将事件表达式eventPropertyName的值传递给语句的最终方法action,该方法应用于target
    返回此事件处理程序将设置的目标可写属性的名称,或将在目标上调用的方法的名称。
    返回应在应用于目标的操作中使用的事件属性。
    返回将触发操作的方法的名称。
    返回将发送消息给此事件处理程序的对象。
    invoke(Object proxy, Method method, Object[] arguments)
    从事件中提取适当的属性值并将其传递给与此EventHandler关联的操作。

    Methods declared in class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Constructor Details

  • Method Details

    • getTarget

      public Object getTarget()
      返回此事件处理程序将发送消息的对象。
      返回:
      此事件处理程序的目标
      参见:
    • getAction

      public String getAction()
      返回此事件处理程序将设置的目标的可写属性的名称,或者此事件处理程序将在目标上调用的方法的名称。
      返回:
      此事件处理程序的操作
      参见:
    • getEventPropertyName

      public String getEventPropertyName()
      返回应用于目标的操作中应使用的事件的属性。
      返回:
      事件的属性
      参见:
    • getListenerMethodName

      public String getListenerMethodName()
      返回将触发操作的方法的名称。返回值null表示监听器接口中的所有方法都会触发操作。
      返回:
      将触发操作的方法的名称
      参见:
    • invoke

      public Object invoke(Object proxy, Method method, Object[] arguments)
      从事件中提取适当的属性值并将其传递给与此EventHandler关联的操作。
      指定者:
      invoke 在接口中 InvocationHandler
      参数:
      proxy - 代理对象
      method - 监听器接口中的方法
      arguments - 包含在代理实例上的方法调用中传递的参数值的对象数组,如果接口方法不带参数,则为null。基本类型的参数将包装在适当的基本包装类的实例中,例如java.lang.Integerjava.lang.Boolean
      返回:
      将操作应用于目标的结果
      参见:
    • create

      public static <T> T create(Class<T> listenerInterface, Object target, String action)
      创建listenerInterface的实现,其中监听器接口中的所有方法都将将处理程序的action应用于target。通过调用另一个更通用的create方法来实现此方法,其中eventPropertyNamelistenerMethodName都取值null。有关action参数的完整描述,请参阅create的通用版本

      要创建一个显示JDialog并使用dialog.show()ActionListener,可以编写以下代码:

      EventHandler.create(ActionListener.class, dialog, "show")
      
      类型参数:
      T - 要创建的类型
      参数:
      listenerInterface - 要为其创建代理的监听器接口
      target - 将执行操作的对象
      action - 目标上的属性或方法的名称(可能带限定符)
      返回:
      实现listenerInterface的对象
      抛出:
      NullPointerException - 如果listenerInterface为null
      NullPointerException - 如果target为null
      NullPointerException - 如果action为null
      IllegalArgumentException - 如果为listenerInterface创建代理失败,原因是由Proxy.newProxyInstance(java.lang.ClassLoader, java.lang.Class<?>[], java.lang.reflect.InvocationHandler)指定的任何限制
      参见:
    • create

      public static <T> T create(Class<T> listenerInterface, Object target, String action, String eventPropertyName)
      /** 创建listenerInterface的实现,其中监听器接口中的所有方法都将传递事件表达式eventPropertyName的值到语句的最终方法action中,该方法应用于target。通过调用更通用的create方法来实现此方法,其中listenerMethodName取值null。有关actioneventPropertyName参数的完整描述,请参阅create的通用版本

      要创建一个将JLabel的文本设置为传入事件的JTextField源的文本值的ActionListener,可以使用以下代码:

      EventHandler.create(ActionListener.class, label, "text", "source.text");
      
      这等效于以下代码:
      //使用内部类而不是EventHandler的等效代码。
      new ActionListener() {
          public void actionPerformed(ActionEvent event) {
              label.setText(((JTextField)(event.getSource())).getText());
           }
      };
      
      类型参数:
      T - 要创建的类型
      参数:
      listenerInterface - 要为其创建代理的监听器接口
      target - 将执行操作的对象
      action - 目标上的属性或方法的名称(可能带限定符)
      eventPropertyName - 传入事件的可读属性的名称(可能带限定符)
      返回:
      实现listenerInterface的对象
      抛出:
      NullPointerException - 如果listenerInterface为null
      NullPointerException - 如果target为null
      NullPointerException - 如果action为null
      IllegalArgumentException - 如果为listenerInterface创建代理失败,原因是由Proxy.newProxyInstance(java.lang.ClassLoader, java.lang.Class<?>[], java.lang.reflect.InvocationHandler)指定的任何限制
      参见:
    • create

      public static <T> T create(Class<T> listenerInterface, Object target, String action, String eventPropertyName, String listenerMethodName)
      创建一个listenerInterface的实现,其中名为listenerMethodName的方法将事件表达式eventPropertyName的值传递给语句中的最终方法action,该方法应用于target。所有其他监听器方法均不执行任何操作。

      eventPropertyName字符串用于从传递给目标方法的传入事件对象中提取值。常见情况是目标方法不接受参数,在这种情况下,应该对eventPropertyName使用null值。或者,如果希望将传入的事件对象直接传递给目标方法,请使用空字符串。 eventPropertyName字符串的格式是一系列方法或属性,其中每个方法或属性应用于从传入事件对象开始返回的前一个方法的值。语法是:propertyName{.propertyName}*,其中propertyName匹配方法或属性。例如,要从MouseEvent中提取point属性,可以将"point""getPoint"用作eventPropertyName。要从具有JLabel源的MouseEvent中提取"text"属性,可以将以下任何内容用作eventPropertyName"source.text""getSource.text""getSource.getText""source.getText"。如果找不到方法,或者在调用方法时生成异常,将在调度时抛出RuntimeException。例如,如果传入的事件对象为null,并且eventPropertyName非null且不为空,则将抛出RuntimeException

      action参数与eventPropertyName参数的格式相同,其中最后一个属性名称标识方法名或可写属性。

      如果listenerMethodNamenull,则接口中的所有方法都会触发在target上执行action

      例如,要创建一个MouseListener,每次按下鼠标按钮时将目标对象的origin属性设置为传入MouseEvent的位置(即mouseEvent.getPoint()的值),可以编写如下代码:

      EventHandler.create(MouseListener.class, target, "origin", "point", "mousePressed");
      
      这相当于编写一个MouseListener,其中除了mousePressed之外的所有方法都是空操作:
      //相当于使用内部类而不是EventHandler编写的等效代码。
      new MouseAdapter() {
          public void mousePressed(MouseEvent e) {
              target.setOrigin(e.getPoint());
          }
      };
       
      类型参数:
      T - 要创建的类型
      参数:
      listenerInterface - 要为其创建代理的监听器接口
      target - 将执行操作的对象
      action - 目标上的(可能限定的)属性或方法的名称
      eventPropertyName - 传入事件的可读属性的(可能限定的)名称
      listenerMethodName - 应触发操作的监听器接口中的方法的名称
      返回:
      实现listenerInterface的对象
      抛出:
      NullPointerException - 如果listenerInterface为null
      NullPointerException - 如果target为null
      NullPointerException - 如果action为null
      IllegalArgumentException - 如果为listenerInterface创建代理失败,因为未满足Proxy.newProxyInstance(java.lang.ClassLoader, java.lang.Class<?>[], java.lang.reflect.InvocationHandler)指定的任何限制
      参见: