LLops Blog

Blog de programación creativa mantenido por llops. Experimentos y artículos entorno a la plataforma flash y as3.

Accediendo al stage antes de tiempo

En AS3 es una práctica habitual asociar eventos al stage para cogerlos globalmente. El caso más utilizado probablemente se dé con los del tipo MouseEvent. Por ejemplo, si tenemos varios objetos en pantalla, en vez de definir un evento click para cada uno de ellos, cogemos sólo el click en el escenario (global) y vemos sobre quién se está interactuando:

  1. this.stage.addEventListener(MouseEvent.CLICK, click);
  2. private function click(e:MouseEvent):void
  3. {
  4.     trace("Click en", e.target);
  5. }

Pero a veces, cuando intentamos añadir un evento al stage obtenemos el siguiente error:

TypeError: Error #1009: No se puede acceder a una propiedad o a un método de una referencia a un objeto nulo.

Vamos a reproducir el error.

Tenemos dos clases: Main, asociada al documentClass, y Circulo, que se encarga de dibujar un pequeño circulo y capta un evento click.

Clase Main

  1. package {
  2.     import flash.display.Sprite;
  3.     import Circulo;
  4.    
  5.     public class Main extends Sprite {
  6.        
  7.         function Main() {
  8.             var c:Circulo = new Circulo();
  9.             addChild(c);
  10.         }
  11.     }
  12. }

 

Clase Circulo

  1. package {
  2.     import flash.display.Sprite;
  3.     import flash.events.*;
  4.  
  5.     public class Circulo extends Sprite {
  6.        
  7.         function Circulo() {
  8.            
  9.             // Dibujar Circulo
  10.             this.graphics.beginFill(0xFF0000);
  11.             this.graphics.drawCircle(50, 50, 10);
  12.             this.graphics.endFill();
  13.            
  14.             // Definir el evento click
  15.             this.stage.addEventListener(MouseEvent.CLICK, clic);
  16.         }
  17.        
  18.         private function clic(e:MouseEvent):void
  19.         {
  20.             if (e.target == this) trace("Click sobre circulo")
  21.             else trace("No es circulo");
  22.         }
  23.     }
  24. }

Si compilamos obtenemos:

TypeError: Error #1009: No se puede acceder a una propiedad o a un método de una referencia a un objeto nulo.
    at Circulo()
    at Main()

 

¿Por qué obtenemos este error?

Stage es el contenedor base de todos los objetos visuales y se encuentra en lo más alto de la displayList.  Este contenedor no se puede acceder directamente, sino que se tiene que hacer mediante la propiedad stage, que se encuentra en cualquier objeto que extiende de DisplayObject.

Nuestro objeto Circulo extiende de Sprite y por tanto es un DisplayObject que soporta la propiedad stage, pero cuando intentamos acceder a dicha propiedad el objeto no se encuentra todavía en la displayList y por tanto la referencia es nula.

 

Solución

Para solucionar esto existen dos eventos muy útiles definidos en DisplayObjet: added y addedToStage. El primero se dispacha cuando un objeto se añade a la displayList y el segundo cuando se añade al escenario.

Así pues, podemos suscribirnos a estos eventos antes de acceder al stage y así garantizar que está disponible y que no genera error.

Finalmente nuestra clase Circulo quedaría:

  1. package {
  2.     import flash.display.Sprite;
  3.     import flash.events.*;
  4.  
  5.     public class Circulo extends Sprite {
  6.        
  7.         function Circulo() {
  8.            
  9.             // Dibujar Circulo
  10.             this.graphics.beginFill(0xFF0000);
  11.             this.graphics.drawCircle(50, 50, 10);
  12.             this.graphics.endFill();
  13.            
  14.             // Escuchar el evento ADDED
  15.             this.addEventListener(Event.ADDED, init);
  16.             // o en este caso también ADDED_TO_STAGE
  17.             //this.addEventListener(Event.ADDED_TO_STAGE, init);
  18.         }
  19.        
  20.         private function init(e:Event):void
  21.         {
  22.             // Definir el evento click
  23.             this.stage.addEventListener(MouseEvent.CLICK, clic);
  24.         }
  25.        
  26.         private function clic(e:MouseEvent):void
  27.         {
  28.             if (e.target == this) trace("Click sobre circulo")
  29.             else trace("No es circulo");
  30.         }
  31.     }
  32. }

