Comunidad de diseño web y desarrollo en internet online

Cómo acceder a la línea de tiempo desde una clase

Citar            
MensajeEscrito el 11 May 2010 11:35 am
Hola a todos.

Es la segunda vez que escribo en el foro (espero tener más acogida q la primera q no tuve ninguna respuesta :( ) y semi-nueva en AS3. Estoy haciendo una aplicación que consiste en diversas pantallas, para ello en la linea de tiempo general asigno un frame a cada pantalla (las q son diferentes o no tienene elementos comunes). Paralelamente, he ido creando diversas clases para ir cargando los contenidos de cada pantalla. Muchos de los contenidos/interfaz se cargan dinámicamente desde un XML externo (de ésto se encarga cada una de las clases correspondientes).

Dentro de cada clase p.e hay una serie de componentes que actuan como botones (pero son Mc). Para eventos de mouse como "over" tengo unas funciones detectoras de evento dentro de la misma clase. Estas funciones sí que funcionan correctamente, pero la función que atiende al click del mouse no. Mejor dicho, no es que no funcione sino que cuando las instrucciones no son relativas a la linea de tiempo (p.e. abrir página externa, abrir archivo pdf...etc) no hay ningún problema pero cuando quiero acceder a la linea de tiempo desde la clase para cambiar de frame me es imposible. La idea es simple, al pulsar sobre un componente de la clase quiero pasar de un frame a otro....Ahora, a modo provisional lo estoy haciendo pasándole una Function (declarada en la linea de tiempo) y desplazandose desde fuera de la clase, pero sinceramente no es lo que busco.

Sé que es problable que el código se pueda optimizar y ahorrar variables (con otros métodos tenia problemas) ahora mismo no es lo q me preocupa sino lo que he comentado anteriormente. COn mirar lo que he indicado en rojo suficiente.

Gracias por adelantado!!

El código (de una de las clases...) en versión resumida sería el siguiente:

[i]
package myAs{

/*________________Import de las clases necesarias____________*/
[..]
import myAs.GlobalVars;

/*____________________________________________________________*/

public class NavigationBar extends Sprite{

/*Static Vars*/
public static const TEORIA:Number= 0;
public static const EJERCICIOS:Number= 1;
public static const ACTIVIDADES:Number= 2;
public static const USUARIO:Number= 3;

/*__________________Declaración de variables__________________*/

private var urlFile :String = "Data/ES/navigationBar.xml";//Asigno la url que se va a cargar
private var datos :XML; //Objeto contenedor del XML

private var sectionOn:Number; //Variable que nos indica cual es la sección activa ("over")

private var nodeElementArray:Array;//En este array guardamos los datos de los nodos <element>
private var navigationItemArray:Array; //En este array guardamos los objetos 'NavigationBarItem'

private var changeStateArray:Array; //Array de booleanos q nos indica si el botón [i] puede cambiar o no su estado

var action:Function;

/*_____Constructor de la clase____________________________*/
function NavigationBar(myAction:Function){

action=myAction;
[...]
LoadData();
}

/*FUNCIÓN: Se encarga de carga el XML externo que contiene los atributos
de los botones de la barra de navegación*/
private function LoadData():void{

//1. Creamos objeto cargador
var loader:URLLoader=new URLLoader();
//2. Añadimos Listeners
loader.addEventListener(Event.COMPLETE,Loaded);
loader.addEventListener(IOErrorEvent.IO_ERROR,Failed);
//3. Cargar petición (creamos obj. que contendrá la petición)
loader.load(new URLRequest(urlFile));

}

/*FUNCIÓN: Se encarga de lanzar mensage de error en caso de fallo en la
carga.
*/
private function Failed(e:IOErrorEvent):void {

trace("Error loading XML file: " + e);

}
/*FUNCIÓN: Función que se ejecuta cuando se completa la descarga.
*/
private function Loaded(e:Event):void {

//1.Almacenamos los datos del XML
datos = new XML(e.target.data);

//2. Almacenar/montar los datos.
Assemble();
//3. Crear obj/Mostrar datos.
Display();

}
/*FUNCIÓN: Función q almacena los atributos/propiedades de cada <element> del XML.
*/
private function Assemble():void{

//0.1. Contabilizar el número de nodos <element>
var nElement:Number= datos.elements.element.length();
//0.2. Variable auxiliar para almacenar los atributos/propiedades de cada nodo <element>
var nodeElement:Object;
//0.3. Crear 'nodeElementArray'
nodeElementArray=new Array();

//1. Recorremos los nodos <element>
for(var i:uint=0; i<nElement; i++)
{
//1.1. Creamos objeto auxiliar
nodeElement=new Object();
nodeElement.id=datos.elements.element[i].@id;
[...]

nodeElementArray.push({id:nodeElement.id,posX:nodeElement.posX,posY:nodeElement.posY,title:nodeElement.title,destination:nodeElement.destination});

}

}
/*FUNCIÓN: Creamos cada uno de los objetos (botones) q compondrán la barra de navegación.
*/
private function Display():void{

//0.1. Miramos la longitud del vector que almacena los datos
var nElements:Number=Number(nodeElementArray.length);
//0.2. Creamos el Array que almacena los 'NavigationBarItem'
navigationItemArray=new Array();

//1. Recorremos el vector de datos
for(var k:uint=0; k<nElements; k++)
{
//1.1. Añadimos un objeto 'NavigationBarItem' al vector
navigationItemArray.push(new NavigationBarItem);

//1.2. Posicionamos el objeto
navigationItemArray[k].x=nodeElementArray[k].posX;
navigationItemArray[k].y=nodeElementArray[k].posY;

//1.3. Añadimos texto al botón
navigationItemArray[k].label_txt.text=nodeElementArray[k].title;

//1.4. Configuramos el objeto
navigationItemArray[k].buttonMode=true; //Propiedad q permite q cambie el cursor (modoBotón-mano) sobre el MovieClip
navigationItemArray[k].mouseChildren=false;//Propiedad q permite que cambie el cursor (modoBotón-mano) también sobre el texto

//1.5. Almacenamos atributos/props en el propio objeto
navigationItemArray[k].id=Number(nodeElementArray[k].id);
[..]

//1.6. Asignamos registramos funciones detectoras de eventos
navigationItemArray[k].addEventListener(MouseEvent.CLICK, action);-------->AQUÍ es donde tengo el PROBLEMA!!
navigationItemArray[k].addEventListener(MouseEvent.MOUSE_OVER, Over);
navigationItemArray[k].addEventListener(MouseEvent.MOUSE_OUT, Out);

//1.7. Añadimos a la lista de visualización
addChild(navigationItemArray[k]);

}
//Mostrar activo (teoria por defecto)
SetSectionOn(GlobalVars.getInstance().section);
UpdateSectionOn();

}//end 'Display()'

/*FUNCIONES: Func. detectoras de eventos
*/
private function Over(e:MouseEvent):void{

if(changeStateArray[e.currentTarget.id]==true)
e.currentTarget.gotoAndPlay("over"); //contiene una referencia al objeto que está procesando en ese
//momento el objeto de evento.
}
private function Out(e:MouseEvent):void{

if((e.currentTarget.id != (GlobalVars.getInstance().section))&&((changeStateArray[e.currentTarget.id]==true)))
e.currentTarget.gotoAndPlay("out");
}

/*FUNCIÓN: Getters y Setters
*/
[..]
/*FUNCIÓN: Funciones q controlan los estados de los botones (ON/OFF)
*/
public function GetSectionOn():Number{
return(sectionOn);
}
public function SetSectionOn(mySection:Number):void{

sectionOn=mySection;

switch(sectionOn){

case TEORIA:
changeStateArray[TEORIA]=false;//No puede cambiar su estado -sección activa-
changeStateArray[EJERCICIOS]=true;
changeStateArray[ACTIVIDADES]=true;
changeStateArray[USUARIO]=true;
break;

case EJERCICIOS:
[..]

}//end 'switch'
}
[..]


}//End class
}//End package


//______________________En el Timeline_______________________________

Tengo la función Navigate que es la que le paso al crear el obj.


import myAs.NavigationBar;

var navigationBar:NavigationBar=new NavigationBar(Navigate);

addChild(navigationBar);

function Navigate(e:MouseEvent):void{

switch(e.currentTarget.id)//contiene una referencia al objeto que está procesando en ese momento el objeto de evento.
{

case 0://Pulsamos TEORIA
//Si estamos en TEORIA y pulsamos TEORIA debemos mantener los contenidos
if(GlobalVars.getInstance().section!=0)
{
GlobalVars.getInstance().section=0;
removeChild(indexContent);
gotoAndStop("pantallaN4_seccionTeoria");----->Esto es lo que quiero hacer desde una función detectora de evento en la misma Clase!!!
}
else
GlobalVars.getInstance().section=0;
break;
[...]

} //end function
[/i]

Por emedmaria

73 de clabLevel



 

firefox
Citar            
MensajeEscrito el 11 May 2010 11:43 am
Para no asustar a nadie voy a resumir aun más el código...

package myAs{

/*________________Import de las clases necesarias____________*/
[..]
import myAs.GlobalVars;

public class NavigationBar extends Sprite{


/*__________________Declaración de variables__________________*/

private var urlFile :String = "Data/ES/navigationBar.xml";//Asigno la url que se va a cargar
private var datos :XML; //Objeto contenedor del XML
private var sectionOn:Number; //Variable que nos indica cual es la sección activa ("over")
private var nodeElementArray:Array;//En este array guardamos los datos de los nodos <element>
private var navigationItemArray:Array; //En este array guardamos los objetos 'NavigationBarItem'
private var changeStateArray:Array; //Array de booleanos q nos indica si el botón puede cambiar o no su estado
var action:Function;

/*_____Constructor de la clase____________________________*/
function NavigationBar(myAction:Function){
action=myAction;
[...]
LoadData();
}

/*FUNCIÓN: Se encarga de carga el XML externo que contiene los atributos
de los botones de la barra de navegación*/
private function LoadData():void{

//1. Creamos objeto cargador
var loader:URLLoader=new URLLoader();
//2. Añadimos Listeners
loader.addEventListener(Event.COMPLETE,Loaded);
loader.addEventListener(IOErrorEvent.IO_ERROR,Failed);
//3. Cargar petición (creamos obj. que contendrá la petición)
loader.load(new URLRequest(urlFile));
}

/*FUNCIÓN: Se encarga de lanzar mensage de error en caso de fallo en la
carga.
*/
private function Failed(e:IOErrorEvent):void {
trace("Error loading XML file: " + e);
}

/*FUNCIÓN: Función que se ejecuta cuando se completa la descarga.
*/
private function Loaded(e:Event):void {

//1.Almacenamos los datos del XML
datos = new XML(e.target.data);
//2. Almacenar/montar los datos.
Assemble();
//3. Crear obj/Mostrar datos.
Display();

}
/*FUNCIÓN: Función q almacena los atributos/propiedades de cada <element> del XML.
*/
private function Assemble():void{
[...]
}

/*FUNCIÓN: Creamos cada uno de los objetos (botones) q compondrán la barra de navegación.
*/
private function Display():void{
[..]
//1.6. Asignamos registramos funciones detectoras de eventos
navigationItemArray[k].addEventListener(MouseEvent.CLICK, action);-------->AQUÍ es donde tengo el PROBLEMA!!
navigationItemArray[k].addEventListener(MouseEvent.MOUSE_OVER, Over);
navigationItemArray[k].addEventListener(MouseEvent.MOUSE_OUT, Out);

//1.7. Añadimos a la lista de visualización
addChild(navigationItemArray[k]);

}
[..]

}//end 'Display()'

/*FUNCIONES: Func. detectoras de eventos
*/
private function Over(e:MouseEvent):void{

if(changeStateArray[e.currentTarget.id]==true)
e.currentTarget.gotoAndPlay("over"); //contiene una referencia al objeto que está procesando en ese
//momento el objeto de evento.
}
private function Out(e:MouseEvent):void{
if((e.currentTarget.id != (GlobalVars.getInstance().section))&&((changeStateArray[e.currentTarget.id]==true)))
e.currentTarget.gotoAndPlay("out");
}
[..]

}//End class
}//End package

//______________________En el Timeline_______________________________

Tengo la función Navigate que es la que le paso al crear el obj.


import myAs.NavigationBar;

var navigationBar:NavigationBar=new NavigationBar(Navigate);

addChild(navigationBar);

function Navigate(e:MouseEvent):void{

[..]
gotoAndStop("nombre_del_label_del_frame");----->Esto es lo que quiero hacer desde una función detectora de evento en la misma Clase!!!

[..]
} //end function

Por emedmaria

73 de clabLevel



 

firefox
Citar            
MensajeEscrito el 11 May 2010 02:38 pm
Sin leer más que el título, cuando nos queremos comunicar la Clase principal con una secundaria tenemos tres opciones. Estoy pensando que lo que haces es NO usar un load para cargar .swf.
1.-Asignar en una variable la Clase de Documento. Se puede hacer en el propio constructor si es que creamos el objeto (MC) con new y addChild, o en otra función

Código ActionScript :

//Nuestra Clase es de la forma
public class UnaClase extends Sprite{
   private var _root:MovieClip;  //<---la declaramos aquí
   public function UnaClase(mc:DisplayObject){
            _root=mc as MovieClip
   }
   //Podríamos poner en una función
   private function irAFrame(){
        _root.gotoAndPlay("Hola")
   }
}
//En nuestra película principal
var unaclase:UnaClase=new UnaClase(this)

2.-Si nuestra clase extiende de DisplayObject (o de alguna Clase que extienda de DisplayObject), podemos usar parent siempre que ya esté añadida al stage

Código ActionScript :

public class DosClase extends Sprite{
   public function UnaClase(){
   }
   //Podríamos poner en una función
   private function irAFrame(){
        MovieClip(parent).gotoAndPlay("Hola")
   }
}
//En nuestra película principal
var dosclase:DosClase=new DosClase()
addChild(dosclase)

Si la tenemos ya en un frame, no tendremos problemas -vale, no pondremos ni lo del new ni lo del addChild, pero si no es así tenemos que tener cuidado: NO podemos usar parent (o stage o root) antes de que se haya añadido al stage. Por eso no lo podemos usar en la "función constructora. Sí lo podríamos hacer si es en una función que controla un Mouse.CLICK, pero, por ejemplo, no podríamos hacerlo en una función que contrale un Event.ENTER_FRAME so pena que añadamos el listener DESPUÉS de que se haya añadido al Stage. Así, una clase se suele parece a algo como

Código ActionScript :

public function TresClase():void 
      {
         if (stage) init();
         else addEventListener(Event.ADDED_TO_STAGE, init);
      }
      
      private function init(e:Event = null):void 
      {
         removeEventListener(Event.ADDED_TO_STAGE, init);
              ...aquí ya podemos lo que se nos ocurra...
                }
      } 

