GWT自定义事件
嘿,我有一个问题得到我的头自定义GWT事件处理程序的工作。 我已经读了很多关于这个话题,还是有些模糊。 我已经阅读了Stackoverflow上的线程,就像这个GWT自定义事件处理程序一样 。 有人可以用下面的应用mannar来解释它吗?
我有2个课程块和一个男人课。 当男人与块相撞时,男人会发起一个事件(onCollision()),然后块类监听这个事件。
谢谢
一般事件:
总是发送事件来通知某些事情(例如状态的改变)。 让我们以一个男人和一堵墙为例。 在这里,我们可以想象,有一个游戏,用户可以在迷宫中走路。 每次用户碰到墙壁时,都应该通知碰撞,以便它能够对其发生反应(例如,墙壁可以将其本身视为被摧毁的墙壁)。 每当检测到与墙壁发生碰撞时,都可以通过发送碰撞事件来实现。 这个事件是由一个人发送的,系统中感兴趣的每个对象都会接收到它,并可以相应地做出反应。 想要接收事件的对象必须注册自己感兴趣的事件。
这是事件如何在每个系统或框架(不仅在GWT中)普遍工作。 为了在这样的系统中发送和接收事件,你必须定义:
- 什么发送(事件是什么样的)
- 谁接收事件(事件接收器)
- 谁发送事件(事件发送者)
然后你可以:
- 注册想要接收事件的事件接收器
- 发送事件
GWT中的事件:
这里我将展示一个在GWT中使用自定义事件的例子。 我将使用负责检查邮箱并通知用户是否有新邮件的系统的示例。 假设系统中至less有两个组件:
- 消息检查器负责检查邮箱和
- 消息显示器负责显示新的邮件
消息检查器在收到新邮件并且消息显示器收到这些事件时发送事件。
第1步:定义事件
有关新邮件的信息将作为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
。 然而,在每一类事件中,他们通常以非常相似的方式实施。
该类存储有关收到的消息的信息(请参阅构造函数)。 每个事件接收者可以使用getMessage
方法获取它。
第2步:定义事件接收器
GWT中的每个事件types都与表示此事件types的接收者的接口相关联。 在GWT接收器被称为处理程序。 在这个例子中, MessageReceivedEvent
的事件接收器接口将被命名为MessageReceivedEventHandler
。 源代码如下:
public interface MessageReceivedEventHandler extends EventHandler { void onMessageReceived(MessageReceivedEvent event); }
每个处理程序必须扩展EventHandler
接口。 它还应该定义一个方法,当事件发生时它将被调用(它至less需要一个参数 – 一个事件)。 这里的方法被命名为onMessageReceived
。 每个接收者可以通过实现这个方法来对事件做出反应。
示例中唯一的事件接收者是MessageDisplayer
组件:
public class MessageDisplayer implements MessageReceivedEventHandler { @Override public void onMessageReceived(MessageReceivedEvent event) { String newMessage = event.getMessage(); // display a new message // ... } }
第3步:定义事件发送者
在这个例子中,唯一的事件发送者是一个负责检查邮件的组件 – 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
中,顾名思义就是pipe理事件处理器(事件接收器)。 正如在开始时所说的,每个想要接收事件的接收者都必须注册自己感兴趣。 这是处理程序经理的目的。 他们可以注册事件处理程序,他们可以发送特定的事件给每个注册的事件处理程序。
当一个HanlderManager
被创build时,它的构造函数需要一个参数。 每个事件都有一个源的来源,这个参数将被用作这个处理程序pipe理器发送的所有事件的源。 在这个例子中,这是事件的来源是MessageChecker
。
fireEvent
方法在HasHandlers
接口中定义,负责发送事件。 正如你所看到的,它只是使用一个处理程序pipe理器来发送(火)和事件。
事件接收者使用addMessageReceivedEventHandler
来注册他们自己感兴趣的事件。 再次处理程序pipe理器用于此。
步骤4:绑定事件接收器和事件发送器
当一切都被定义时,事件接收者必须在事件发送者中注册自己。 这通常在创build对象时完成:
MessageChecker checker = new MessageChecker(); MessageDisplayer displayer = new MessageDisplayer(); checker.addMessageReceivedEventHandler(displayer);
现在由checker
发送的所有事件将被displayer
接收。
第5步:发送事件
要发送一个事件, MessageChecker
必须创build一个事件实例并使用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的答案增加了对创build自定义事件稍微不同的方式的支持。 这个事件实现是特定的构build,与com.google.web.bindery.event.shared
包中的GWT的EventBus一起使用。 有关如何为GWT 2.4构build自定义事件的示例:
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); } }
该事件使用如下:
要使用eventbus注册此事件的处理程序,请调用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
事件类中find。 该实现使用EventBus的替代选项。 它使用通过eventBus.fireEventFromSource
添加绑定到特定源的处理程序的能力,并可以通过eventBus.fireEventFromSource
触发。
这里给出的事件实现也适用于GWT的活动 。
我通过扩展GWT的Composite类创build了自己的小部件。 我想在这个课堂上创build自己的自定义事件。 我希望事件可以被GWT的WindowBuilder编辑器访问。
我从这个页面的答案中学到了很多东西,但是我不得不做一些改变。
我想从Hilbrand Bouwkamp的答案开始,因为它更新。 但是我遇到了一些问题。 1)答案提到了事件总线。 偶数巴士是主程序拥有的全球variables。 目前尚不清楚小部件库如何访问它。 2)我不是从头开始的。 我正在扩展GWT库代码。 为了做到这一点,我不得不从GwtEvent类开始,而不是从Event类开始。
Piotr的回答基本上是正确的,但是很长。 我的类(间接)扩展了GWT的Widget类。 Widget负责处理很多细节,比如创build一个HandlerManager对象。 (我查看了源代码,这正是标准Widget的工作原理,而不是使用EventBus。)
我只需要添加两件东西到我的小部件类来添加一个自定义的事件处理程序。 这些显示在这里:
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的事件类几乎完全一样,如上所示。 有一点值得注意。 基于这个例子,我开始使用getValue()。 后来我join了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框架,请参阅此堆栈 。
GWTP是“一个完整的模型 – 视图 – 演示者框架来简化你的下一个GWT项目”。