Bien Volviendo al TEMA. Gracias eh estado leendo soble esa clase :" EventDispatcher" y es muy interesante ...
CLARO ENCONTRAMOS LA SOLUCION xP ! y bien les Dire Todo lo que me pase CHECANDO:
Primero Busque y Busque y me tope con miles de cosas que no tenian resultado:
la primera solucion que me dieron fue la de poner una variable stactic y ponerla en el constructor y asignale su scope y otra hacer uso de otra clase "Delegate": que es una mejora a lo de la instancia seria algo asi :
Código ActionScript :
import mx.utils.Delegate;//usando la clase Delegate
class conexion{
public static var ins;
public function conexion(param){
ins = this; // asignando el scope para llamar a las funciones. ya no seria necesario porque tenemos la clase "Delegate"
xmlX = new XML();
xmlX.ignoreWhite = true;
xmlL = new LoadVars();
if(indice.length > 0){
for(var i=0;i<indice.length;i++){
xmlL.indice[i]= valor[i];
}
}
//-------------------------------------------
xmlL.sendAndLoad(archivo,xmlX,metodo);
xmlX.onLoad= Delegate.create(this, parse);//usando la clase que porcierto si deriamos parametros a la funcion que queremos llamar seria Delegate.create(this, parse,parametro) xP
}
public function parse(success:Boolean){//funcion que llama la clase Delegate
if(success){
//ins.respuesta = Delegate.create(this, respuestaXML());//no sirvio pero es util fuera de la funcion anidada
this.respuesta = Delegate.create(this, respuestaXML());//No sirvio porque tampoco se le asino a la variable de la clase que es respuesta y es publica. Enconces donde esta el problema porque nada de esto Funciona!!!! :(
}
}//fin parse
public function respuestaXML(){
//------------------------------
//this.dispatchEvent({type:"complete", target: this});
var respuesta2 = new Array();
var code = xmlX.firstChild.childNodes;
for(var forx=0;forx<code.length;forx++){
respuesta2[forx] = new Array();
for(var j=0;j<atributos.length;j++){
respuesta2[forx][j] = code[forx].attributes[atributos[j]];
//trace(respuesta2[forx][j]);
}
}
return respuesta2;
}//fin respuestaXML
public function getResp(){
trace(ins.respuesta);
return ins.respuesta;//NO RETORNA LOS DATOS
}//fin getResp
}
Pues BIEN estuve a punto de rendirme cuando me dijeron que use la clase " EventDispatcher" y bien denuevo a investigar ok y esto es lo que encontre :
----------------------------------------------------------------------------------------------------------------------------------
Una de las partes más importantes y que más confusión y problemas ha generado de AS2 es la comunicación entre clases. Foros y listas de correo están llenos de problemas y dudas sobre "ámbitos", "eventdispatchers" y "delegates".
Como regla general yo diría:
* Si necesitas comunicación dentro de la misma clase, siempre Delegate.
* Si necesitas que más de una clase escuche lo que hace otra, siempre EventDispatcher.
* Si la comunicación es 1:1, depende.
Vamos a ver el funcionamiento de los 2 métodos.
------------------------------------------------------------------------------------------------------------------------
"Delegate"
------------------------------------------------------------------------------------------------------------------------
NOTA: Lo que voy a contar aquí es prácticamente un copy&paste de un tuto que publiqué hace tiempo y que está enlazado al final. Si lo leíste en su día, te puedes saltar lo que sigue sin problemas.
Los foros de Flash están llenos de preguntas que tienen que ver con el "scope" o ámbito dentro de los famosos "callbacks" de objetos como XML, LoadVars, XMLSocket, etc. Flash necesita estas funciones porque las llamadas al servidor en Flash son asíncronas, es decir, el player no detiene la ejecución del código cuando se hace, por ejemplo, una petición de un fichero xml:
Código ActionScript :
class A{
private var oneVar:String="Helloworld";
functionA(){
var myXML:XML = newXML();
myXML.ignoreWhite = true;
myXML.onLoad=function():Void{
trace(oneVar); //undefined ¬¬
}
myXML.load("myXML.xml");
}
}
Esto pasa porque el ámbito "dentro" del onLoad es el propio objeto myXML, NO la clase. Puedes hacer la prueba haciendo trace(this) dentro del onLoad. Una de las primeras soluciones que se utilizó para esto fue crear dentro de la función principal una
variable que hacía referencia a la propia clase. Algo como esto:
Código ActionScript :
class A{
private var oneVar:String="Helloworld";
functionA(){
var owner=this;
var myXML:XML = newXML();
myXML.ignoreWhite = true;
myXML.onLoad = function():Void{
trace(owner.oneVar); //yeah!
}
myXML.load("myXML.xml");
}
}
Y esto funciona. Este comportamiento "peculiar" de Flash (de los ECMAScript, vamos) se llama closure.
ámbito en las llamadas asíncronas. Pues a todo esto llegó la versión 7.2 del Flash IDE y el señor Mike Chambers introdujo la clase Delegate. Utilizando esa clase dejaríamos el código anterior en algo como esto:
Código ActionScript :
importmx.utils.Delegate;
class A{
private var oneVar:String = "Hello world 2";
function A(){
var myXML:XML = new XML();
myXML.ignoreWhite = true;
myXML.onLoad = Delegate.create(this,xmlLoaded);
myXML.load("myXML.xml");
}
private function xmlLoaded(success:Boolean):Void{
trace(oneVar);
}
}
Estamos "delegando" el onLoad en la función xmlLoaded, pero, lo más importante, el ámbito de la función xmlLoaded es la clase original, por lo que "encontramos" la variable sin problemas.
Esto definitivamente NO es lo mismo que hacer: myXML.onLoad = xmlLoaded. Si lo probáis, estaréis con el mismo problema que antes, el ámbito de la función xmlLoaded será el objeto myXML, por lo que el trace volverá a ser undefined.
El mayor problema de la clase de Macromedia (aún era Macromedia) es que NO permite el paso de parámetros a la función delegada, pero pronto llegaron los frikis para solucionarlo haciendo sus propias clases para delegar. La que yo utilizo es una copia con alguna modificación de una que encontré en la lista de MTASC. Con estas nuevas clases se pueden pasar parámetros de la siguiente forma:
Código ActionScript :
myXML.onLoad=Delegate.create(this,xmlLoaded,"val1",val2);
OJO, nuestros parámetros llegarán después de los "oficiales", en este caso el típico success que llega a los onLoad del objeto XML.
------------------------------------------------------------------------------------------------------------------------------------------------
"EvenDispatcher"
------------------------------------------------------------------------------------------------------------------------------------------------
La misión básica de EvenDispatcher es permitir que varios objetos estén "escuchando" los eventos que lanza otro. EvenDispatcher siempre trata de comunicación entre clases, ya sea 1:1 (un emisor y un receptor) o 1:n (un emisor y varios receptores).
Técnicamente es una implementación del patrón Observer (ver enlaces al final) y fue introducida en su día por Macromedia. Pero como casi siempre apareció una versión libre, GDispatcher, en esta ocasión a cargo de Grant Skinner (gskinner.com).
Las clases que emiten eventos con EvenDispatcher son completamente independientes de quien esté escuchando, nunca saben si los escuchan 1 o 10, ellos sólo se limitan a emitir. Son como una radio o televisión con audiencia.
Sólo el objeto emisor necesita importar GDispatcher. Algo como lo siguiente:
Código ActionScript :
importcom.gskinner.GDispatcher;
class broadcaster{
public var addEventListener:Function;
public var removeEventListener:Function;
private var dispatchEvent:Function;
public function broadcaster(){
GDispatcher.initialize(this);
send();
}
private function send():Void{
var ev:Object = new Object();
ev.type = "myEvent";
ev.variable = "wadus";
dispatchEvent(ev);
}
}
import broadcaster;
class receiver{
public function receiver(){
varbr:broadcaster = newbroadcaster();
br.addEventListener("myEvent",this,"callback");
}
private function callback(ev:Object):Void{
trace(ev.type+""+
ev.variable);
}
}
Lo primero que llama la atención es que hayamos definido en la clase emisora unas variables del tipo Function. Si alguien se molesta en abrir GDispatcher puede ver que lo que hace en el método initialize es crear en tiempo de ejecución funciones a la clase que se le pasa como parámetro. Así que tenemos que definir esas mismas funciones como propiedades de nuestra clase para que el compilador no se queje de que el método al que el receptor trata de acceder (addEventListener) no existe.
La clase receptora es bastante simple. Simplemente importa a la emisora y se añade como listener para un evento concreto. Para hacerlo utiliza el método addEventListener pasando como parámetros el evento que quiere escuchar, el objeto que está escuchando (la propia clase (this) en este caso, pero se puede hacer que escuche otra) y la función que va a recibir la llamada. OJO que la función está pasada como cadena.
La implementación que hemos visto es perfectamente válida y funcional pero se puede mejorar. El primer problema es que el literal del nombre del evento ("myEvent") lo estamos repitiendo dos veces, una en el emisor y otra en el receptor. Malo. Otra es que el tipo del parámetro que llega a la función receptora es del tipo genérico Object, lo que no nos permite ninguna validación de tipos al compilar. Malo también. Bueno, pues las 2 cosas las vamos a solucionar en la misma jugada. Vamos a crear un objeto específico para el evento y será ese objeto "conocido" el que se envíe.
Código ActionScript :
class myEvent{
public static var EVENT_LITERAL:String = "eventOne";
public var type:String = "";
public var variable:Number;
public function myEvent(_variable:Number){
type = EVENT_LITERAL;
variable = _variable;
}
}
Código ActionScript :
importcom.gskinner.GDispatcher;
import myEvent;
class broadcaster{
public var addEventListener:Function;
public var removeEventListener:Function;
private var dispatchEvent:Function;
public function broadcaster(){
GDispatcher.initialize(this);
send();
}
private function send():Void{
var ev:myEvent = new myEvent(5);
dispatchEvent(ev);
}
}
Código ActionScript :
import broadcaster;
import myEvent;
class receiver{
public function receiver(){
var br:broadcaster = new broadcaster();
br.addEventListener(preventivamente_LITERAL,this, "callback");
}
private function callback(ev:myEvent):Void{
trace(ev.type + " "
+ ev.variable);
}
}
Mucho mejor. El literal con el nombre del evento sólo se define una vez en la clase myEvent. Se define como variable estática para que la clase receptora pueda utilizarlo sin tener que crear una instancia. La propiedad type se define para ser compatibles con EventDispatcher y GDispatcher.
Además con la nueva implementación el tipo del evento que llega al receptor es myEvent y no Object, por lo que tendremos validación de tipos al compilar.
Si sustituyes myEvent, por videoStarted, applicationReady, menuButtonPressed y similares, es cuando se empieza a ver la utilidad de EvenDispatcher (vamos, de un patrón Observer).
-----------------------------------------------------------------------------------------------
EvenDispatcher ¿vs? Delegate
-----------------------------------------------------------------------------------------------
Una vez vistos EventDispatcher y Delegate, ¿hay situaciones en las que se pueda elegir entre usar una opción o la otra? Ya hemos visto que la comunicación dentro de la misma clase siempre es con Delegate, así la decisión viene cuando hay que comunicar 2 clases. Vamos a ver cómo.
Código ActionScript :
importBroadcaster;
importtv.zarate.utils.Delegate;
class Receiver{
public function Receiver(){
var buttonCallback:Function = Delegate.create(this, buttonPressed);
var broadcaster:Broadcaster = newBroadcaster(buttonCallback);
}
private function buttonPressed():Void{
//este método se ejecuta cuando se presione el botón
//en la clase emisora
}
}
Código ActionScript :
class Broadcaster{
public function Broadcaster(buttonPressedCallback:Function){
var button:MovieClip = base_mc.createEmptyMovieClip("button", 100);
button.onPress = buttonPressedCallback;
}
}
Atención a la jugada. La clase receptora crea una función delegada y la pasa como parámetro a la emisora que simplemente se lo asigna al evento onPress de su botón. Así que cuando el botón es presionado, la clase emisora recibe sin problemas el evento.
Ahora, ¿qué hacemos si hay que pasar parámetros en la llamada? Esto es algo que NO podríamos hacer:
Código ActionScript :
button.onPress = buttonPressedCallback("parametro");
Ya que al añadir "()" estaríamos ejecutando la función. Si necesitamos pasar parámetros con este método, habría que pasar por una función intermedia. Repito sólo la clase emisora:
Código ActionScript :
importtv.zarate.utils.Delegate;
class Broadcaster{
public function Broadcaster(externalCallback:Function){
var button:MovieClip = base_mc.createEmptyMovieClip("button", 100);
button.onPress = Delegate.create(this, butPressed, externalCallback);
}
private function butPressed(externalCallback:Function):Void{
externalCallback("parametro");
}
}
Al utilizar la clase emisora internamente una función para recibir el evento onPress del botón, ya puede pasar los parámetros que quiera al callback externo.
LUEGO DE ESO ENCONTRE UNA CLASE MEJORADA DE "EvenDispatcher" QUE ESTA EN ESTA MISMA PAGINA AQUI EL LINK:
[url=http://www.cristalab.com/tips/clase-que-mejora-el-eventdispatcher-de-actionscript-2-c52269l/][/url]
A TODO ESTO AHORA MI CODIGO SE VE ASI CON LA CLASE DEL ENLACE:
Código ActionScript :
/*********CLASS CONEXION XML CREADO POR XIM*******/
//import mx.events.EventDispatcher;
import com.npi.events.EventDispatcher;
import mx.utils.Delegate;
class conexion{
public var msn;
public var respuesta;
public var xmlX:XML;
public var xmlL;
//---------------------------
public var archivo;
public var indice;
public var valor;
public var metodo;
public var atributos;
//---------------------------
public static var ins;//
//---------------------------
public function conexion(archivo2,indice2,valor2,metodo2,atributos2){
EventDispatcher.initialize(this);
ins = this;msn = new Array();respuesta = new Array();indice = new Array();valor = new Array();atributos = new Array();
mensaje();
///----ASIGNANDO---
archivo = archivo2;indice = indice2;valor = valor2;atributos = atributos2;
if(metodo2 = 1){metodo = "post";}else{metodo = "get";}
//-------------------------------------------
xmlX = new XML();
xmlX.ignoreWhite = true;
xmlL = new LoadVars();
if(indice.length > 0){
for(var i=0;i<indice.length;i++){
xmlL.indice[i]= valor[i];
}
}
//-------------------------------------------
xmlL.sendAndLoad(archivo,xmlX,metodo);
xmlX.onLoad= Delegate.create(this, parse);
//newLoad.load("mensajes.php");
//-------------------------------------------
}//fin constructor
public function mensaje(){
msn[0] = "Error al conectar";
msn[1] = "Error al tratar de hacer la consulta";
msn[2] = "Problemas al tratar de cargar el XML";
}//fin mensaje
public function parse(success:Boolean){
if(success){
Delegate.create(this, respuestaXML());
}else{
trace(msn[2]);
}
}//fin parse
public function respuestaXML(){
//------------------------------
//this.dispatchEvent({type:"complete", target: this}); //NO FUNCIONA EL THIS
var respuesta2 = new Array();
var code = xmlX.firstChild.childNodes;
for(var forx=0;forx<code.length;forx++){
respuesta2[forx] = new Array();
for(var j=0;j<atributos.length;j++){
respuesta2[forx][j] = code[forx].attributes[atributos[j]];
//trace(respuesta2[forx][j]);
}
}
ins.respuesta = respuesta2;//ASIGNADO
ins.dispatchEvent({type:"complete", target:this}, true);//TUVE QUE COLOCAR LA INSTANCIA "INS" ES UTIL
}//fin respuestaXML
public function getResp(){
trace(ins.respuesta);//COMPRUEBO
return ins.respuesta;//AHORA SI RETORNA LOS DATOS
}//fin getResp
}//fin class
Y LO LLAMO DE ESTA FORMA :
Código ActionScript :
import conexion;
var xxI = new Array();
var xxV = new Array();
var aaT = new Array();
var resp = new Array();
aaT[0]= "nombre";
aaT[1]= "descripcion";
conec = new conexion("descripcion2.xml",xxI,xxV,0,aaT);//INSTANCIO PARA QUE ESCUCHE EL addEventListener
conec.addEventListener("complete", getDatos,true) //ESCUCHA SE SE COMPLETO Y LLAMA A LA FUNCION getDatos
function getDatos(){
conec.getResp(); //AHORA SI RETORNA
}
BIEN ACABE ESO SERIA TODO SI AYUDE EN ALGO ESPERO QUE SI
SALUDOS DESDE LIMA - PERU GRACIAS!!!