ちょっと私はカスタムGWTイベントハンドラーがどのように機能するかについて頭を悩ましています。私はこのトピックについてかなり読んだことがありますが、それでもいささかぼやけています。このようなStackoverflowのスレッドをここで読みました GWT Custom Event Handler 。誰かが次のような応用マナーでそれを説明できますか。
ブロックと男性クラスの2つのクラスがあります。男がブロックと衝突すると、男はイベント(onCollision())を発生させ、ブロッククラスはそのイベントをリッスンします。
ありがとう
イベントは常に何かについて通知するために送信されます(例:状態の変化)。男と壁の例を見てみましょう。ここでは、ユーザーが迷宮の中で男として歩くことができるゲームがあると想像できます。ユーザーが壁にぶつかるたびに、衝突に反応できるように衝突について通知する必要があります(たとえば、壁はそれ自体を破壊された壁としてレンダリングできます)。これは、壁との衝突が検出されるたびに衝突イベントを送信することで実現できます。このイベントは男性によって送信され、イベントに関心のあるシステム内のすべてのオブジェクトがそれを受信し、それに応じて対応できます。イベントを受信したいオブジェクトは、イベントに関心があるとして自身を登録する必要があります。
これは、すべてのシステムまたはフレームワークで(GWTだけでなく)イベントが一般的に機能する方法です。そのようなシステムでイベントを送受信するには、以下を定義する必要があります。
その後、次のことができます。
ここでは、GWTでカスタムイベントを使用する例を示します。メールボックスのチェックを担当し、新しいメールがあるかどうかをユーザーに通知するシステムの例を使用します。システムに少なくとも2つのコンポーネントがあると仮定しましょう。
メッセージチェッカーは、新しいメールを受信するとイベントを送信し、メッセージ表示はこれらのイベントを受信します。
新しいメールに関する情報は、MessageReceivedEvent
クラスのインスタンスとして送信されます。クラスには新しいメールが含まれています(簡単にするために、それはString
であると仮定しましょう)。
このクラスの完全なソースコードを以下に示します(コメントはソースコードの下にあります)。
public class MessageReceivedEvent extends GwtEvent<MessageReceivedEventHandler> {
public static Type<MessageReceivedEventHandler> TYPE = new Type<MessageReceivedEventHandler>();
private final String message;
public MessageReceivedEvent(String message) {
this.message = message;
}
@Override
public Type<MessageReceivedEventHandler> getAssociatedType() {
return TYPE;
}
@Override
protected void dispatch(MessageReceivedEventHandler handler) {
handler.onMessageReceived(this);
}
public String getMessage() {
return message;
}
}
MessageReceivedEventHandler
は、イベントレシーバーを表すインターフェイスです。現時点では気にしないでください。これについては後で説明します。
GWTイベントを表すすべてのクラスは、GwtEvent
クラスを拡張する必要があります。このクラスには、getAssociatedType
とdispatch
の2つの抽象メソッドを実装する必要があります。ただし、すべてのイベントクラスでは、通常、非常によく似た方法で実装されます。
このクラスには、受信したメッセージに関する情報が格納されます(コンストラクターを参照)。すべてのイベントレシーバーは、getMessage
メソッドを使用して取得できます。
GWTの各イベントタイプは、このイベントタイプのレシーバーを表すインターフェイスに関連付けられています。 GWTでは、レシーバーはハンドラーと呼ばれます。この例では、MessageReceivedEvent
のイベントレシーバーインターフェイスの名前はMessageReceivedEventHandler
になります。ソースコードは次のとおりです。
public interface MessageReceivedEventHandler extends EventHandler {
void onMessageReceived(MessageReceivedEvent event);
}
各ハンドラーは、EventHandler
インターフェイスを拡張する必要があります。また、イベントが発生したときに呼び出されるメソッドを定義する必要があります(少なくとも1つのパラメーター(イベント)を取る必要があります)。ここでは、メソッドの名前はonMessageReceived
です。このメソッドを実装することにより、各レシーバーはイベントに反応できます。
例の唯一のイベントレシーバーはMessageDisplayer
コンポーネントです。
public class MessageDisplayer implements MessageReceivedEventHandler {
@Override
public void onMessageReceived(MessageReceivedEvent event) {
String newMessage = event.getMessage();
// display a new message
// ...
}
}
この例では、唯一のイベント送信者はメールのチェックを担当するコンポーネントです-EventChecker
:
public class MessageChecker implements HasHandlers {
private HandlerManager handlerManager;
public MessageChecker() {
handlerManager = new HandlerManager(this);
}
@Override
public void fireEvent(GwtEvent<?> event) {
handlerManager.fireEvent(event);
}
public HandlerRegistration addMessageReceivedEventHandler(
MessageReceivedEventHandler handler) {
return handlerManager.addHandler(MessageReceivedEvent.TYPE, handler);
}
}
すべてのイベント送信者は、HasHandlers
インターフェイスを実装する必要があります。
ここで最も重要な要素はHandlerManager
フィールドです。 GWTでは、HandlerManager
という名前が示すように、イベントハンドラー(イベントレシーバー)を管理します。冒頭で述べたように、イベントを受信するすべてのイベントレシーバーは、自身を関心があるものとして登録する必要があります。これがハンドラマネージャの目的です。イベントハンドラーを登録し、登録されたすべてのイベントハンドラーに特定のイベントを送信できます。
HanlderManager
が作成されると、コンストラクターで1つの引数を取ります。すべてのイベントにはOriginのソースがあり、このパラメーターはこのハンドラーマネージャーによって送信されるすべてのイベントのソースとして使用されます。例では、イベントソースがthis
であるため、MessageChecker
です。
メソッドfireEvent
はHasHandlers
インターフェイスで定義され、イベントの送信を担当します。ご覧のとおり、ハンドラーマネージャーを使用してイベントを送信(起動)するだけです。
addMessageReceivedEventHandler
は、イベントの受信に関心があるとして自身を登録するために、イベントレシーバーによって使用されます。この場合も、ハンドラマネージャが使用されます。
すべてが定義されると、イベント受信者はイベント送信者に自分自身を登録する必要があります。これは通常、オブジェクトの作成中に行われます。
MessageChecker checker = new MessageChecker();
MessageDisplayer displayer = new MessageDisplayer();
checker.addMessageReceivedEventHandler(displayer);
これで、checker
によって送信されたすべてのイベントがdisplayer
によって受信されます。
イベントを送信するには、MessageChecker
がイベントインスタンスを作成し、fireEvent
メソッドを使用して送信する必要があります。この杖はnewMailReceived
メソッドで実行できます:
public class MessageChecker implements HasHandlers {
// ... not important stuff omitted
public void newMailReceived() {
String mail = ""; // get a new mail from mailbox
MessageReceivedEvent event = new MessageReceivedEvent(mail);
fireEvent(event);
}
}
私はそれが明確で助けになることを願っています:)
この質問とPiotr GWTからの回答により、カスタムイベントを作成するわずかに異なる方法のサポートが追加されました。このイベント実装は、パッケージcom.google.web.bindery.event.shared
のGWTのEventBusで使用される特定のビルドです。 GWT 2.4のカスタムイベントを作成する方法の例:
import com.google.web.bindery.event.shared.Event;
import com.google.web.bindery.event.shared.EventBus;
import com.google.web.bindery.event.shared.HandlerRegistration;
/**
* Here is a custom event. For comparison this is also a MessageReceivedEvent.
* This event extends the Event from the web.bindery package.
*/
public class MessageReceivedEvent extends Event<MessageReceivedEvent.Handler> {
/**
* Implemented by methods that handle MessageReceivedEvent events.
*/
public interface Handler {
/**
* Called when an {@link MessageReceivedEvent} event is fired.
* The name of this method is whatever you want it.
*
* @param event an {@link MessageReceivedEvent} instance
*/
void onMessageReceived(MessageReceivedEvent event);
}
private static final Type<MessageReceivedEvent.Handler> TYPE =
new Type<MessageReceivedEvent.Handler>();
/**
* Register a handler for MessageReceivedEvent events on the eventbus.
*
* @param eventBus the {@link EventBus}
* @param handler an {@link MessageReceivedEvent.Handler} instance
* @return an {@link HandlerRegistration} instance
*/
public static HandlerRegistration register(EventBus eventBus,
MessageReceivedEvent.Handler handler) {
return eventBus.addHandler(TYPE, handler);
}
private final String message;
public MessageReceivedEvent(String message) {
this.message = message;
}
@Override
public Type<MessageReceivedEvent.Handler> getAssociatedType() {
return TYPE;
}
public String getMessage() {
return message;
}
@Override
protected void dispatch(Handler handler) {
handler.onMessageReceived(this);
}
}
イベントは次のように使用されます。
このイベントのハンドラーをイベントバスに登録するには、MessageReceivedEventクラスの静的登録メソッドを呼び出します。
MessageReceivedEvent.register(eventbus, new MessageReceivedEvent.Handler() {
public void onMessageReceived(MessageReceivedEvent event) {
//...do something usefull with the message: event.getMessage();
}
});
次に、イベントバスでイベントを起動するには、新しく構築されたイベントでfireEvent
を呼び出します。
eventBus.fireEvent(new MessageReceivedEvent("my message"));
別の実装は、GWT独自のEntityProxyChange
イベントクラスにあります。その実装は、EventBusの代替オプションを使用します。 addHandlerToSource
を介して特定のソースにバインドされ、eventBus.fireEventFromSource
を介してトリガーできるハンドラーを追加する機能を使用します。
GWTの Activities を使用する場合は、ここで指定したイベント実装もより適しています。
GWTのCompositeクラスを拡張して、独自のウィジェットを作成しました。このクラスで独自のカスタムイベントを作成したかった。 GWTのWindowBuilderエディターがイベントにアクセスできるようにしたかったのです。
このページの回答から多くのことを学びましたが、いくつかの変更を加える必要がありました。
ヒルブランド・ブーカンプの答えから始めたかったのは、それが新しいからです。しかし、私はいくつかの問題に遭遇しました。 1)その答えは、イベントバスに言及していました。偶数バスは、メインプログラムが所有するグローバル変数です。ウィジェットライブラリがどのようにアクセスできるかは明確ではありません。 2)私はゼロから始めていませんでした。 GWTライブラリコードを拡張していました。そのためには、EventクラスではなくGwtEventクラスから開始する必要がありました。
Piotrの答えは本質的に正しいですが、非常に長いものでした。私のクラスは(間接的に)GWTのWidgetクラスを拡張します。 Widgetは、HandlerManagerオブジェクトの作成など、多くの詳細を処理します。 (ソースコードを調べたところ、EventBusを使用するのではなく、標準のウィジェットが正確に機能します。)
カスタムイベントハンドラーを追加するには、ウィジェットクラスに2つの項目を追加するだけで済みました。それらはここに示されています:
public class TrackBar extends Composite {
public HandlerRegistration addValueChangedHandler(TrackBarEvent.Handler handler)
{
return addHandler(handler, TrackBarEvent.TYPE);
}
private void fireValueChangedEvent()
{
final TrackBarEvent e = new TrackBarEvent(value);
fireEvent(e);
}
私の新しいイベントは、上記のPiotrのイベントクラスとほぼ同じです。 1つのことは注目に値します。その例に基づいて、getValue()から始めました。後で、より多くの情報を提供するためにgetTrackBar()を追加しました。もしゼロから始めていたら、前者ではなく後者に焦点を当てるでしょう。完全なイベントクラスを以下に示します。
import com.google.gwt.event.shared.EventHandler;
import com.google.gwt.event.shared.GwtEvent;
public class TrackBarEvent extends GwtEvent< TrackBarEvent.Handler >
{
public interface Handler extends EventHandler {
void onTrackBarValueChanged(TrackBarEvent event);
}
static final Type<TrackBarEvent.Handler> TYPE =
new Type<TrackBarEvent.Handler>();
private final int value;
public TrackBarEvent(int value) {
this.value = value;
}
@Override
public Type<TrackBarEvent.Handler> getAssociatedType() {
return TYPE;
}
public int getValue() {
return value;
}
public TrackBar getTrackBar()
{
return (TrackBar)getSource();
}
@Override
protected void dispatch(Handler handler) {
handler.onTrackBarValueChanged(this);
}
}
GWTの上で [〜#〜] gwtp [〜#〜] フレームワークを使用している場合は、 this Stack を参照してください。
[〜#〜] gwtp [〜#〜] は、「次のGWTプロジェクトを簡素化する完全なモデルビュープレゼンターフレームワーク」です。