Exemple de gestion des événements : Alarm Clock

Flash Player 9 et les versions ultérieures, Adobe AIR 1.0 et les versions ultérieures

L’exemple Alarm Clock correspond à une horloge qui permet à l’utilisateur de déterminer l’heure à laquelle l’alarme doit se déclencher et d’afficher un message en même temps. Il repose sur l’application SimpleClock du chapitre Utilisation des dates et des heures et illustre de nombreux aspects de l’utilisation des événements dans ActionScript 3.0, notamment les suivants :

  • Ecoute des événements et réponse

  • Notification d’un événement aux écouteurs

  • Créer un type d’événement personnalisé

Pour obtenir les fichiers d’application Flash Professional associés à cet exemple, voir www.adobe.com/go/learn_programmingAS3samples_flash_fr. Pour obtenir les fichiers d’application Flex associés à cet exemple, voir http://www.adobe.com/go/as3examples_fr. Les fichiers d’application Alarm Clock se trouvent dans le dossier Samples/AlarmClock. Il s’agit des fichiers suivants :

Fichier

Description

AlarmClockApp.mxml

ou

AlarmClockApp.fla

Fichier d’application principal dans Flash (FLA) ou Flex (MXML).

com/example/programmingas3/clock/AlarmClock.as

Classe permettant d’étendre la classe SimpleClock, qui ajoute la fonctionnalité de réveil.

com/example/programmingas3/clock/AlarmEvent.as

Une classe d’événement personnalisé (sous-classe de flash.events.Event), qui sert d’objet événement à l’événement alarm de la classe AlarmClock.

com/example/programmingas3/clock/AnalogClockFace.as

Dessine une horloge ronde et les aiguilles des heures, des minutes et des secondes en fonction de l’heure (décrit dans l’exemple SimpleClock).

com/example/programmingas3/clock/SimpleClock.as

Composant d’interface d’horloge doté d’une fonctionnalité simple de mesure temporelle (décrit dans l’exemple SimpleClock).

Présentation du réveil

Dans cet exemple, la principale fonctionnalité de l’horloge (dont la mesure du temps et l’affichage du cadran) réutilise le code de l’application SimpleClock, décrite à la section Exemple de date et heure : horloge analogique simple. La classe AlarmClock étend la classe SimpleClock de cet exemple en y ajoutant la fonctionnalité de réveil requise : réglage de l’heure de déclenchement et avertissement une fois l’alarme déclenchée.

Le rôle des événements est de fournir un avertissement lorsque se produit quelque chose. La classe AlarmClock expose l’événement Alarme, à l’écoute duquel d’autres objets peuvent être placés afin d’effectuer les actions voulues. En outre, la classe AlarmClock utilise une occurrence de la classe Timer pour déterminer à quel moment déclencher l’alarme. Comme la classe AlarmClock, la classe Timer fournit un événement pour avertir d’autres objets (une occurrence de AlarmClock dans ce cas) une fois un certain délai écoulé. Comme dans la plupart des applications ActionScript, les événements constituent une part importante de la fonctionnalité de l’exemple Alarm Clock.

Déclenchement de l’alarme

Comme mentionné plus haut, la seule fonctionnalité de la classe AlarmClock est liée à la définition et au déclenchement de l’alarme. La classe intégrée Timer (flash.utils.Timer) permet au développeur de définir du code qui sera exécuté après un délai spécifique. La classe AlarmClock utilise une occurrence de Timer pour déterminer le moment auquel déclencher l’alarme.

    import flash.events.TimerEvent; 
    import flash.utils.Timer; 
 
    /** 
     * The Timer that will be used for the alarm. 
     */ 
    public var alarmTimer:Timer; 
    ... 
    /** 
     * Instantiates a new AlarmClock of a given size. 
     */ 
    public override function initClock(faceSize:Number = 200):void 
    { 
        super.initClock(faceSize); 
        alarmTimer = new Timer(0, 1); 
        alarmTimer.addEventListener(TimerEvent.TIMER, onAlarm); 
    }