>> Descargar ejemplo

Post publicado el 18 de February de 2008 a las 16:07 por llops

Categorias: Tips

Etiquetas: , , , ,

¿Quieres seguir los comentarios de esta entrada? RSS 2.0

Permalink, Trackback

8 comentarios

  1. Hummm, i tried create another instance of the circle object and i add it to displaylist. After this the event workn't properly. The output show me both messages. Because?

  2. #2   LLops

    Ummm it's strange, for me this code works properly:

    1. function Main() {
    2.     var c:Circulo = new Circulo();
    3.     addChild(c);
    4.            
    5.     var d:Circulo = new Circulo();
    6.     addChild(d);
    7.     d.x += 30;
    8. }

    Are you trying with the correct code?

  3. #3   EgoSum

    Gracias por el tip, me ha solucionado ese runtime error que me salia cuando intentaba lanzar un swf hecho en flash que cargaba a partir de un SWFLoader en flex.

  4. #4   Juan

    Hola. Como les va?

    Tengo la siguiente clase en un archivo .AS

    package {
    import mx.core.WindowedApplication;
    import flash.events.*;

    public class HW extends WindowedApplication
    {
    private var appWA:WindowedApplication;

    public function HW(){
    super();
    }

    }
    }

    Y cuando la quiero usar de la siguiente manera con el siguiente codigo de un archivo .MXML

    public function ingresar():void {

    var newWindow:HW = new HW();
    newWindow.initialize();
    newWindow.setVisible(true);

    }

    Obtengo el siguiente error:

    TypeError: Error #1009: No se puede acceder a una propiedad o a un método de una referencia a un objeto nulo.
    at mx.core::Application/initialize()
    at HW/initialize()
    at ingresar()

    Para resolver el problema intente agregar el siguiente codigo:

    override public function initialize():void{
    super.initialize();
    }

    public function HW(){
    this.addEventListener(Event.ADDED_TO_STAGE, initialize);
    super();
    }

    Pero no he tenido éxito. Agradecería me puedan indicar como lo soluciono.

    Gracias.

  5. #5   gonzalo geraldo

    Muchas gracias Llops, este tema no lo podia resolver y no lo he visto documentado. Tengo el Essential Actionscript 3.0 y tampoco aparece (espero no pecar de no entender lo que leo). En el Help de Actionscript tampoco lo habia visto explicado asi.

    Me ha servido mucho

    saludos

  6. #6   David E Sanchez

    Hola!
    Quisiera Agradecer la ayuda!!!! pues me proporciono informacion ademas de que encontre solucion al mismisimo problema que se presenta aqui; lo unico que puedo decir es gracias LLop!!! estare publicando mis trabajos para que me ayuden a mejorar pues soy Principiente en FLASH y empece con CS3
    Salu2 a la comunidad!!!!

  7. #7   matias

    Ok, pero esto solo funciona cuando se utilizan classes, pero si el codigo esta en un keyframe dentro de un movieclip no funciona...

    a mi me continua tirando ese error y no tengo forma de solucionarlo...

  8. #8   LLops

    Matias, si el código está en un keyframe, no necesitas utilizar este evento, ya que un objeto en linea de tiempo lleva implícito encontrarse en la displayList.

    Si quieres, detállame el caso concreto (puedes hacerlo a través de contacto) y le echo un vistazo a ver si te puedo ayudar.

¡Deja un comentario!

Recuerda:

  • Los lectores de este blog son gente maja y sensible, así que pórtate bien y se respetuoso con tus comentarios.
  • Puedes usar las siguientes etiquetas html: <b>, <em> y <a>.
  • Si deseas añadir código utiliza este formato: [as3]code[/as3].

LLops en Twitter

Top