Locked History Actions

Diff for "GWT/Events"

Differences between revisions 12 and 13
Deletions are marked like this. Additions are marked like this.
Line 103: Line 103:
=== HandlerRegistration ===
Line 104: Line 105:
Swingでよくあるリスナ登録メソッドとは異なり、 addSomeEventHandler()登録メソッドは、HandlerRegistrationインターフェースを実装したオブジェクトを返すことになっている。このインターフェースには、removeHandler()というメソッドがただひとつ登録されている。
Line 105: Line 107:
つまり、Swingのやり方とは異なり、Somethingクラスには、ハンドラの登録解除メソッドはなく、登録メソッドから返されたHandlerRegistrationオブジェクトのremoveHandler()メソッドを呼び出すことにより登録解除を行うことになっている。

イベントシステム

参考

概要

GWTのイベントシステムは、Swingのものをアレンジしたものと言ってよい。基本的な用語は以下の通り

  • Source:Swingでのイベントソースと同じ意味。イベントの発行元オブジェクトで、オブザーバパターンでの「オブザーバブル」。
  • Event:Swingでのイベントとほぼ同じ意味。Swingと同様に、イベントオブジェクトは少なくともそのソースへの参照を持つが、加えて必要な任意の情報を保持してもよい。
  • EventHandler:Swingでいうところのリスナ。オブザーバパターンでの「オブザーバ」

  • HandlerManager(もしくはEventBus):Swingでいうところのリスナリスト。オブザーバブルオブジェクト上でオブザーバを管理するオブジェクト。

最も単純な形態

以下にできる限り単純なサンプルを示すが、一般的にはこのようなコードは作成しないものと思われる。

イベントの定義

イベントの定義自体に、そのハンドラ(Swingでいうリスナ)を指定しなければならない。 Swingでは、リスナはイベントを参照するが、その逆はなかった。 後述のハンドラの定義をあわせてみると、GWTではイベントとハンドラは双方向に参照しあっている。

また、このイベントオブジェクトは初めからハンドラが確定しているため、イベントの配布はイベント自身に行わせることができる。 これがdispatchというメソッドで、イベントオブジェクトはハンドラが渡された場合、その何というメソッドを呼び出せばよいかがわかっている。

TYPEとgetAssociatedType()については後述。

import com.google.web.bindery.event.shared.*;

public class SomeEvent extends Event<SomeEventHandler> {
  
  public static Type<SomeEventHandler>TYPE = new Type<SomeEventHandler>();
  
  @Override
  public Event.Type<SomeEventHandler>getAssociatedType() {
    return TYPE;
  }
  
  @Override
  protected void dispatch(SomeEventHandler handler) {
    handler.onSomething(this);
  }
}

イベントハンドラ

イベントハンドラは単純で、これはSwingのリスナと似たようなもの。 ただし、Swingと異なり、メソッドはただ一つにするのがお約束である。 というより、イベントの配布はイベントオブジェクト自身が行うのだが、前項のように、一つのメソッドしか呼び出すことはできない。

※イベントがGwtEventの場合は、そのハンドラはEventHandlerをextendsするのが一般的だが、ここでは必要ない。

public interface SomeEventHandler  {
  public void onSomething(SomeEvent e);
}

イベントソースの例

一般には、EventBusはその名のとおり、アプリの各パーツを連絡する「バス」として用いられるので、 通常は以下のような使い方はしない。単純化するために「可能な例」をあげた。

また、GwtEventの場合には、HasHandlerインターフェースを作成してそれを実装するのが通例だが、ここでは省略している。

この単純化された例はSwingでの構造とほぼ同じである。つまり、ハンドラ(リスナ)を登録するメソッドを用意し、 リスナリスト(EventBus)に追加する。 何らかのイベントを発生させたい場合、イベントオブジェクトを作成し、リスナリスト中のすべてのハンドラにそれを通知する。

import com.google.web.bindery.event.shared.*;

public class Something {
  private EventBus eventBus = new SimpleEventBus();
  
  public void fireEvent() {
    eventBus.fireEvent(new SomeEvent()); 
  }
  
  public HandlerRegistration addSomeEventHandler(SomeEventHandler handler) {
    return eventBus.addHandler(SomeEvent.TYPE, handler);
  }
}

getAssociatedType()の意味

さて、イベントオブジェクトに実装しなければならないgetAssociatedType()メソッドだが、これが必要な理由はどこにもまともに説明されていない。 単に、「どのイベントであるか」を知るためであれば、このようなものは使わずにSomeEvent.classでもよいはずである。

この方式の場合、SomeEventクラスからはstaticのTYPEとgetAssociatedType()メソッドは除去され、SomethingのaddSomeEventHandlerは

    return eventBus.addHandler(SomeEvent.class, handler);

と記述することになるだろう。わざわざこうなっている理由は今のところ不明である。

HandlerRegistration

Swingでよくあるリスナ登録メソッドとは異なり、 addSomeEventHandler()登録メソッドは、HandlerRegistrationインターフェースを実装したオブジェクトを返すことになっている。このインターフェースには、removeHandler()というメソッドがただひとつ登録されている。

つまり、Swingのやり方とは異なり、Somethingクラスには、ハンドラの登録解除メソッドはなく、登録メソッドから返されたHandlerRegistrationオブジェクトのremoveHandler()メソッドを呼び出すことにより登録解除を行うことになっている。

イベントオブジェクトの階層

GwtEvent

JavaDocの訳: Handlermanagerが発生するすべてのGWTウィジェットとDOMのイベントのルートとなる。 イベントを発生させたHandlerManagerが、それを完了させた後はGWTイベントは死んだ状態となるので、それ以降はアクセスしてはいけない。 アプリケーションのカスタムイベントをGwtEventのサブクラスとする必要はない。Eventのサブクラスとすることを推奨する。

DomEvent

JavaDocの訳: GwtEventのサブクラスであり、下層のネイティブなブラウザイベントオブジェクトとsinkEvents()で用いられるGWTイベントビットを理解するTypeのサブクラスを提供する (意味不明)。

HumanInputEvent

JavaDocの訳:マウス等の位置イベントやタッチイベント等を表現する抽象クラス。