GWT/Events/EventSystem

GwtEventSystem翻訳

※これはincubator時代の文書で、現在のGWTにはこの仕様(あるいは変更仕様)が組み込まれている。

イントロ

現在のListener Widget Event Systemは理解と使用が簡単であり、これらは大きなメリットである。 が、デメリットもある。ここで我々は

現在のListener Systemのデメリット

          if(clickListeners == null) {
            sinkEvents(Event.ON_CLICK);
            clickListeners = new ClickListenerCollection(); 
          }
          clickListeners.add(handler);

http://en.wikipedia.org/wiki/Sink_%28computing%29

提案するハンドラシステム

Widget Event API

全GWTユーザが使用することになるAPIである。 ユーザはウィジェットに新ハンドラを追加することができる。

クラスの概略

動作の仕方

各ハンドラは一つの引数を持つ一つのメソッドを持つ。 例えば、「void onClick(ClickEvent event)」あるいは「void onKeyDown(KeyDownEvent event)」のように。

あるイベントタイプをサポートするウィジェットは、対応するHas*Handlersインターフェースを実装する。 したがって、「form HandlerRegistration addFooHandler(FooEvent)」という形になる。 例えば、クリックハンドラをサポートするウィジェットはHasClickHandlersを実装する。

ハンドラを削除するには、ハンドラのaddメソッドが返したHandlerRegistrationインスタンスに対して、removeHandler()を呼び出す。

ハンドラの使用例

 DateBox start = new DateBox();
 start.addKeyDownHandler(new KeyDownHandler() {
      public void onKeyDown(KeyDownEvent e) {
        if (e.getNativeKeyCode() == KEY_RIGHT){
           Window.alert("I have to be right");
        }
      }
    });

ウィジェット開発者用イベントAPI

これらは、自身のウィジェットを作成してパッケージングする開発者向けのものである。 ウィジェットに新しいハンドラをhook upし、それらにイベントを送信するようにする。

クラス概要

Extra Widget methods

動作の仕方

ハンドラのウィジェットへの登録時、ウィジェットはイベントタイプとハンドラを指定してaddHandlerを呼び出す。

     public void addKeyDownHandler(KeyDownHandler handler) {
        addHandler(handler,KeyDownEvent.getType());
     } 

ウィジェットのハンドラを使う(訳注:イベントを通知する?)には、イベントオブジェクトを作成し、ウィジェットのfireEventを呼び出す。

      @Override
      public void onBrowserEvent(Event e){
        ...
        case ON_KEYDOWN:
          fireEvent(new KeyDownEvent(e)); 
      }

ウィジェットのイベントハンドリングコード例

以下のコードは、DateBoxKeyDownHandlerをハンドリングさせている。 言い換えれば、上に述べたDataBox.addKeyDownEvent機能を実装している。

public class DateBox extends Composite implements FiresKeyDownEvents {
...

 // implements FiresKeyDownEvents.addKeyDownHandler
 public void addKeyDownHandler(KeyDownHandler handler) {
    // Widget's addDomHandler method. 
    // Registers the current handler as a KeyDownEvent handler.
    addDomHandler(handler,KeyDownEvent.getType());
 }

ウィジェットは現在、デフォルトのonBrowserEvent実装を持つため、明示的にキーダウンイベントをfireする必要はない。

上級ウィジェット生成法

このAPIはカスタムイベントの生成が必要な場合や、あるいはWidgetクラスを継承しないウィジェットの生成が必要な場合のためのものである。

クラス概要

Protectedメソッド

カスタムイベントの作成ステップ

以下は、ユーザがhappyになったときにトリガーされるイベントである。

    public class HappyEvent extends GwtEvent{
       ...
    }

    interface HappyHandler extends EventHandler {
      public void onHappiness(HappyEvent event);
    }

    interface HasHappyEvents {
      public HandlerRegistration addHappyHandler(HappyHandler handler);
    }

    class HappyEvent extends AbstractEvent{
      public static AbstractEvent.Key KEY = new AbstractEvent.Key(){...}
     
      public GwtEvent.Key getKey(){
        return KEY; 
      }
      ...
    }

    class HappyEvent extends GwtEvent {
      static Key<HappyEvent,HappyHandler> KEY = new Key<HappyEvent,HappyHandler>(){
        protected void fire(HappyHandler handler, HappyEvent event) {
           handler.onHappiness(event);
        };
       ...
    }

Happy Handler生成の全コード

public interface HappyHandler extends EventHandler {
  public void onHappiness(HappyEvent event);
}

public interface HasHappyEvents {
  public HandlerRegistration addHappyHandler(HappyHandler handler);
}

public class HappyEvent extends GwtEvent { 
  public final static Key<HappyEvent,HappyHandler> KEY = new Key<HappyEvent,HappyHandler>(){
    protected void fire(HappyHandler handler, HappyEvent event) {
       handler.onHappiness(event);
    }

  public GwtEvent.Key getKey(){
    return KEY; 
  } 
}

実際にはどのように動作させるのか

ハンドラシステムの問題解決

Listener Problem

Handler solution

(1) Cannot add extra information about an event

Can add metadata to event

(2) Cannot add extra features

Each handler represents a single method, so more can always be added

(3) Excess unused listener fields

A single manager field is used

(4) Excess events are sunk

Only the events that are needed are sunk

(5) Extra blank methods

No extra methods needed

(6) Boiler plate code

Between Widget enhancements and HandlerManager classes, most boiler plate code removed. Remaining boiler plate code will be inlined

(7) All event sources must be widgets

sources simply must implement the Fires* interface

(8) All widgets must manage sinking of events

All standard widgets have events sunk automatically

Migration Path

Removing all the listener methods within a single iteration of a library would be very disruptive. Instead, the listeners methods will be deprecated. In order to avoid supporting both sets of machinery within each widget, we will introduce wrapper classes to convert listeners to handlers.

Default OnBrowserEvent implementation

We already have a significant amount of boiler plate code in the libraries code to fire native dom events to listeners. The conversion of listeners --> handlers makes this boiler plate code event larger, which would lead to more code overall in GWT applications, a prospect we would rather avoid.

Additionally, by adding addHandlerAndSink() to Widget, we have successfully hidden half the complexity of dealing with native browser events. If the default onBrowserEvent just did the right thing, then it would be much easier for beginning GWT developers to create widgets directly, which leads to tighter, smaller code.

Solution

We wire up DomEvent so it can fire a native event directly on the handler manager.

We register dom event keys lazily, so that unused event types (i.e. ones where no handler is ever constructed) are still dead-stripped in the compiled output.

How it works

In Widget

 public void onBrowserEvent(Event e){
     DomEvent.fireEvent(e,getHandlerManager());
 }

In DomEvent

We introduce a specialized Type subclass with the following information:

For instance, here is the DomEvent.Key for click events:

  /**
   * Event Key for Click.
   */
  public static final Key<ClickEvent, ClickHandler> KEY = new Key<ClickEvent, ClickHandler>(
      Event.ONCLICK) {
    @Override
    protected void fire(ClickHandler handler, ClickEvent event) {
      handler.onClick(event);
    }

    @Override
    public ClickEvent wrap(Event nativeEvent) {
      return new ClickEvent(nativeEvent);
    }
  };

In DomEvent, then we have the fire event method.

   public static void fireEvent(Event e, HandlerManager m) {
     DomEvent.Key eventKey = registeredDomKeys.get(e.getEventType());
     if(m.hasHandlersFor(eventKey)) {
        m.fireEvent(eventKey, eventKey.wrap(e));
     }
  }
last edited 2011-11-18 04:45:03 by ysugimura