Voorbeeld van gebeurtenisafhandeling: alarmklok

Flash Player 9 of hoger, Adobe AIR 1.0 of hoger

Het wekkervoorbeeld bestaat uit een klok waarbij de gebruiker een tijdstip kan aangeven waarop de wekker afgaat en een bericht wordt weergegeven. Het wekkervoorbeeld is gebaseerd op de toepassing SimpleClock in Werken met datums en tijden. Met dit voorbeeld worden verschillende aspecten van het werken met gebeurtenissen in ActionScript 3.0 geïllustreerd, waaronder:

  • Luisteren naar en reageren op een gebeurtenis

  • Listeners een melding geven van een gebeurtenis

  • Een aangepast gebeurtenistype maken

Zie http://www.adobe.com/go/learn_programmingAS3samples_flash_nl als u de Flash Professional-toepassingsbestanden voor dit voorbeeld wilt downloaden. Zie http://www.adobe.com/go/as3examples_nl als u de Flex-toepassingsbestanden voor dit voorbeeld wilt downloaden. U vindt de bestanden voor de wekkertoepassing in de map Samples/AlarmClock. De toepassing bestaat uit de volgende bestanden:

Bestand

Beschrijving

AlarmClockApp.mxml

of

AlarmClockApp.fla

Het hoofdtoepassingsbestand in Flash (FLA) of Flex (MXML).

com/example/programmingas3/clock/AlarmClock.as

Een klasse die de klasse SimpleClock uitbreidt en wekkerfunctionaliteit toevoegt.

com/example/programmingas3/clock/AlarmEvent.as

Een aangepaste Event-klasse (een subklasse van flash.events.Event), die als gebeurtenisobject fungeert voor de gebeurtenis alarm van de klasse AlarmClock.

com/example/programmingas3/clock/AnalogClockFace.as

Hiermee wordt een ronde wijzerplaat getekend met uur-, minuut- en secondewijzers die de tijd aangeven (beschreven in het voorbeeld SimpleClock).

com/example/programmingas3/clock/SimpleClock.as

Een wijzerplaatcomponent met eenvoudige tijdwaarnemingsfunctionaliteit (beschreven in het voorbeeld SimpleClock).

Overzicht wekker

In dit voorbeeld wordt voor de hoofdfunctionaliteit van de klok, zoals het bijhouden van de tijd en het weergeven van de wijzerplaat, opnieuw gebruikgemaakt van de code van de toepassing SimpleClock, zoals beschreven in Voorbeeld van datum en tijd: eenvoudige analoge klok. De klasse AlarmClock breidt de klasse SimpleClock van dat voorbeeld uit door de functionaliteit toe te voegen die voor een wekker is vereist, zoals het instellen van de wektijd en het geven van een melding wanneer de wekker ‘afgaat’.

Het geven van een melding wanneer er iets gebeurt is de taak waarvoor gebeurtenissen zijn bedoeld. Met de klasse AlarmClock wordt de gebeurtenis alarm beschikbaar gemaakt, waar andere objecten naar kunnen luisteren teneinde de juiste handelingen uit te voeren. Hiernaast maakt de klasse AlarmClock gebruik van een instantie van de klasse Timer om te bepalen wanneer de wekker moet afgaan. Net als de klasse AlarmClock kent de klasse Timer een gebeurtenis voor het doorgeven van meldingen aan andere objecten (een instantie AlarmClock in dit geval) wanneer een bepaalde hoeveelheid tijd is verstreken. Net als bij de meeste ActionScript-toepassingen maken bij het wekkervoorbeeld gebeurtenissen een belangrijk deel uit van de functionaliteit.

De wekker af laten gaan

Zoals eerder is vermeld, heeft de enige feitelijke functionaliteit die de klasse AlarmClock biedt, betrekking op het instellen en af laten gaan van de wekker. Met de ingebouwde klasse Timer (flash.utils.Timer) kunnen ontwikkelaars code schrijven die na een bepaalde hoeveelheid tijd wordt uitgevoerd. De klasse AlarmClock maakt gebruik van een instantie Timer om te bepalen wanneer de wekker moet afgaan.

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