3.-Podemos usar un evento personalizado. Esto es, dispatchamos un evento

Código ActionScript :

//Nuestra Clase es de la forma
public class CuatroClase extends Sprite{
   //Voy a declara una variable STRING como pública
   public var mistring:String;
   public function CuatroClase(mc:DisplayObject){
   }
   //Podríamos poner en una función
   private function irAFrame(){
        mistring="Hola"
        dispatchEvent(new Event("IR_A")); 
   }
}
//En nuestra película principal
var cuatroclase:cuatroClase=new CuatroClase()
addChild(cuatroclase)
//añadimos el listener
cuatroclase.addEventListener("IR_A",onEventoIr); 
public function onEventoIr(e:Event){
     trace(evento.target.mistring)
}

De nuevo, si tenemos ya el objeto en el stage, podemos ahorrarnos lo del new y addChild, pero DEBEMOS añadirle el evento -la función onEvento se puede declarar donde queramos-
4.-Existen otros modos como acceder a datos globales

Por Eliseo2

710 de clabLevel



 

firefox
Citar            
MensajeEscrito el 12 May 2010 08:23 am
En primer lugar, MIL GRACIAS!! Una respuesta muy detallada y aclaratoria :)

-He empleado el segundo método que me propones (DosClase) y me funciona perfectamente para uno de los casos necesarios. Cuando tengo una clase que se encarga de crear unos componenentes (tras la lectura del XML) y en la línea de tiempo hago el new y lo añado a la lista de visualización para mostrarlo en el frame correspondiente.