L’occurrence de Timer définie dans la classe AlarmClock est appelée alarmTimer. La méthode initClock(), qui effectue les opérations de configuration nécessaires à l’occurrence de AlarmClock, exploite la variable alarmTimer de deux manières. Tout d’abord, la variable est instanciée avec les paramètres indiquant à l’occurrence de Timer d’attendre 0 milliseconde et de déclencher l’événement timer une seule fois. Après instanciation de alarmTimer, le code appelle la méthode addEventListener() de cette variable pour indiquer qu’il veut écouter l’événement timer de cette variable. Le fonctionnement d’une occurrence de Timer repose sur la distribution de l’événement timer après un certain délai. La classe AlarmClock doit savoir quand l’événement timer est distribué afin de déclencher sa propre alarme. En appelant addEventListener(), le code AlarmClock s’enregistre comme écouteur auprès de alarmTimer. Les deux paramètres indiquent que la classe AlarmClock souhaite écouter l’événement timer (indiqué par la constante TimerEvent.TIMER), et que lorsque l’événement survient, la méthode onAlarm() de la classe AlarmClock doit être appelée en réponse à l’événement.

Pour effectivement définir l’alarme, la méthode setAlarm() de la classe AlarmClock est appelée, comme suit :

    /** 
     * Sets the time at which the alarm should go off. 
     * @param hour The hour portion of the alarm time. 
     * @param minutes The minutes portion of the alarm time. 
     * @param message The message to display when the alarm goes off. 
     * @return The time at which the alarm will go off. 
     */ 
    public function setAlarm(hour:Number = 0, minutes:Number = 0, message:String = "Alarm!"):Date 
    { 
        this.alarmMessage = message; 
        var now:Date = new Date(); 
        // Create this time on today's date. 
        alarmTime = new Date(now.fullYear, now.month, now.date, hour, minutes); 
 
        // Determine if the specified time has already passed today. 
        if (alarmTime <= now) 
        { 
            alarmTime.setTime(alarmTime.time + MILLISECONDS_PER_DAY); 
        } 
     
        // Stop the alarm timer if it's currently set. 
        alarmTimer.reset(); 
        // Calculate how many milliseconds should pass before the alarm should 
        // go off (the difference between the alarm time and now) and set that 
        // value as the delay for the alarm timer. 
        alarmTimer.delay = Math.max(1000, alarmTime.time - now.time); 
        alarmTimer.start(); 
     
        return alarmTime; 
    }

Cette méthode effectue plusieurs opérations, notamment le stockage du message d’alarme et la création d’un objet Date (alarmTime) représentant le moment réel où l’alarme se déclenchera. Point le plus important de cette étude, le minuteur de la variable alarmTimer, dans les dernières lignes la méthode, est défini et activé. Tout d’abord, la méthode reset() est appelée, qui arrête le minuteur et le remet à zéro s’il est déjà reparti. Ensuite, l’heure actuelle (représentée par la variable now) est soustraite à la valeur de la variable alarmTime afin de déterminer combien de millisecondes doivent s’écouler avant le déclenchement de l’alarme. La classe Timer ne déclenche pas l’événement timer à une heure absolue ; c’est ce décalage relatif qui est attribué à la propriété delay d’alarmTimer. Enfin, la méthode start() est appelée pour lancer le minuteur.

Une fois le délai spécifié écoulé, alarmTimer distribue l’événement timer. Comme la classe AlarmClock s’est enregistrée comme écouteur auprès de sa méthode onAlarm() pour l’événement timer, lorsque celui-ci survient, onAlarm() est appelée.

    /** 
     * Called when the timer event is dispatched. 
     */ 
    public function onAlarm(event:TimerEvent):void  
    { 
        trace("Alarm!"); 
        var alarm:AlarmEvent = new AlarmEvent(this.alarmMessage); 
        this.dispatchEvent(alarm); 
    }

Lorsqu’une méthode est enregistrée comme écouteur d’événement, elle doit être définie avec la signature adaptée (c’est-à-dire le jeu de paramètres et le type de renvoi de la méthode). Pour écouter l’événement timer de la classe Timer, une méthode doit comporter un paramètre dont le type de données est TimerEvent (flash.event.TimerEvent), une sous-classe de la classe Event. Lorsque l’occurrence de Timer appelle ses écouteurs d’événement, elle transmet une occurrence de TimerEvent à l’objet événement.

Notification de l’alarme à d’autres composants

De même que la classe Timer, la classe AlarmClock fournit un événement qui permet de transmettre des notifications à d’autres éléments de code lorsque l’alarme se déclenche. Pour qu’une classe puisse utiliser le système de gestion des événements intégré à ActionScript, elle doit implémenter l’interface flash.events.IEventDispatcher. La plupart du temps, cela se fait par extension de la classe flash.events.EventDispatcher, qui assure une implémentation standard de IEventDispatcher (ou par extension de l’une des sous-classes de EventDispatcher). Comme décrit précédemment, la classe AlarmClock étend la classe SimpleClock, qui (par le biais d’une chaîne d’héritage) étend la classe EventDispatcher. Ainsi, la classe AlarmClock intègre déjà une fonctionnalité lui permettant de fournir ses propres événements.