De in de klasse AlarmClock gedefinieerde Timer-instantie heeft de naam alarmTimer. De methode initClock(), die vereiste instelbewerkingen uitvoert voor de instantie AlarmClock, doet twee dingen met de variabele alarmTimer. Eerst wordt de variabele geïnstantieerd met parameters die de Timer-instantie de opdracht geven om 0 milliseconden te wachten en de wekkergebeurtenis slechts één keer te activeren. Nadat alarmTimer is geïnstantieerd, roept de code de methode addEventListener() van die variabele aan om aan te geven dat deze naar de gebeurtenis timer van die variabele wil luisteren. Een instantie Timer werkt door de gebeurtenis timer te verzenden nadat een bepaalde hoeveelheid tijd is verlopen. De klasse AlarmClock moet weten wanneer de gebeurtenis timer wordt verzonden voor het laten afgaan van de eigen wekker. Door addEventListener() aan te roepen, registreert de code van AlarmClock zichzelf als listener bij alarmTimer. De twee parameters geven aan dat de klasse AlarmClock naar de gebeurtenis timer wil luisteren (aangegeven door de constante TimerEvent.TIMER) en dat bij het plaatsvinden van de gebeurtenis de methode onAlarm() van de klasse AlarmClock moet worden aangeroepen als reactie op deze gebeurtenis.

