Exemplo de tratamento de evento: relógio de alarme

Flash Player 9 e posterior, Adobe AIR 1.0 e posterior

O exemplo do Alarm Clock consiste em um relógio que permite que o usuário especifique um horário no qual o alarme deve ser desativado, bem como uma mensagem a ser exibida nesse horário. O exemplo do Alarm Clock baseia-se no aplicativo SimpleClock da seção Trabalho com datas e horas e ilustra vários aspectos do trabalho com eventos ActionScript 3.0, incluindo:

  • Como ouvir e responder a um evento

  • Notificação de um evento aos ouvintes

  • Criação de um tipo de evento personalizado

Para obter os arquivos do aplicativo Flash Professional dessa amostra, consulte http://www.adobe.com/go/learn_programmingAS3samples_flash_br . Para obter os arquivos do aplicativo Flex dessa amostra, consulte http://www.adobe.com/go/as3examples_br . Os arquivos do aplicativo Alarm Clock estão localizados na pasta Amostras/AlarmClock. O aplicativo inclui estes arquivos:

Arquivo

Descrição

AlarmClockApp.mxml

ou

AlarmClockApp.fla

O arquivo principal do aplicativo no Flash (FLA) ou no Flex (MXML).

com/example/programmingas3/clock/AlarmClock.as

Uma classe que estende a classe SimpleClock, adicionando a funcionalidade do despertador.

com/example/programmingas3/clock/AlarmEvent.as

Uma classe de evento personalizada (uma subclasse de flash.events.Event) que serve como objeto do evento alarm da classe AlarmClock.

com/example/programmingas3/clock/AnalogClockFace.as

Desenha a superfície de um relógio redondo e os ponteiros de horas, minutos e segundos com base na hora (descrito no exemplo de SimpleClock).

com/example/programmingas3/clock/SimpleClock.as

Um componente da interface do relógio com um recurso simples de marcação da hora (descrito no exemplo de SimpleClock).

Visão geral do Alarm Clock

O principal recurso do relógio neste exemplo, incluindo o controle da hora e a exibição da superfície do relógio, reutiliza o código do aplicativo SimpleClock, descrito em Exemplo de data e hora: relógio analógico simples . A classe AlarmClock estende a classe SimpleClock desse exemplo, adicionando a funcionalidade necessária para um despertador, incluindo a definição da hora do alarme e do envio da notificação quando o alarme for “desativado”.

Os eventos são gerados para enviar a notificação sobre algo ocorrido. A classe AlarmClock expõe o evento Alarm, que outros objetos podem ouvir para executar as ações desejadas. Além disso, a classe AlarmClock usa uma ocorrência da classe Timer para determinar quando o alarme deve ser acionado. Assim como AlarmClock, a classe Timer gera um evento para notificar outros objetos (neste caso, uma ocorrência de AlarmClock) após um determinado período. Assim como a maioria dos aplicativos do ActionScript, os eventos formam uma parte importante da funcionalidade do aplicativo Alarm Clock de exemplo.

Acionamento do alarme

Conforme mencionado anteriormente, a única funcionalidade da classe AlarmClock está relacionada com a definição e o acionamento do alarme. A classe incorporada Timer (flash.utils.Timer) permite que o desenvolvedor defina o código que será executado após o período especificado. A classe AlarmClock usa uma ocorrência de Timer para determinar quando o alarme deve ser desativado.

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

A ocorrência de Timer definida na classe AlarmClock chama-se alarmTimer . O método initClock() , que executa as operações de configuração necessárias para a ocorrência de AlarmClock, faz duas coisas com a variável alarmTimer . Primeiro, a variável é percorrida com os parâmetros que instruem a ocorrência de Timer a aguardar 0 milissegundos e acionar o evento timer apenas uma vez. Depois de percorrer alarmTimer , o código chama o método addEventListener() da variável para indicar se deseja ouvir o evento timer dessa variável. Uma ocorrência de Timer funciona enviando o evento timer após um período especificado. A classe AlarmClock não precisa saber quando o evento timer é enviado para desativar seu próprio alarme. Chamando addEventListener() , o código de AlarmClock se autorregistra como ouvinte em alarmTimer . Os dois parâmetros indicam que a classe AlarmClock deseja ouvir o evento timer (indicado pela constante TimerEvent.TIMER ) e que, quando o evento ocorrer, o método onAlarm() da classe AlarmClock deve ser chamado em resposta a esse evento.

Para definir o alarme realmente, o método setAlarm() da classe AlarmClock é chamado do seguinte modo:

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

