GWT Custom Events - PullRequest
       8

GWT Custom Events

67 голосов
/ 01 июня 2010

Эй, у меня проблема с тем, чтобы понять, как работают пользовательские обработчики событий GWT. Я прочитал довольно много о теме, и это все еще кое-что туманное. Я читал темы здесь, в Stackoverflow, как этот Пользовательский обработчик событий GWT . Может ли кто-нибудь объяснить это в прикладном маннаре, таком как следующее.

У меня есть 2 класса: блок и мужской класс. Когда человек сталкивается с блоком, он запускает событие (onCollision ()), а затем класс блока прослушивает это событие.

Спасибо

Ответы [ 4 ]

195 голосов
/ 03 июня 2010

События в целом:

События всегда отправляются для информирования о чем-либо (например, об изменении состояния). Давайте возьмем ваш пример с человеком и стеной. Здесь можно представить, что есть игра, в которой пользователь может ходить как человек в лабиринте. Каждый раз, когда пользователь ударяется о стену, он должен быть проинформирован о столкновении, чтобы он мог на него отреагировать (например, стена может выглядеть как разрушенная стена). Это может быть достигнуто путем отправки события столкновения каждый раз, когда обнаруживается столкновение со стеной. Это событие отправляется человеком, и каждый объект в системе, заинтересованный в событии, получает его и может соответствующим образом реагировать на него. Объекты, которые хотят получать события, должны зарегистрироваться как заинтересованные в событии.

Вот как события в целом работают в каждой системе или структуре (не только в GWT). Чтобы отправлять и получать события в таких системах, необходимо определить:

  1. Что отправлено (как выглядят события)
  2. Кто получает события (получатели событий)
  3. Кто отправляет события (отправители событий)

Тогда вы можете:

  1. Регистрация получателей событий, которые хотят получать события
  2. Отправка событий

События в GWT:

Здесь я покажу пример использования пользовательских событий в GWT. Я буду использовать пример системы, которая отвечает за проверку почтового ящика и сообщать пользователю, если есть новые письма. Предположим, что в системе есть как минимум 2 компонента:

  • средство проверки сообщений, отвечающее за проверку почтового ящика, и
  • средство отображения сообщений, отвечающее за отображение новых писем

Средство проверки сообщений отправляет события при получении нового сообщения, и средство просмотра сообщений получает эти события.

Шаг 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 связан с интерфейсом, представляющим приемники этого типа события. В 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
        // ...
    }

}

Шаг 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 как подсказывает название, управляет обработчиками событий (получателями событий). Как было сказано в начале, каждый получатель событий, который хочет получать события, должен зарегистрироваться как заинтересованный. Для этого и нужны менеджеры-обработчики. Они позволяют регистрировать обработчики событий и отправлять определенное событие каждому зарегистрированному обработчику событий.

Когда создается HanlderManager, он принимает один аргумент в своем конструкторе. Каждое событие имеет источник происхождения, и этот параметр будет использоваться в качестве источника для всех событий, отправляемых этим менеджером обработчика. В примере это this, поскольку источником событий является MessageChecker.

Метод fireEvent определен в интерфейсе HasHandlers и отвечает за отправку событий. Как вы можете видеть, он просто использует диспетчер обработчиков для отправки (огня) и события.

addMessageReceivedEventHandler используется получателями событий для регистрации их как заинтересованных в получении событий. Снова для этого используется менеджер обработчиков.

Шаг 4. Связывание получателей событий с отправителями событий

Когда все определено, получатели событий должны зарегистрироваться в отправителях событий. Обычно это делается при создании объектов:

MessageChecker checker = new MessageChecker();
MessageDisplayer displayer = new MessageDisplayer();
checker.addMessageReceivedEventHandler(displayer);

Теперь все события, отправленные checker, будут получены displayer.

Шаг 5. Отправка событий

Чтобы отправить событие, 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);
    }

}

Надеюсь понятно и поможет :) 1111 *

35 голосов
/ 10 октября 2011

Поскольку в этом вопросе и ответе от Петра GWT добавлена ​​поддержка немного другого способа создания пользовательских событий. Эта реализация события является специфической сборкой, которая будет использоваться с EventBus GWT в пакете 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);
    }
}

Событие используется следующим образом:

Чтобы зарегистрировать свой обработчик для этого события с помощью eventbus, вызовите метод статического регистра в классе MessageReceivedEvent:

MessageReceivedEvent.register(eventbus, new MessageReceivedEvent.Handler() {
   public void onMessageReceived(MessageReceivedEvent event) {
     //...do something usefull with the message: event.getMessage();
   }
});

Теперь для вызова события по вызову Eventbus fireEvent с недавно созданным событием:

eventBus.fireEvent(new MessageReceivedEvent("my message"));

Другая реализация может быть найдена в собственном классе событий EntityProxyChange GWT. Эта реализация использует альтернативную опцию EventBus. Он использует возможность добавлять обработчики, которые связаны с конкретным источником, через addHandlerToSource и могут быть вызваны через eventBus.fireEventFromSource.

Приведенная здесь реализация события также более подходит при работе с GWT Activity .

3 голосов
/ 23 сентября 2013

Я создал свой собственный виджет, расширив класс GWT Composite. Я хотел создать свое собственное событие в этом классе. Я хотел, чтобы события были доступны редактору WindowBuilder от GWT.

Я многому научился из ответов на этой странице, но мне пришлось внести некоторые изменения.

Я хотел начать с ответа Хилбранда Боукампа, потому что он был новее. Но я столкнулся с парой проблем. 1) Этот ответ сделал ссылку на событие шины. Четная шина - это глобальная переменная, принадлежащая основной программе. Не ясно, как библиотека виджетов могла получить доступ к этому. 2) Я не начинал с нуля. Я расширял код библиотеки GWT. Чтобы сделать это, мне нужно было начать с класса GwtEvent, а не с класса Event.

Ответ Петра по сути правильный, но он был очень длинным. Мой класс (косвенно) расширяет класс виджетов GWT. Виджет заботится о многих деталях, таких как создание объекта HandlerManager. (Я просмотрел исходный код, и именно так работают стандартные виджеты, а не с помощью 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);
    }

Мое новое событие почти точно такое же, как класс событий Петра, показанный выше. Стоит отметить одну вещь. Я начал с 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);
    }
}
1 голос
/ 04 ноября 2015

Если вы используете GWTP фреймворк поверх GWT, см. этот стек .

GWTP - это «Полная структура представления модели-представления, упрощающая ваш следующий проект GWT».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...