Voor het feitelijke instellen van de wektijd wordt de methode setAlarm() van de klasse AlarmClock aangeroepen, zoals hier wordt aangegeven:

    /** 
     * 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; 
    }

Deze methode doet verschillende dingen, zoals het opslaan van het wekbericht en het maken van een Date-object (alarmTime), die het feitelijke moment vertegenwoordigt waarop de wekker moet afgaan. Het belangrijkste in deze code zijn hier de laatste paar regels van de methode, waar de wekker van de variabele alarmTimer wordt ingesteld en geactiveerd. Eerst wordt de methode reset() aangeroepen, waarbij de timer wordt gestopt en opnieuw wordt ingesteld, voor het geval deze al draait. Vervolgens wordt de huidige tijd (vertegenwoordigd door de variabele now) afgetrokken van de waarde van de variabele alarmTime, om te bepalen na hoeveel milliseconden de wekker kan afgaan. De gebeurtenis timer wordt niet op een absoluut tijdstip door de klasse Timer geactiveerd, zodat dit relatieve tijdsverschil wordt toegewezen aan de eigenschap delay van alarmTimer. Ten slotte wordt de methode start() aangeroepen om de timer daadwerkelijk te starten.

Als de opgegeven hoeveelheid tijd is verlopen, verzendt alarmTimer de gebeurtenis timer. Aangezien de klasse AlarmClock de methode onAlarm() als listener heeft geregistreerd voor die gebeurtenis, wordt bij het plaatsvinden van de gebeurtenis timeronAlarm() aangeroepen.

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

Een methode die als gebeurtenislistener is geregistreerd, moet met de juiste handtekening worden gedefinieerd (dat wil zeggen, met de parameters en het retourneringstype die voor de methode gelden). Een methode is een listener voor de gebeurtenis timer van de klasse Timer als deze één parameter definieert waarvan het gegevenstype gelijk is aan TimerEvent (flash.events.TimerEvent), een subklasse van de klasse Event. Als de instantie Timer de gebeurtenislisteners aanroept, wordt een instantie TimerEvent als gebeurtenisobject doorgegeven.

Anderen op de hoogte stellen van het weksignaal

Net als de klasse Timer kent de klasse AlarmClock een gebeurtenis die ervoor zorgt dat aan andere code meldingen kunnen worden gestuurd wanneer de wekker afgaat. Een klasse kan gebruikmaken van het systeem voor gebeurtenisafhandeling dat in ActionScript is ingebouwd, als deze klasse de interface flash.events.IEventDispatcher implementeert. Dit gebeurt meestal door de klasse flash.events.EventDispatcher uit te breiden, die een standaardimplementatie bevat van IEventDispatcher (of door een van de subklassen van EventDispatcher uit te breiden). Zoals hierboven werd beschreven, bevat de AlarmClock-klasse de SimpleClock-klasse, die (via een overervingsketen) de EventDispatcher-klasse bevat. Dit alles betekent dat de klasse AlarmClock al ingebouwde functionaliteit heeft om eigen gebeurtenissen aan te kunnen bieden.

Andere code kan zich registreren voor het ontvangen van een melding bij het plaatsvinden van de gebeurtenis alarm van de klasse AlarmClock door de methode addEventListener() aan te roepen die AlarmClock overerft van EventDispatcher. Wanneer een AlarmClock-instantie gereed is voor het verzenden van een melding aan andere code met betrekking tot het plaatsvinden van de gebeurtenis alarm, roept deze de methode dispatchEvent() aan, die ook wordt overgeërfd van EventDispatcher.

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

Deze regels code zijn afkomstig van de methode onAlarm() van de klasse AlarmClock (die eerder in haar geheel is weergegeven). De methode dispatchEvent() van de AlarmClock-instantie wordt aangeroepen, waardoor weer een melding wordt verzonden naar alle geregistreerde listeners dat de gebeurtenis alarm van de AlarmClock-instantie heeft plaatsgevonden. De parameter die aan dispatchEvent() wordt doorgegeven, is het gebeurtenisobject dat later ook aan de listenermethoden wordt doorgegeven. In dit geval is het een instantie van de klasse AlarmEvent, een subklasse van de klasse Event die speciaal voor dit voorbeeld is gemaakt.

Een aangepaste alarmgebeurtenis doorgeven

Alle gebeurtenislisteners ontvangen een gebeurtenisobjectparameter met informatie over de specifieke gebeurtenis die plaatsvindt. In veel gevallen is het gebeurtenisobject een instantie van de klasse Event. In sommige gevallen is het echter handig om aanvullende informatie aan gebeurtenislisteners door te geven. Een algemene manier om dit te bereiken, is om een nieuwe klasse, subklasse of gebeurtenisklasse te definiëren en een instantie van de klasse als het gebeurtenis gebruiken. In dit voorbeeld wordt een instantie AlarmEvent als gebeurtenisobject gebruikt wanneer de gebeurtenis alarm van de klasse AlarmClock wordt verzonden. De klasse AlarmEvent, die hier wordt weergegeven, bevat aanvullende informatie over de gebeurtenis alarm, met name het wekbericht:

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

De beste manier om een aangepaste gebeurtenisobjectklasse te maken, is het definiëren van een klasse die de klasse Event uitbreidt, zoals weergegeven in het vorige voorbeeld. Voor het aanvullen van de overgeërfde functionaliteit definieert de klasse AlarmEvent de eigenschap message, die de tekst bevat van het alarmbericht dat aan de gebeurtenis is gekoppeld. De waarde van message wordt als parameter doorgegeven in de constructor van AlarmEvent. De klasse AlarmEvent definieert ook de constante ALARM, die naar de specifieke gebeurtenis (alarm) kan verwijzen bij het aanroepen van de methode addEventListener() van de klasse AlarmClock.

Naast het toevoegen van aangepaste functionaliteit, moet elke subklasse van de klasse Event de overgeërfde methode clone() overschrijven als onderdeel van het systeem voor gebeurtenisafhandeling van ActionScript. Subklassen van de klasse Event kunnen optioneel ook de overgeërfde methode toString() overschrijven om de eigenschappen van de aangepaste gebeurtenis op te nemen in de waarde die bij het aanroepen van de methode toString() wordt geretourneerd.

    /** 
     * 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"); 
    }

De overschreven methode clone() moet een nieuwe instantie van de aangepaste Event-subklasse retourneren, waarbij alle aangepaste eigenschappen zo worden ingesteld dat deze met de huidige instantie overeenkomen. In de overschreven methode toString() wordt de hulpprogrammamethode formatToString() (overgeërfd van Event) gebruikt om een tekenreeks te verkrijgen met de naam van het aangepaste type en met de namen en waarden van alle eigenschappen hiervan.