Esse método faz várias coisas, como armazenar a mensagem do alarme e criar um objeto Date ( alarmTime ) que representa o momento real em que o alarme é desativado. O mais importante nisto tudo, nas várias linhas finais do método, é o fato de o objeto timer da variável alarmTimer ser definido e ativado. Primeiro, o método reset() é chamado, interrompendo o cronômetro e redefinindo-o caso já esteja em execução. Em seguida, o horário atual (representado pela variável now ) é subtraído do valor da variável alarmTime para determinar quantos milissegundos devem se passar até o alarme ser desativado. A classe Timer não aciona o evento timer em um tempo absoluto, de modo que essa diferença relativa de tempo é atribuída à propriedade delay de alarmTimer . Finalmente, o método start() é chamado para iniciar o cronômetro realmente.

Assim que o período especificado termina, alarmTimer envia o evento timer . Com a classe AlarmClock registrou o método onAlarm() como um ouvinte desse evento, quando o evento timer acontece, onAlarm() é chamado.

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

Um método que é registrado como ouvinte de evento deve ser definido com a assinatura apropriada (isto é, o conjunto de parâmetros e o tipo de retorno do método). Para ser ouvinte do evento timer da classe Timer, um método deve definir um parâmetro cujo tipo de dados seja TimerEvent (flash.events.TimerEvent), uma subclasse de Event. Quando chama seus ouvintes de evento, a ocorrência de Timer transmite uma ocorrência de TimerEvent como objeto de evento.

Notificação do alarme a outros

Assim como a classe Timer, a classe AlarmClock fornece um evento que permite que outros códigos recebam notificações quando o alarme é desativado. Para que uma classe use a estrutura de manipulação de eventos incorporada no ActionScript, essa classe deve implementar a interface flash.events.IEventDispatcher. Normalmente, isso é feito por meio da extensão da classe flash.events.EventDispatcher, que fornece uma implementação padrão de IEventDispatcher (ou por meio da extensão de uma das subclasses de EventDispatcher). Como descrito anteriormente, a classe AlarmClock estende a classe SimpleClock, que (através de uma cadeia de herança) estende a classe EventDispatcher. Tudo isso significa que a classe AlarmClock já tem uma funcionalidade interna para fornecer seus próprios eventos.

Outro código pode ser registrado para ser notificado sobre o evento alarm da classe AlarmClock chamando o método addEventListener() que AlarmClock herda de EventDispatcher. Quando uma ocorrência de AlarmClock está pronta para notificar outro código sobre a geração do evento alarm , o método dispatchEvent() , que também é herdado de EventDispatcher, é chamado.

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

Essas linhas de código foram obtidas do método onAlarm() da classe AlarmClock (mostrada por completo antes). O método dispatchEvent() da ocorrência de AlarmClock é chamado e notifica todos os ouvintes registrados sobre o acionamento do evento alarm da ocorrência de AlarmClock. O parâmetro transmitido para dispatchEvent() é o objeto de evento que será transmitido junto com os métodos de ouvinte. Nesse caso, é uma ocorrência da classe AlarmEvent, uma subclasse de Event criada especificamente para este exemplo.

Fornecimento de um evento de alarme personalizado

Todos os ouvintes de evento recebem um parâmetro de objeto de evento com informações sobre o evento específico que está sendo acionado. Em muitos casos, o objeto de evento é uma ocorrência da classe Event. No entanto, em alguns casos é útil fornecer informações adicionais aos ouvintes de evento. Uma maneira comum de fazer isso é definir uma nova classe, uma subclasse de Event, e usar uma ocorrência dessa classe como objeto de evento. Neste exemplo, uma ocorrência de AlarmEvent é usada como objeto quando o evento alarm da classe AlarmClock é enviado. A classe AlarmEvent, mostrada aqui, fornece informações adicionais sobre o evento alarm , especificamente a mensagem de 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; 
        } 
        ... 
    }

A melhor maneira de criar uma classe de objeto de evento personalizada é definir uma classe que estende a classe Event, como mostrou o exemplo anterior. Para complementar a funcionalidade herdada, a classe AlarmEvent define uma propriedade message que contém o texto da mensagem de alarme associada ao evento; o valor de message é transmitido como um parâmetro no construtor AlarmEvent. A classe AlarmEvent também define a constante ALARM , que pode ser usada para fazer referência ao evento específico ( alarm ) ao chamar o método addEventListener() da classe AlarmClock.

Além de adicionar a funcionalidade personalizada, cada subclasse de Event deve substituir o método clone() herdado como parte da estrutura de manipulação de eventos do ActionScript. As subclasses de Event também podem substituir o método toString() herdado para incluir as propriedades do evento personalizado no valor retornado quando o método toString() é chamado.

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

O método clone() substituído precisa retornar uma nova ocorrência da subclasse personalizada de Event, com todas as propriedades personalizadas definidas para corresponder à ocorrência atual. No método toString() substituído, o método de utilitário formatToString() (herdado de Event) é usado para fornecer uma string com o nome do tipo personalizado, bem como nomes e valores de todas as propriedades.