Reproductor de música en Actionscript 3, usando POO y patrón MVC

Volvemos a la clase Control. Recuerda que dentro del método crearPlaylist(), primero creábamos la clase Playlist con new Playlist(), y seguidamente la mostrábamos con mostrarlista(). Posteriormente inicializábamos el reproductor con el método inicializar() de este. Nos quedaba por ver a fondo la última línea de este método, controlReproductor(). Este método es, digamos, el centro de operaciones. Asigna detectores a los botones de la interfaz gráfica de usuario:

// Método que asigna el control de interacciones a los detectores
private function controlReproductor():void {
            // Obtener referencias a los sprites gráficos ya creados del reproductor
            var display_txt:TextField = _reproductor.getElemento("temaActual_txt") as TextField;
            var botonPlay:Sprite = _reproductor.getElemento("botonPlay") as Sprite;
            var botonStop:Sprite = _reproductor.getElemento("botonStop") as Sprite;
            var botonPrevious:Sprite = _reproductor.getElemento("botonPrevious") as Sprite;
            var botonNext:Sprite = _reproductor.getElemento("botonNext") as Sprite;
            var botonNoRepeat:Sprite = _reproductor.getElemento("botonNoRepeat") as Sprite;
            var botonRandomOff:Sprite = _reproductor.getElemento("botonRandomOff") as Sprite;
            var botonAbrir:Sprite = _reproductor.getElemento("botonAbrir") as Sprite;
            var list:List = _reproductor.getElemento("listaCanciones") as List;
            var bVolumen:Slider = _reproductor.getElemento("barraVolumen") as Slider;

            // Poner inicialmente el elemento seleccionado en el display del reprod.
            display_txt.text = list.getItemAt(list.selectedIndex).label;

            // Control de los eventos:

            // Controles de reproducción
            botonPlay.addEventListener(MouseEvent.CLICK, accionReproductor);
            botonStop.addEventListener(MouseEvent.CLICK, accionReproductor);
            botonPrevious.addEventListener(MouseEvent.CLICK, accionReproductor);
            botonNext.addEventListener(MouseEvent.CLICK, accionReproductor);

            botonPlay.doubleClickEnabled = true;
            botonStop.doubleClickEnabled = true;
            botonPrevious.doubleClickEnabled = true;
            botonNext.doubleClickEnabled = true;
            botonPlay.addEventListener(MouseEvent.DOUBLE_CLICK, accionReproductor);
            botonStop.addEventListener(MouseEvent.DOUBLE_CLICK, accionReproductor);
            botonPrevious.addEventListener(MouseEvent.DOUBLE_CLICK, accionReproductor);
            botonNext.addEventListener(MouseEvent.DOUBLE_CLICK, accionReproductor);

            // Controles de opciones de reproducción
            botonNoRepeat.addEventListener(MouseEvent.CLICK, accionReproductor);
            botonRandomOff.addEventListener(MouseEvent.CLICK, accionReproductor);
            list.addEventListener(ListEvent.ITEM_DOUBLE_CLICK, accionReproductor);
            list.addEventListener(Event.CHANGE, accionReproductor);
            bVolumen.addEventListener(Event.CHANGE, accionReproductor);

            // Controles de hints o mensajes contextuales
            botonNoRepeat.addEventListener(MouseEvent.ROLL_OVER, crearTip);
            botonNoRepeat.addEventListener(MouseEvent.ROLL_OUT, cerrarTip);
            botonRandomOff.addEventListener(MouseEvent.ROLL_OVER, crearTip);
            botonRandomOff.addEventListener(MouseEvent.ROLL_OUT, cerrarTip);
            bVolumen.addEventListener(MouseEvent.ROLL_OVER, crearTip);
            bVolumen.addEventListener(MouseEvent.ROLL_OUT, cerrarTip);
 }

Al inicio del método, obtenemos referencias a los botones que hay por defecto en el reproductor, y les asignamos los diferentes detectores de eventos de ratón. En vez de crear distintos manejadores de evento para cada detector de clic, lo que hago es asignarles el mismo, accionReproductor(). Más tarde en el manejador, como veremos a continuación, se puede filtrar qué botón ha activado el evento para actuar en consecuencia. También asigno detectores de rollOver y rollOut para los botones de opción con el fin de crear mensajes contextuales explicativos gracias a la clase Tip, que ya veremos después. De momento vamos a ver lo que realiza el método accionReproductor(), para la gestión de los clics:

// Manejador de eventos de CLICK y DOUBLE_CLICK en botones
private function accionReproductor(e:Event):void {
            var boton:Sprite = e.currentTarget as Sprite;
            var botonPlay, botonPause, botonRep, botonRandom:Sprite;
            trace(boton);
            switch (boton.name) {
                case "botonPlay":
                    _reproductor.play();
                    botonPause = new BotonPause();
                    intercambiar(boton, botonPause, "botonPause");
                break;
                case "botonStop":
                    _reproductor.stop();
                    if ((botonPause = Sprite(_reproductor.getChildByName("botonPause"))) != null) {
                        botonPlay = new BotonPlay();
                        intercambiar(botonPause, botonPlay, "botonPlay");
                    }
                break;
                case "botonPause":
                    _reproductor.pause();
                    botonPlay = new BotonPlay();
                    intercambiar(boton, botonPlay, "botonPlay");
                break;
                case "botonPrevious":
                    _reproductor.previous();
                break;
                case "botonNext":
                    _reproductor.next();
                break;
                case "botonNoRepeat":
                    // Al clicar "no repeat" pasamos al estado "repeat once", y poner su icono correspondiente
                    _reproductor.estadoRepeat = 1;
                    botonRep = new BotonRepeatOnce();
                    intercambiar(boton, botonRep, "botonRepeatOnce");
                break;
                case "botonRepeatOnce":
                    // Al clicar "repeat once" pasamos al estado "repeat all", y ponemos su icono
                    _reproductor.estadoRepeat = 2;
                    botonRep = new BotonRepeatAll();
                    intercambiar(boton, botonRep, "botonRepeatAll");
                break;
                case "botonRepeatAll":
                    // Al clicar "repeat all" pasamos al estado "no repeat", y ponemos su icono
                    _reproductor.estadoRepeat = 0;
                    botonRep = new BotonNoRepeat();
                    intercambiar(boton, botonRep, "botonNoRepeat");
                break;
                case "listaCanciones":
                    // Comprobar si se trata de un doble clic en un item o de un cambio de item
                    trace("Tipo de evento: " + e.type);
                    if (e.type == Event.CHANGE) {
                        _reproductor.reset();
                    }
                    if (e.type == ListEvent.ITEM_DOUBLE_CLICK) {
                        if (_reproductor.isPlaying) {
                            _reproductor.stop();
                        }
                        _reproductor.play();
                        if ((botonPlay = _reproductor.getChildByName("botonPlay") as Sprite) != null) {
                            botonPause = new BotonPause();
                            intercambiar(botonPlay, botonPause, "botonPause");
                        }
                    }
                break;
                case "botonRandomOff":
                    // Al hacer clic en "estado random off", pasamos a "estado random on" y mostramos su botón
                    _reproductor.estadoRandom = true;
                    botonRandom = new BotonRandomOn();
                    intercambiar(boton, botonRandom, "botonRandomOn");
                break;
                case "botonRandomOn":
                    // Al hacer clic en "estado random on", pasamos a "estado random off" y mostramos su botón
                    _reproductor.estadoRandom = false;
                    botonRandom = new BotonRandomOff();
                    intercambiar(boton, botonRandom, "botonRandomOff");
                break;
                case "barraVolumen":
                    // Ordenar al reproductor que se actualice su volumen dependiendo del
                    // nuevo valor del slider "barraVolumen"
                    _reproductor.cambiarVolumen();

            }
 }

Este método es largo, pero sencillo de entender. Al ejecutarse, cada vez que hay un clic o doble clic en uno de los botones, se filtra qué botón ha sido el activador del evento, y mediante un switch podemos actuar dependiendo del nombre de instancia del botón. Pero antes de pasar a ver lo que realiza específicamente cada botón, comentaré el método intercambiar(), llamado cuando se trata de botones como botonPlay, botonPause, o los botones de opción. Este método cambia el botón actual por el botón que ha de sustituirle, reasignándole los detectores de eventos pertinentes, y un nombre de instancia para poder volver a ser referenciado. Así es el código de este método:

private function intercambiar(boton1:Sprite, boton2:Sprite, nomBoton2:String):void {
     // Por si había un tip abierto, cerrarlo
     Tip.cerrar();
     // Intercambio
     boton2.x = boton1.x;
     boton2.y = boton1.y;
     boton2.name = nomBoton2;
     _reproductor.addChild(boton2);
     // Añadir detectores correspondientes para el nuevo botón
     boton2.addEventListener(MouseEvent.CLICK, accionReproductor);
     boton2.addEventListener(MouseEvent.ROLL_OVER, crearTip);
     boton2.addEventListener(MouseEvent.ROLL_OUT, cerrarTip);
     // Eliminar detectores del botón que se va a eliminar
     boton1.removeEventListener(MouseEvent.CLICK, accionReproductor);
     boton1.removeEventListener(MouseEvent.ROLL_OVER, crearTip);
     boton1.removeEventListener(MouseEvent.ROLL_OUT, cerrarTip);
     _reproductor.removeChild(boton1);
}

Ahora ya puedo comentar mejor el método accionReproductor(). Para los botones de play/pause, previous/next, habiendo aclarado el método intercambiar(), el código es bastante explicativo, y en cualquier caso, los métodos análogos de la clase Reproductor llamados desde aquí se verán en su momento. El botón de stop a efectos de funcionalidad interna, hace lo mismo que el de pause, o sea, una parada de reproducción y un intercambio entre botones del pause al play, solo que ha de comprobarse que previamente está en marcha el botón pause, o dicho de otra forma, hay una canción reproduciéndose. Entre los botones botonNoRepeat, botonRepeatOnce, botonRepeatAll, hay un sucesivo intercambio, y un cambio de estado en el reproductor para cada uno de ellos. Lo mismo pasa entre botonRandomOff y botonRandomOn. Por último nos quedan los botones barraVolumen, que llama al reproductor para que actualice el volumen del sonido dependiendo del nuevo valor de dicha barra (recuerda, el componente Slider), y listaCanciones, que se trata del componente List. En este último caso, se ha de filtrar también qué tipo de evento ha sido ejecutado para este componente. Puede haber sido un doble clic en cualquier elemento de la lista, lo cual reproduciría su canción correspondiente desde el principio, o puede haber sido un evento change, en cuyo caso se le ordena al reproductor que se resetee.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>