-Una cuestión acerca del tercer método (evento personalizado). No veo cuando usas el mc:DisplayObject pasado al constructor. Dentro de la clase, ¿cuando llamamos a la función 'irAFrame' para hacer el dispatch del Evento?

-Un tercera pregunta. Si empleo el segundo método para un caso ligeramente diferente me aparece el error:"Error #1034: Error de conversión forzada: no se puede convertir flash.display::Stage@10e74b51 en flash.display.MovieClip.".

Ésto me sucede cuando tengo una clase p.e. BarraDeNavegacion01.as (con su listener y su funcion detectora de evento), otra clase independiente BarraDeNavegacion02.as (con su listener y su funciones detectora de evento que no precisan la linea de tiempo) y por último una última clase que precisa/añade las anteriores p.e. Interface.as.

La última clase la he creado porque se mantendrá constante a lo largo de varios frames, por tanto el contenido que se mostrará por pantalla/frame será la Interface y lo que irá variando será un contenido (que otra clase se encargará de gestionar). El objetivo es que en la línea de tiempo hagamos un addChild de la Interface despreocupandonos de lo q haga puesto q sus respectivas clases ya se responsabilizarán, y un addChild/removeChild del contenido dependiendo del caso....

No sé si me he explicado con claridad, espero que sí. Imagino q el problema igual viene de que los eventos se controlan desde las clases hijas y la clase padre una vez añadida en la linea de tiempo no se entera...¿Como porpago los eventos a niveles superiores?

