嘿,我无法确定自定义GWT事件处理程序的工作原理。我已经阅读了很多有关该主题的文章,但仍然有些模糊。我在这里读过Stackoverflow上的线程,例如一个GWT自定义事件处理程序。有人可以在下面的应用手册中解释它。
我有2个班级,每个班级和一个男人班。当该人与该块碰撞时,该人触发一个事件(onCollision()),然后该块类侦听该事件。
谢谢
嘿,我无法确定自定义GWT事件处理程序的工作原理。我已经阅读了很多有关该主题的文章,但仍然有些模糊。我在这里读过Stackoverflow上的线程,例如一个GWT自定义事件处理程序。有人可以在下面的应用手册中解释它。
我有2个班级,每个班级和一个男人班。当该人与该块碰撞时,该人触发一个事件(onCollision()),然后该块类侦听该事件。
谢谢
Answers:
事件总是被发送以通知某些事情(例如状态改变)。让我们以一个男人和一堵墙为例。在这里,我们可以想象有一个游戏,用户可以像迷宫中的男人一样行走。每次用户撞墙时,都应告知碰撞,以便对其做出反应(例如,一堵墙可能使自己成为被破坏的墙)。这可以通过在每次检测到与墙壁的碰撞时发送碰撞事件来实现。该事件由一个人发送,并且系统中对该事件感兴趣的每个对象都可以接收该事件并可以做出相应的反应。想要接收事件的对象必须将自己注册为对事件感兴趣。
这就是事件通常在每个系统或框架中(不仅在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
。但是,在每个事件类中,它们通常都以非常相似的方式实现。
该类存储有关已接收消息的信息(请参阅构造函数)。每个事件接收者都可以使用getMessage
方法获取它。
GWT中的每个事件类型都与一个表示该事件类型的接收者的接口相关联。在GWT中,接收者称为处理程序。在示例中,事件接收器接口MessageReceivedEvent
将被命名为MessageReceivedEventHandler
。源代码如下:
public interface MessageReceivedEventHandler extends EventHandler {
void onMessageReceived(MessageReceivedEvent event);
}
每个处理程序都必须扩展EventHandler
接口。它还应定义一种方法,该方法将在事件发生时调用(它应至少包含一个参数-事件)。该方法在此命名为onMessageReceived
。每个接收者都可以通过实现此方法来对事件做出反应。
该示例中唯一的事件接收者是MessageDisplayer
component:
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
字段。在GWTHandlerManager
中,顾名思义,它管理事件处理程序(事件接收器)。就像一开始所说的,每个想要接收事件的事件接收者都必须将自己注册为感兴趣的对象。这就是处理程序管理器的用途。它们使注册事件处理程序成为可能,并且它们可以将特定事件发送到每个注册的事件处理程序。
HanlderManager
创建a时,它将在其构造函数中使用一个参数。每个事件都有一个来源,此参数将用作此处理程序管理器发送的所有事件的来源。在示例中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的回答以来,添加了对创建自定义事件的方式稍有不同的支持。此事件实现是与包中GWT的EventBus一起使用的特定构建com.google.web.bindery.event.shared
。有关如何为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调用上触发事件:
eventBus.fireEvent(new MessageReceivedEvent("my message"));
可以在GWT自己的EntityProxyChange
事件类中找到另一个实现。该实现使用EventBus的替代选项。它具有通过addHandlerToSource
和添加可以绑定到特定源的处理程序的功能eventBus.fireEventFromSource
。
与GWT的Activity配合使用时,此处给出的事件实现也更适合。
我通过扩展GWT的Composite类创建了自己的小部件。我想在此类中创建自己的自定义事件。我希望GWT的WindowBuilder编辑器可以访问这些事件。
我从本页的答案中学到了很多东西,但是我必须进行一些更改。
我想从Hilbrand Bouwkamp的答案开始,因为它是新的。但是我遇到了两个问题。1)该答案引用了事件总线。偶数总线是主程序拥有的全局变量。尚不清楚小部件库如何获得对此的访问。2)我不是从零开始。我当时正在扩展GWT库代码。为了使这项工作有效,我必须从GwtEvent类而不是Event类开始。
皮奥特(Piotr)的回答本质上是正确的,但时间很长。我的类(间接地)扩展了GWT的Widget类。小部件负责许多细节,例如创建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()开始。后来我添加了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);
}
}
public class MyWidget extends Composite implements HasValueChangeHandlers<T>, HasValue<T> { ... }