web-dev-qa-db-fra.com

Événements personnalisés GWT

J'ai un problème pour comprendre comment fonctionnent les gestionnaires d'événements GWT personnalisés. J'ai lu pas mal de choses sur le sujet et c'est toujours un peu brumeux. J'ai lu les discussions ici sur Stackoverflow comme celui-ci Gestionnaire d’événements personnalisés GWT . Quelqu'un pourrait-il l'expliquer dans un mannar appliqué tel que celui-ci.

J'ai 2 classes un bloc et une classe homme. Lorsque l'homme entre en collision avec le bloc, il déclenche un événement (onCollision ()), puis la classe de blocage l'écoute.

Merci

67
Ciarán

Événements en général:

Les événements sont toujours envoyés pour informer de quelque chose (par exemple un changement d'état). Prenons votre exemple avec un homme et un mur. Ici, nous pouvons imaginer qu’il existe un jeu dans lequel un utilisateur peut marcher comme un homme dans un labyrinthe. Chaque fois qu'un utilisateur heurte un mur, il doit être informé de la collision pour pouvoir y réagir (par exemple, un mur peut se transformer en mur détruit). Cela peut être réalisé en envoyant un événement de collision chaque fois que la collision avec un mur est détectée. Cet événement est envoyé par un homme et chaque objet du système intéressé par l'événement le reçoit et peut y réagir en conséquence. Les objets qui veulent recevoir des événements doivent s'inscrire eux-mêmes comme intéressés par l'événement.

C’est ainsi que les événements fonctionnent en général dans tous les systèmes et toutes les structures (pas seulement dans GWT). Pour envoyer et recevoir des événements dans de tels systèmes, vous devez définir:

  1. Ce qui est envoyé (à quoi ressemblent les événements)
  2. Qui reçoit des événements (destinataires d'événements)
  3. Qui envoie des événements (expéditeurs d'événements)

Ensuite vous pouvez:

  1. Enregistrer les destinataires d'événements qui souhaitent recevoir des événements
  2. Envoyer des événements

Événements dans GWT:

Ici, je vais montrer un exemple d'utilisation d'événements personnalisés dans GWT. Je vais utiliser un exemple de système chargé de vérifier une boîte aux lettres et d’informer un utilisateur s’il ya de nouveaux messages. Supposons que le système comporte au moins 2 composants:

  • vérificateur de message chargé de vérifier la boîte aux lettres et 
  • afficheur de messages responsable de l'affichage des nouveaux mails

Le vérificateur de messages envoie des événements lorsqu'un nouveau courrier est reçu et l'afficheur de messages les reçoit.

Étape 1: Définir les événements

Les informations sur un nouveau courrier seront envoyées en tant qu'instance de la classe MessageReceivedEvent. La classe contient un nouveau courrier (pour la simplicité supposons que ce soit juste une String). 

Le code source complet de cette classe est présenté ci-dessous (le commentaire est en dessous du code source). 

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 est une interface qui représente les destinataires d'événements. Ne vous embêtez pas pour le moment, nous en discuterons plus tard.

Chaque classe représentant un événement GWT doit étendre la classe GwtEvent. Cette classe contient deux méthodes abstraites qui doivent être implémentées: getAssociatedType et dispatch. Cependant, dans chaque classe d'événements, ils sont généralement mis en œuvre de manière très similaire.

La classe stocke des informations sur un message reçu (voir constructeur). Chaque destinataire d’événement peut l’obtenir en utilisant la méthode getMessage.

Étape 2: Définir les destinataires d'événements

Chaque type d'événement dans GWT est associé à une interface représentant les destinataires de ce type d'événement. En GWT, les récepteurs sont appelés gestionnaires. Dans l'exemple, une interface de récepteur d'événements pour MessageReceivedEvent sera nommée MessageReceivedEventHandler. Le code source est ci-dessous:

public interface MessageReceivedEventHandler extends EventHandler {
    void onMessageReceived(MessageReceivedEvent event);
}

Chaque gestionnaire doit étendre l'interface EventHandler. Il devrait également définir une méthode qui sera invoquée lorsqu'un événement se produit (il devrait prendre au moins un paramètre - un événement). Ici, la méthode s'appelle onMessageReceived. Chaque destinataire peut réagir à un événement en implémentant cette méthode.

Le seul destinataire d'événements dans l'exemple est le composant MessageDisplayer:

public class MessageDisplayer implements MessageReceivedEventHandler {

    @Override
    public void onMessageReceived(MessageReceivedEvent event) {
        String newMessage = event.getMessage();
        // display a new message
        // ...
    }

}

Étape 3: Définir les expéditeurs d'événements

Dans l'exemple, le seul expéditeur d'événement est un composant responsable de la vérification des e-mails - 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);
    }

}

Chaque expéditeur d’événement doit implémenter l’interface HasHandlers.