Gracias de nuevo!

Por emedmaria

73 de clabLevel



 

firefox
Citar            
MensajeEscrito el 12 May 2010 10:13 am
El tercer ejemplo (del evento personalizado) efectivamente tiene un error (Culpa del copy +Paste) es, efectivamente

Código ActionScript :

public function CuatroClase(){ 
} 

Y sí, la idea es tener una función irAFrame que se ejecute, p.e. añadiendo un listener a un botón que tengas. No lo puse en el código :(

Código ActionScript :

//Si tenemos un botón llamado "miboton"
miboton.addEventListener(MouseEvent.CLICK,irAFrame)

Sobre el error de no se puede convertir flash.display::Stage@10e74b51 en flash.display.MovieClip.".

Estaba pensando en que le pasábamos la película principal. Vamos, si tenemos un .fla
o que estábamos escribiendo en un frame

Código ActionScript :

var unaclase:UnaClase=new UnaClase(this) 

o que la Clase de Documento fuera, p.e. Main de la forma

Código ActionScript :

public function Main extends MovieClip{
      public function Main(){
           var unaclase:UnaClase=new UnaClase(this) 
      }
}

Sí, normalmente una "Clase de Documento" extiende siempre de MovieClip, pues de otro modo no podría tener frames. Si, por cualquier causa queremos que extienda de Sprite o de alguna otra cosa, lo más lógico es que nuestra variable "_root" extienda de Sprite o de esa "alguna otra cosa", aunque para estos casos se suele usar DisplayObject o de DisplayObjectContainer

Código ActionScript :

private var _root:DisplayObject;  //<---la declaramos aquí 
public function UnaClase(mc:DisplayObject){ 
      _root=DisplayObject
} 

Vamos, tanto la variable como el argumento de la función deberían ser del mismo tipo.

Respecto al proceso de "propagación de eventos" normalmente lo que se hace es
1.-Tenemos una clase Principal y dos clases LanzaEvento y EjecutaAcción (realmente son tres objetos)
2.-El objeto LanzaEvento dispatcha un evento que recoge la clase principal
3.-Cuando la clase principal escucha el evento ejecuta una función de EjecutaAccion.

Si la comunicación va a ser entre muchas clases arriba y abajo, a veces es mejor usar una "clase intermedia" tal y como muestra ZGuille en este tip

Trato de hacer un pseudo-ejemplo sencillo pero aburrido del modo de comunicar hijo-padre

Código ActionScript :

//La Clase LanzaEvento
public class LanzaEvento extends EventDispatcher{ //(*)
      public class LanzaEvento(){
         //Normalmente añadimos un evento
         boton.addEventListener(MosueEvent.CLICK,lanzar)
      }
      private function lanzar(e:Event){
            dispatchEvent(new Event("EVENTO"));  
      }
}
//La Clase EjecutaAccion
public class EjecutaAccion { 
      public class EjecutaAccion (){
      }
      //Definimos aquí una función pública
      public hazAlgo(argumento:String){
            trace(argumento)
      }
}
//La Clase Principal -o nuestra película-
//creamos dos objetos
var objEvento:LanzaEvento=new LanzaEvento();
var objAccion:EjecutaAccion=new EjecutaAccion();
//Añadimos un evento a "objEvento"
objEvento.addEventListener("EVENTO",ejecutarAlgo)
function ejecutarAlgo(e:Event){
     //En esta función llamamos al "método" de la otra clase
     objAccion.hazAlgo("Hola Mundo")
}


(*)Al menos ha de extender de la clase [url=http://livedocs.adobe.com/flash/9.0_es/ActionScriptLangRefV3/flash/events/EventDispatcher.html], vamos que puede ser EventDispathcer o DisplayObject o Sprite o....


NOTA:Siento estos ejemplos tan aburridos, debería hacer alguno con MCs y círculos que se movieran en espiral o algo así :(

Por Eliseo2

710 de clabLevel



 

firefox
Citar            
MensajeEscrito el 12 May 2010 10:27 am
Olé!

Nada de aburrido. Suficiente para comprender el concepto!
Como es problable que necesite la comunicación entre varias clases voy a echarle un vistazo al tip que me pasas :)

Última cosa (prometido :S) muy de novata en el foro...¿Como introduces los fragmentos de código con formato?

Gracias por tu tiempo

Por emedmaria

73 de clabLevel



 

firefox
Citar            
MensajeEscrito el 12 May 2010 11:30 am

emedmaria escribió:

¿Como introduces los fragmentos de código con formato?

Se ha de introducir el código entre [ a s ] y [/ a s ] (sin los espacios)
NOTA:Si, en lugar de "Publicar una respuesta" le das al botón de "Responder" (que está encima de la caja de texto) te metes en el "modo avanzado" de responder. En el décimo icono (el que aparece como <> que tiene un combo, puedes ver más opciones)

Por Eliseo2

710 de clabLevel



 

firefox

 

Cristalab BabyBlue v4 + V4 © 2011 Cristalab
Powered by ClabEngines v4, HTML5, love and ponies.