D’autres éléments de code peuvent s’enregistrer pour être notifiés de l’événement alarm de la classe AlarmClock en appelant la méthode addEventListener(), héritée de EventDispatcher. Lorsqu’une occurrence de AlarmClock est prête à notifier à d’autres éléments de code le déclenchement de l’événement alarm, elle le fait en appelant la méthode dispatchEvent(), également héritée de EventDispatcher.

        var alarm:AlarmEvent = new AlarmEvent(this.alarmMessage); 
        this.dispatchEvent(alarm);

Ces lignes de code sont extraites de la méthode onAlarm() de la classe AlarmClock (présentée plus haut dans son intégralité). La méthode dispatchEvent() de l’occurrence de AlarmClock est appelée, puis elle notifie à tous les écouteurs enregistrés le déclenchement de l’événement alarm de l’occurrence de AlarmClock. Le paramètre transmis à dispatchEvent() est l’objet événement qui sera ensuite passé aux méthodes d’écouteur. Dans ce cas, il s’agit d’une occurrence de la classe AlarmEvent, une sous-classe de Event créée spécialement pour cet exemple.

Elaboration d’un événement d’alarme personnalisé

Tous les écouteurs d’événement reçoivent un paramètre d’objet événement avec des informations sur l’événement qui a été déclenché. Dans bien des cas, l’objet événement est une occurrence de la classe Event. Dans d’autres cas néanmoins, il s’avère utile de fournir des informations complémentaires aux écouteurs d’événement. Il suffit pour cela de définir une nouvelle classe, sous-classe de la classe Event, et d’utiliser une occurrence de cette classe comme objet événement. Dans cet exemple, une occurrence de AlarmEvent est utilisée comme objet événement lorsque l’événement alarm de la classe AlarmClock est distribué. La classe AlarmEvent, présentée ici, fournit des informations complémentaires sur l’événement alarm, à savoir le message d’alarme :

    import flash.events.Event; 
     
    /** 
     * This custom Event class adds a message property to a basic Event. 
     */ 
    public class AlarmEvent extends Event  
    { 
        /** 
         * The name of the new AlarmEvent type. 
         */ 
        public static const ALARM:String = "alarm"; 
         
        /** 
         * A text message that can be passed to an event handler 
         * with this event object. 
         */ 
        public var message:String; 
         
        /** 
         *Constructor. 
         *@param message The text to display when the alarm goes off. 
         */ 
        public function AlarmEvent(message:String = "ALARM!") 
        { 
            super(ALARM); 
            this.message = message; 
        } 
        ... 
    }

Le meilleur moyen de créer une classe d’objet événement personnalisée est de définir une classe qui étend la classEvent, comme illustré dans l’exemple précédent. Pour compléter la fonctionnalité héritée, la classe AlarmEvent définit une propriété message qui contient le texte du message d’alarme associé à l’événement. La valeur message est transmise sous forme de paramètre au constructeur AlarmEvent. La classe AlarmEvent définit également la constante ALARM qui peut servir à référencer l’événement (alarm) lors de l’appel de la méthode addEventListener() de la classe AlarmClock.

Outre l’ajout de fonctionnalité, chaque sous-classe Event doit redéfinir la méthode clone() héritée dans le cadre de la gestion des événements ActionScript. Les sous-classes Event peuvent éventuellement redéfinir la méthode toString() afin d’inclure les propriétés de l’événement personnalisé dans la valeur renvoyée par l’appel de la méthode toString().

    /** 
     * Creates and returns a copy of the current instance. 
     * @return A copy of the current instance. 
     */ 
    public override function clone():Event 
    { 
        return new AlarmEvent(message); 
    } 
     
    /** 
     * Returns a String containing all the properties of the current 
     * instance. 
     * @return A string representation of the current instance. 
     */ 
    public override function toString():String 
    { 
        return formatToString("AlarmEvent", "type", "bubbles", "cancelable", "eventPhase", "message"); 
    }

La méthode clone() redéfinie doit renvoyer une nouvelle occurrence de la sous-classe Event personnalisée, avec toutes les propriétés personnalisées définies pour correspondre à l’occurrence actuelle. Dans la méthode toString() redéfinie, la méthode d’utilitaire formatToString() (héritée de Event) sert à fournir une chaîne comportant le nom du type personnalisé, ainsi que les noms et valeurs de toutes ses propriétés.