L'élément le plus important ici est un champ HandlerManager. Dans GWT, HandlerManager comme son nom l'indique gère les gestionnaires d'événements (récepteurs d'événements). Comme il a été dit au début, chaque récepteur d’événement qui souhaite recevoir des événements doit s’inscrire lui-même comme intéressé. C'est à quoi servent les gestionnaires de gestionnaires. Ils permettent d’enregistrer des gestionnaires d’événements et d’envoyer un événement particulier à chaque gestionnaire d’événements enregistré.

Quand une HanlderManager est créée, il faut un argument dans son constructeur. Chaque événement a une source d'origine et ce paramètre sera utilisé comme source pour tous les événements envoyés par ce gestionnaire de gestionnaires. Dans l'exemple, il s'agit de this car la source des événements est MessageChecker.

La méthode fireEvent est définie dans l'interface HasHandlers et est responsable de l'envoi des événements. Comme vous pouvez le constater, il utilise simplement un gestionnaire de gestionnaires pour envoyer (déclencher) et déclencher un événement.

addMessageReceivedEventHandler est utilisé par les destinataires d’événements pour s’enregistrer comme intéressés par la réception d’événements. Encore une fois gestionnaire gestionnaire est utilisé pour cela.

Étape 4: associez les destinataires d'événements aux expéditeurs d'événements

Lorsque tout est défini, les destinataires d'événements doivent s'inscrire eux-mêmes dans les expéditeurs d'événements. Cela se fait généralement lors de la création d'objets:

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

Désormais, tous les événements envoyés par checker seront reçus par displayer.

Étape 5: Envoyer des événements

Pour envoyer un événement, MessageChecker doit créer une instance d'événement et l'envoyer à l'aide de la méthode fireEvent. Cela peut être fait avec la méthode 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);
    }

}

J'espère que c'est clair et que ça va aider :)

194
Piotr

Depuis cette question et la réponse de Piotr, GWT a ajouté la prise en charge d’une manière légèrement différente de créer des événements personnalisés. Cette implémentation d'événement est une construction spécifique à utiliser avec EventBus du GWT dans le package com.google.web.bindery.event.shared. Un exemple sur la façon de créer un événement personnalisé pour 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);
    }
}

L'événement est utilisé comme suit:

Pour inscrire votre gestionnaire pour cet événement avec eventbus, appelez la méthode du registre statique sur la classe MessageReceivedEvent:

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

Maintenant, déclenchez l'événement sur l'appel eventbus fireEvent avec un événement nouvellement construit:

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

Une autre implémentation peut être trouvée dans la propre classe d'événements EntityProxyChange de GWT. Cette implémentation utilise une option alternative de EventBus. Il utilise la possibilité d'ajouter des gestionnaires liés à une source spécifique via addHandlerToSource et pouvant être déclenchés via eventBus.fireEventFromSource.

La mise en œuvre de l'événement donnée ici est également plus appropriée lorsque vous travaillez avec Activités .

35
Hilbrand Bouwkamp

J'ai créé mon propre widget en étendant la classe Composite de GWT. Je voulais créer mon propre événement personnalisé dans cette classe. Je voulais que les événements soient accessibles à l'éditeur WindowBuilder de GWT.

J'ai beaucoup appris des réponses fournies sur cette page, mais j'ai dû faire quelques changements.

Je voulais commencer par la réponse de Hilbrand Bouwkamp, ​​car elle était plus récente. Mais j'ai rencontré quelques problèmes. 1) Cette réponse faisait référence au bus d’événement. Le bus pair est une variable globale appartenant au programme principal. Il n'est pas clair comment une bibliothèque de widgets pourrait avoir accès à cela. 2) Je ne partais pas de zéro. J'étais en train d'étendre le code de la bibliothèque GWT. Pour que cela fonctionne, je devais partir de la classe GwtEvent, plutôt que de la classe Event.

La réponse de Piotr est essentiellement correcte, mais c'était très long. Ma classe (indirectement) étend la classe Widget de GWT. Widget prend en charge de nombreux détails, tels que la création d'un objet HandlerManager. (J'ai parcouru le code source et c'est exactement comment les widgets standard fonctionnent, pas en utilisant un EventBus.)

Je n'avais qu'à ajouter deux éléments à ma classe de widgets pour ajouter un gestionnaire d'événements personnalisé. Ceux-ci sont montrés ici:

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);
    }

Mon nouvel événement est presque identique à la classe d'événements de Piotr, illustrée ci-dessus. Une chose est à noter. J'ai commencé avec getValue (), sur la base de cet exemple. Plus tard, j'ai ajouté getTrackBar () pour donner beaucoup plus d'informations. Si je partais de zéro, je me concentrerais sur le dernier, et non le premier. La classe d'événement complète est indiquée ci-dessous.

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);
    }
}
3
Trade-Ideas Philip

Si vous utilisez le framework GWTP par dessus GWT, reportez-vous à this Stack .

GWTP est "Un cadre complet modèle-vue-présentateur pour simplifier votre prochain projet GWT."

0
cellepo